diff --git a/.configurations/configuration.dsc.yaml b/.configurations/configuration.dsc.yaml deleted file mode 100644 index 77f910e0..00000000 --- a/.configurations/configuration.dsc.yaml +++ /dev/null @@ -1,37 +0,0 @@ -# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2 -properties: - resources: - - resource: Microsoft.WinGet.DSC/WinGetPackage - id: vsPackage - directives: - description: Install Visual Studio 2022 Community - module: Microsoft.WinGet.DSC - allowPrerelease: true - settings: - id: Microsoft.VisualStudio.2022.Community - source: winget - - resource: Microsoft.VisualStudio.DSC/VSComponents - id: vsConfig - dependsOn: - - vsPackage - directives: - description: Install required VS workloads - module: Microsoft.VisualStudio.DSC - allowPrerelease: true - settings: - productId: Microsoft.VisualStudio.Product.Community - channelId: VisualStudio.17.Release - includeRecommended: true - Components: - - Microsoft.VisualStudio.Workload.NativeGame - - resource: Microsoft.WinGet.DSC/WinGetPackage - dependsOn: - - vsConfig - directives: - description: Install Microsoft GDK - module: Microsoft.WinGet.DSC - allowPrerelease: true - settings: - id: Microsoft.GDK.2303 - source: winget - configurationVersion: 0.2.0 \ No newline at end of file diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..f15501a0 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*.{cpp,h,inl,fx,fxh,hlsl,hlsli}] +indent_size = 4 +indent_style = space +trim_trailing_whitespace = true +insert_final_newline = true +end_of_line = crlf +charset = latin1 diff --git a/.gitattributes b/.gitattributes index 0bda1ce6..af734a06 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,7 +1,6 @@ -# Auto detect text files and perform LF normalization * text=auto - # Explicitly declare code/VS files as CRLF +*.cs eol=crlf *.cpp eol=crlf *.cmd eol=crlf *.h eol=crlf @@ -11,17 +10,82 @@ *.fxh eol=crlf *.inc eol=crlf *.inl eol=crlf +*.csproj eol=crlf *.vcxproj eol=crlf *.filters eol=crlf *.sln eol=crlf - -# Explicitly declare resource files as binary -*.docx binary -*.pdb binary -*.dds binary -*.sdkmesh binary -*.spritefont binary -*.wav binary -*.xwb binary -*.jpg binary -*.png binary +# Binary +*.bin filter=lfs diff=lfs merge=lfs -text +*.BIN filter=lfs diff=lfs merge=lfs -text +*.exe filter=lfs diff=lfs merge=lfs -text +*.dll filter=lfs diff=lfs merge=lfs -text +*.pdb filter=lfs diff=lfs merge=lfs -text +*.pdn filter=lfs diff=lfs merge=lfs -text +*.vsix filter=lfs diff=lfs merge=lfs -text +*.*_ filter=lfs diff=lfs merge=lfs -text +# Assets +*.xbtc filter=lfs diff=lfs merge=lfs -text +*.fbx filter=lfs diff=lfs merge=lfs -text +*.glb filter=lfs diff=lfs merge=lfs -text +*.gltf filter=lfs diff=lfs merge=lfs -text +*.mb filter=lfs diff=lfs merge=lfs -text +*.rasterfont filter=lfs diff=lfs merge=lfs -text +*.sdkmesh filter=lfs diff=lfs merge=lfs -text +*.sdkmesh_anim filter=lfs diff=lfs merge=lfs -text +*.spritefont filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text +*.otf filter=lfs diff=lfs merge=lfs -text +# Unity Assets +*.unitypackage filter=lfs diff=lfs merge=lfs -text +# Images +*.bmp filter=lfs diff=lfs merge=lfs -text +*.BMP filter=lfs diff=lfs merge=lfs -text +*.dds filter=lfs diff=lfs merge=lfs -text +*.DDS filter=lfs diff=lfs merge=lfs -text +*.gif filter=lfs diff=lfs merge=lfs -text +*.hdr filter=lfs diff=lfs merge=lfs -text +*.jpg filter=lfs diff=lfs merge=lfs -text +*.JPG filter=lfs diff=lfs merge=lfs -text +*.jpeg filter=lfs diff=lfs merge=lfs -text +*.pfm filter=lfs diff=lfs merge=lfs -text +*.png filter=lfs diff=lfs merge=lfs -text +*.PNG filter=lfs diff=lfs merge=lfs -text +*.svg filter=lfs diff=lfs merge=lfs -text +*.tga filter=lfs diff=lfs merge=lfs -text +*.TGA filter=lfs diff=lfs merge=lfs -text +*.tif filter=lfs diff=lfs merge=lfs -text +*.TIF filter=lfs diff=lfs merge=lfs -text +*.tiff filter=lfs diff=lfs merge=lfs -text +*.wdp filter=lfs diff=lfs merge=lfs -text +# Video/Audio +*.mp4 filter=lfs diff=lfs merge=lfs -text +*.wav filter=lfs diff=lfs merge=lfs -text +*.xwb filter=lfs diff=lfs merge=lfs -text +*.xwma filter=lfs diff=lfs merge=lfs -text +*.ogg filter=lfs diff=lfs merge=lfs -text +# Misc +*.docx filter=lfs diff=lfs merge=lfs -text +*.pptx filter=lfs diff=lfs merge=lfs -text +*.xvd filter=lfs diff=lfs merge=lfs -text +*.zip filter=lfs diff=lfs merge=lfs -text +*.snk filter=lfs diff=lfs merge=lfs -text +*.AlignmentChunk filter=lfs diff=lfs merge=lfs -text +# Exceptions needed for build +*.lib -text +Infrastructure/Policheck/*.mdb filter= diff= merge= -text +Infrastructure/Automation/dependencies/XTF/*.dll filter= diff= merge= -text +Infrastructure/Tools/InstallerWait.exe filter= diff= merge= -text +Infrastructure/Tools/nuget.exe filter= diff= merge= -text +Samples/Live/GameService/Game_Service_Configuration_and_Documentation.docx filter=lfs diff=lfs merge=lfs -text +Samples/Live/GameService/Readme.docx filter=lfs diff=lfs merge=lfs -text +Samples/Live/MicrosoftStoreService/MicrosoftStoreService/Microsoft_Store_Service_Configuration_and_Documentation.docx filter=lfs diff=lfs merge=lfs -text +Samples/Live/MicrosoftStoreService/MicrosoftStoreService/Readme.docx filter=lfs diff=lfs merge=lfs -text +Samples/_Deprecated/GameService_LegacyXTokens/GameService_ReadMe_ja-jp.docx filter=lfs diff=lfs merge=lfs -text +Samples/_Deprecated/GameService_LegacyXTokens/GameService_ReadMe_ko-kr.docx filter=lfs diff=lfs merge=lfs -text +Samples/_Deprecated/GameService_LegacyXTokens/GameService_ReadMe_zh-cn.docx filter=lfs diff=lfs merge=lfs -text +Samples/_Deprecated/GameService_LegacyXTokens/LocalizedDocumentation/Game_Service_Readme_ja-jp.docx filter=lfs diff=lfs merge=lfs -text +Samples/_Deprecated/GameService_LegacyXTokens/LocalizedDocumentation/Game_Service_Readme_ko-kr.docx filter=lfs diff=lfs merge=lfs -text +Samples/_Deprecated/GameService_LegacyXTokens/LocalizedDocumentation/Game_Service_Readme_zh-cn.docx filter=lfs diff=lfs merge=lfs -text +Kits/AMDTK/fidelityfx/tools/binary_store/FidelityFX_SC.exe filter= diff= merge= -text +Kits/AMDTK/fidelityfx/tools/binary_store/glslangValidator.exe filter= diff= merge= -text +Wiki/Media/*.png filter= diff= merge= -text diff --git a/.github/workflows/pr-summary-eval-reusable.yml b/.github/workflows/pr-summary-eval-reusable.yml index 0049162d..21b4285d 100644 --- a/.github/workflows/pr-summary-eval-reusable.yml +++ b/.github/workflows/pr-summary-eval-reusable.yml @@ -24,14 +24,12 @@ jobs: - name: Fetch current PR body uses: actions/github-script@v7 - env: - PR_NUMBER: ${{ inputs.pr-number }} with: script: | const { data: pr } = await github.rest.pulls.get({ owner: context.repo.owner, repo: context.repo.repo, - pull_number: parseInt(process.env.PR_NUMBER, 10), + pull_number: ${{ inputs.pr-number }}, }); const fs = require('fs'); fs.writeFileSync('/tmp/pr-body.txt', pr.body || ''); @@ -45,12 +43,9 @@ jobs: - name: Post evaluation comment uses: actions/github-script@v7 - env: - PR_NUMBER: ${{ inputs.pr-number }} with: script: | const fs = require('fs'); - const prNumber = parseInt(process.env.PR_NUMBER, 10); let result; try { result = JSON.parse(fs.readFileSync('eval-result.json', 'utf8')); @@ -80,7 +75,7 @@ jobs: const comments = await github.rest.issues.listComments({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: prNumber, + issue_number: ${{ inputs.pr-number }}, }); const marker = '## ✅ PR Summary Format Eval'; @@ -100,7 +95,7 @@ jobs: await github.rest.issues.createComment({ owner: context.repo.owner, repo: context.repo.repo, - issue_number: prNumber, + issue_number: ${{ inputs.pr-number }}, body, }); } diff --git a/.github/workflows/pr-summary-generate.yml b/.github/workflows/pr-summary-generate.yml index 2a2584fe..9291a243 100644 --- a/.github/workflows/pr-summary-generate.yml +++ b/.github/workflows/pr-summary-generate.yml @@ -3,8 +3,6 @@ name: Generate PR Summary on: pull_request: types: [opened] - issue_comment: - types: [created] permissions: contents: read @@ -13,53 +11,21 @@ permissions: jobs: generate-summary: - # Run when: - # 1. A PR is opened without a description, OR - # 2. Someone comments "/generate-summary" on a PR - if: | - (github.event_name == 'pull_request' && (github.event.pull_request.body == '' || github.event.pull_request.body == null)) || - (github.event_name == 'issue_comment' && github.event.issue.pull_request && contains(github.event.comment.body, '/generate-summary')) + # Only run for bot-created PRs + if: endsWith(github.event.pull_request.user.login, '[bot]') runs-on: ubuntu-latest - outputs: - pr-number: ${{ steps.pr-number.outputs.number }} steps: - - name: Determine PR number - id: pr-number - env: - EVENT_NAME: ${{ github.event_name }} - PR_NUMBER: ${{ github.event.pull_request.number }} - ISSUE_NUMBER: ${{ github.event.issue.number }} - run: | - if [ "$EVENT_NAME" = "pull_request" ]; then - echo "number=$PR_NUMBER" >> "$GITHUB_OUTPUT" - else - echo "number=$ISSUE_NUMBER" >> "$GITHUB_OUTPUT" - fi - - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - - name: React to comment - if: github.event_name == 'issue_comment' - uses: actions/github-script@v7 - with: - script: | - await github.rest.reactions.createForIssueComment({ - owner: context.repo.owner, - repo: context.repo.repo, - comment_id: context.payload.comment.id, - content: 'rocket', - }); - - name: Get PR diff summary env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - PR_NUMBER: ${{ steps.pr-number.outputs.number }} run: | - gh pr diff "$PR_NUMBER" --stat > /tmp/diff-stat.txt 2>/dev/null || echo "Unable to retrieve diff" > /tmp/diff-stat.txt - gh pr diff "$PR_NUMBER" --name-only > /tmp/changed-files.txt 2>/dev/null || echo "" > /tmp/changed-files.txt + gh pr diff ${{ github.event.pull_request.number }} --stat > /tmp/diff-stat.txt 2>/dev/null || echo "Unable to retrieve diff" > /tmp/diff-stat.txt + gh pr diff ${{ github.event.pull_request.number }} --name-only > /tmp/changed-files.txt 2>/dev/null || echo "" > /tmp/changed-files.txt - name: Read format instructions run: | @@ -157,19 +123,16 @@ jobs: - name: Update PR title and description if: steps.generate.outputs.summary != '' uses: actions/github-script@v7 - env: - PR_TITLE: ${{ steps.generate.outputs.title }} - PR_NUMBER: ${{ steps.pr-number.outputs.number }} with: script: | const fs = require('fs'); const summary = fs.readFileSync('/tmp/pr-summary.md', 'utf8'); - const title = process.env.PR_TITLE || ''; + const title = '${{ steps.generate.outputs.title }}'; const update = { owner: context.repo.owner, repo: context.repo.repo, - pull_number: parseInt(process.env.PR_NUMBER, 10), + pull_number: context.payload.pull_request.number, body: summary, }; @@ -185,4 +148,4 @@ jobs: needs: generate-summary uses: ./.github/workflows/pr-summary-eval-reusable.yml with: - pr-number: ${{ fromJSON(needs.generate-summary.outputs.pr-number) }} + pr-number: ${{ github.event.pull_request.number }} diff --git a/.gitignore b/.gitignore index 51cb59f4..01e13a2d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,40 +1,471 @@ -*.psess -*.aps -*.vsp -*.log -*.err -*.wrn +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Original from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore + +# User-specific files +*.rsuser *.suo -*.sdf *.user -*.i +*.userosscache +*.sln.docstates + +# shortcuts +*.lnk + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ +**/xbox/build/ +Gaming.Desktop.x64/ +Gaming.Xbox.x64/ +Gaming.Xbox.XboxOne.x64/ +Gaming.Xbox.Scarlett.x64/ +[Pp]rofile/ + +# ignore Unity samples for now? +#[Uu]nitySamples/ + +# ignore Unity GDK version mapper working files +Scripts/Unity for Game Core Downloads - Microsoft Game Core on Xbox - Unity Discussions.html +Scripts/Unity for Game Core Downloads - Microsoft Game Core on Xbox - Unity Discussions_files/ +Scripts/page_text.txt + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log *.vspscc -*.opensdf +*.vssscc +.builds +*.pidb +*.svclog +*.scc +*.wrn +*.err +*.cso + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb *.opendb -*.ipch -*.cache -*.tlog -*.lastbuildstate -*.ilk +*.opensdf +*.sdf +*.cachefile *.VC.db -.vs -"Generated Files" -Bin -ipch -Debug -Profile -Release -x64 -Gaming.Desktop.x64 -Gaming.Xbox.XboxOne.x64 -Gaming.Xbox.Scarlett.x64 -Kits/DirectXTK12/Src/Shaders/Compiled/ -Kits/DirectXTex/Shaders/Compiled/ -/wiki -AppPackages -packages -!Kits/OpenSource/**/ -.vscode -.editorconfig -Directory.Build.props -Directory.Build.targets \ No newline at end of file +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +#*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross 4form F# VS Code tools) working folder +.ionide/ + +# vcpkg artifacts +vcpkg_installed/ + +# CMake out folder +out/ +CMakeUserPresets.json + +# ignore User folder for samples +User/* + +# ignore location for AtgSample.exe +Infrastructure/Tools/AtgSample.exe + + +# Ignore kit binaries & shaders and tests +Kits/DirectXMesh/Bin +Kits/DirectXTex/Bin +Kits/DirectXTK12/Bin +Kits/DirectXMesh/build +Kits/DirectXTex/build +Kits/DirectXTK12/build +Kits/DirectXTK12/Src/Shaders/Compiled/*.inc +Kits/DirectXTK12/Src/Shaders/Compiled/*.pdb +Kits/DirectXTex/Shaders/Compiled/*.inc +Kits/DirectXTex/Shaders/Compiled/*.pdb +Kits/DirectXMesh/Tests +Kits/DirectXTex/Tests +Kits/DirectXTK12/Tests +Kits/DirectXMesh/wiki +Kits/DirectXTex/wiki +Kits/DirectXTK12/wiki + +# Build related files we need to allow +!Infrastructure/Tools/*.exe + +# Ignore VSIX payload modifications +Infrastructure/Templates/**/[Pp]ayload/*.vstemplate +!Infrastructure/Templates/**/*_branding_*/[Pp]ayload/*.vstemplate +!Infrastructure/Templates/**/UITKMediaItems/[Pp]ayload/*.vstemplate +Infrastructure/Templates/**/[Pp]ayload/Assets/ +Infrastructure/Templates/**/[Pp]ayload/Kits/ + +# Ignore ATG build/dist folders +SDKDist/ +LocalDist/ + +# Ignore some LIVE package script stuff +Samples/Live/Fundamentals_Desktop/Package/ + +# Ignore HlslCompile sample tool +Samples/Graphics/HlslCompile/*.exe + +# Ignore some NR stufff +Samples/Live/NetRumble/GameLayout/ +Samples/Live/NetRumble_Desktop/GameLayout/ + +# Ignore PSO stuff +Samples/Graphics/AdvancedPSO/PSOGen/*.dll + +# SFS sample from SiGMA uses unusual extension for shaders +!Samples/Graphics/SamplerFeedbackStreaming/Common/*.pfx +!Samples/Graphics/SamplerFeedbackStreaming/Streaming/*.pfx + +# LLVM required files +!LLVMGXDK-Changes/** + +# Include all OpenSource files +!Kits/OpenSource/** + +# Ignore some alternative shader names +*.csh + +# Ignore .orig files that happen from doing merges +*.orig +/Samples/Live/GameService/GameService/Properties/launchSettings.json +/Samples/Live/GameService/Microsoft.XboxSecureTokens/Properties/launchSettings.json + +# Ignore the Properties folder of the GameService samples (these have usually deployment info specific to when I am testing and should not be checked in) +Samples/Live/GameService/GameService/Properties/ +/Samples/Graphics/VRSandSparseLighting.zip + +# Ignore VSCode folder +.vscode/ +/Samples/Live/InGameStore/output +/Samples/Live/InGameStore/chunks.xml +/Samples/Live/InGameStore/makescarlettpkg.cmd + +# Ignore output of AdvancedPSO +psoset/ + +# Ignore some AMDTK binary store copies of Microsoft files +Kits/AMDTK/fidelityfx/tools/binary_store/[Dd]3[Dd]*.* +Kits/AMDTK/fidelityfx/tools/binary_store/[Dd][Xx]*.* + +# Auto-generated GDK version cache (created by Scripts/Resolve-GdkVersion.ps1) +Infrastructure/Build/GdkVersions.g.props +Infrastructure/Build/GdkVersions.Specs.g.props diff --git a/Kits/AMDTK/GLTF/GLTFResources.cpp b/Kits/AMDTK/GLTF/GltfResources.cpp similarity index 100% rename from Kits/AMDTK/GLTF/GLTFResources.cpp rename to Kits/AMDTK/GLTF/GltfResources.cpp diff --git a/Kits/AMDTK/GLTF/GLTFResources.h b/Kits/AMDTK/GLTF/GltfResources.h similarity index 100% rename from Kits/AMDTK/GLTF/GLTFResources.h rename to Kits/AMDTK/GLTF/GltfResources.h diff --git a/Kits/AMDTK/Readme.txt b/Kits/AMDTK/Readme.txt new file mode 100644 index 00000000..ac234d30 --- /dev/null +++ b/Kits/AMDTK/Readme.txt @@ -0,0 +1,9 @@ +AMD Tool Kit + +Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. + +Selection of customised GPUOpen Cauldron based utilities for use in sample code. + +Unless otherwise noted, all source code is subject to the terms of the MIT License. +. + diff --git a/Kits/AMDTK/ffx-api/PrebuiltSignedDLL/amd_fidelityfx_dx12.dll b/Kits/AMDTK/ffx-api/PrebuiltSignedDLL/amd_fidelityfx_dx12.dll index 9bd0fbbf..5ba1c77a 100644 Binary files a/Kits/AMDTK/ffx-api/PrebuiltSignedDLL/amd_fidelityfx_dx12.dll and b/Kits/AMDTK/ffx-api/PrebuiltSignedDLL/amd_fidelityfx_dx12.dll differ diff --git a/Kits/AMDTK/ffx-api/include/ffx_api/ffx_api_loader.h b/Kits/AMDTK/ffx-api/include/ffx_api/ffx_api_loader.h new file mode 100644 index 00000000..9df9ac32 --- /dev/null +++ b/Kits/AMDTK/ffx-api/include/ffx_api/ffx_api_loader.h @@ -0,0 +1,43 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +#include "ffx_api.h" +#include + +typedef struct ffxFunctions { + PfnFfxCreateContext CreateContext; + PfnFfxDestroyContext DestroyContext; + PfnFfxConfigure Configure; + PfnFfxQuery Query; + PfnFfxDispatch Dispatch; +} ffxFunctions; + +static inline void ffxLoadFunctions(ffxFunctions* pOutFunctions, HMODULE module) +{ + pOutFunctions->CreateContext = (PfnFfxCreateContext )GetProcAddress(module, "ffxCreateContext"); + pOutFunctions->DestroyContext = (PfnFfxDestroyContext)GetProcAddress(module, "ffxDestroyContext"); + pOutFunctions->Configure = (PfnFfxConfigure )GetProcAddress(module, "ffxConfigure"); + pOutFunctions->Query = (PfnFfxQuery )GetProcAddress(module, "ffxQuery"); + pOutFunctions->Dispatch = (PfnFfxDispatch )GetProcAddress(module, "ffxDispatch"); +} diff --git a/Kits/AMDTK/ffx-api/include/ffx_api/vk/ffx_api_vk.h b/Kits/AMDTK/ffx-api/include/ffx_api/vk/ffx_api_vk.h new file mode 100644 index 00000000..1f56ea6d --- /dev/null +++ b/Kits/AMDTK/ffx-api/include/ffx_api/vk/ffx_api_vk.h @@ -0,0 +1,360 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#include "../ffx_api.h" +#include "../ffx_api_types.h" +#include + +/// FFX specific callback type when submitting a command buffer to a queue. +typedef VkResult (*PFN_vkQueueSubmitFFXAPI)(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); + +/// Helper stucture +struct VkQueueInfoFFXAPI +{ + VkQueue queue; ///< the vulkan queue + uint32_t familyIndex; ///< the queue family index, that will be used to perform queue family ownership transfer + PFN_vkQueueSubmitFFXAPI submitFunc; ///< an optional submit function in case there might be some concurrent submissions +}; + +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK 0x0000003u +struct ffxCreateBackendVKDesc +{ + ffxCreateContextDescHeader header; + VkDevice vkDevice; ///< the logical device used by the program. + VkPhysicalDevice vkPhysicalDevice; ///< the physical device used by the program. + PFN_vkGetDeviceProcAddr vkDeviceProcAddr; ///< function pointer to get device procedure addresses +}; + +#define FFX_API_EFFECT_ID_FGSC_VK 0x00040000u + +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_FGSWAPCHAIN_VK 0x40001u +struct ffxCreateContextDescFrameGenerationSwapChainVK +{ + ffxCreateContextDescHeader header; + VkPhysicalDevice physicalDevice; ///< the physicak device used by the program. + VkDevice device; ///< the logical device used by the program. + VkSwapchainKHR* swapchain; ///< the current swapchain to be replaced. Will be destroyed when the context is created. This can be VK_NULL_HANDLE. Will contain the new swapchain on return. + VkAllocationCallbacks* allocator; ///< optional allocation callbacks. + VkSwapchainCreateInfoKHR createInfo; ///< the description of the desired swapchain. If its VkSwapchainCreateInfoKHR::oldSwapchain field isn't VK_NULL_HANDLE, it should be the same as the ffxCreateContextDescFrameGenerationSwapChainVK::swapchain field above. + VkQueueInfoFFXAPI gameQueue; ///< the main graphics queue, where Present is called. + VkQueueInfoFFXAPI asyncComputeQueue; ///< A queue with Compute capability. + VkQueueInfoFFXAPI presentQueue; ///< A queue with Transfer and Present capabilities. + VkQueueInfoFFXAPI imageAcquireQueue; ///< A queue with no capability required. +}; + +#define FFX_API_CONFIGURE_DESC_TYPE_FGSWAPCHAIN_REGISTERUIRESOURCE_VK 0x40002u +struct ffxConfigureDescFrameGenerationSwapChainRegisterUiResourceVK +{ + ffxConfigureDescHeader header; + struct FfxApiResource uiResource; ///< Resource containing user interface for composition. May be empty. + uint32_t flags; ///< Zero or combination of values from FfxApiUiCompositionFlags. +}; + +#define FFX_API_QUERY_DESC_TYPE_FGSWAPCHAIN_INTERPOLATIONCOMMANDLIST_VK 0x40003u +struct ffxQueryDescFrameGenerationSwapChainInterpolationCommandListVK +{ + ffxQueryDescHeader header; + void** pOutCommandList; ///< Output command nuffer (VkCommandBuffer) to be used for frame generation dispatch. +}; + +#define FFX_API_QUERY_DESC_TYPE_FGSWAPCHAIN_INTERPOLATIONTEXTURE_VK 0x40004u +struct ffxQueryDescFrameGenerationSwapChainInterpolationTextureVK +{ + ffxQueryDescHeader header; + struct FfxApiResource* pOutTexture; ///< Output resource in which the frame interpolation result should be placed. +}; + +#define FFX_API_DISPATCH_DESC_TYPE_FGSWAPCHAIN_WAIT_FOR_PRESENTS_VK 0x40007u +struct ffxDispatchDescFrameGenerationSwapChainWaitForPresentsVK +{ + ffxDispatchDescHeader header; +}; + +#define FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_KEYVALUE_VK 0x40008u +struct ffxConfigureDescFrameGenerationSwapChainKeyValueVK +{ + ffxConfigureDescHeader header; + uint64_t key; ///< Configuration key, member of the FfxApiConfigureFrameGenerationSwapChainKeyVK enumeration. + uint64_t u64; ///< Integer value or enum value to set. + void* ptr; ///< Pointer to set or pointer to value to set. +}; + +//enum value matches enum FfxFrameInterpolationSwapchainConfigureKey +enum FfxApiConfigureFrameGenerationSwapChainKeyVK +{ + FFX_API_CONFIGURE_FG_SWAPCHAIN_KEY_WAITCALLBACK = 0, ///< Sets FfxWaitCallbackFunc + FFX_API_CONFIGURE_FG_SWAPCHAIN_KEY_FRAMEPACINGTUNING = 2, ///< Sets FfxApiSwapchainFramePacingTuning casted from ptr +}; + +#define FFX_API_QUERY_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_GPU_MEMORY_USAGE_VK 0x00040009u +struct ffxQueryFrameGenerationSwapChainGetGPUMemoryUsageVK +{ + ffxQueryDescHeader header; + struct FfxApiEffectMemoryUsage* gpuMemoryUsageFrameGenerationSwapchain; +}; + +/// Function to get the number of presents. This is useful when using frame interpolation +typedef uint64_t (*PFN_getLastPresentCountFFXAPI)(VkSwapchainKHR); + +/// FFX API specific functions to create and destroy a swapchain +typedef VkResult(*PFN_vkCreateSwapchainFFXAPI)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain, void* pContext); +typedef void(*PFN_vkDestroySwapchainFFXAPI)(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator, void* pContext); + +#define FFX_API_QUERY_DESC_TYPE_FGSWAPCHAIN_FUNCTIONS_VK 0x40005u +struct ffxQueryDescSwapchainReplacementFunctionsVK +{ + ffxQueryDescHeader header; + PFN_vkCreateSwapchainFFXAPI pOutCreateSwapchainFFXAPI; ///< Replacement of vkCreateSwapchainKHR. Can be called when swapchain is recreated but swapchain context isn't (for example when toggling vsync). + PFN_vkDestroySwapchainFFXAPI pOutDestroySwapchainFFXAPI; ///< Replacement of vkDestroySwapchainKHR. Can be called when swapchain is destroyed but swapchain context isn't. + PFN_vkGetSwapchainImagesKHR pOutGetSwapchainImagesKHR; ///< Replacement of vkGetSwapchainImagesKHR. + PFN_vkAcquireNextImageKHR pOutAcquireNextImageKHR; ///< Replacement of vkAcquireNextImageKHR. + PFN_vkQueuePresentKHR pOutQueuePresentKHR; ///< Replacement of vkQueuePresentKHR. + PFN_vkSetHdrMetadataEXT pOutSetHdrMetadataEXT; ///< Replacement of vkSetHdrMetadataEXT. + PFN_getLastPresentCountFFXAPI pOutGetLastPresentCountFFXAPI; ///< Additional function to get the number of times present has been called since the swapchain creation. +}; + +#define FFX_API_CREATE_CONTEXT_DESC_TYPE_FGSWAPCHAIN_MODE_VK 0x40010u +struct ffxCreateContextDescFrameGenerationSwapChainModeVK +{ + ffxCreateContextDescHeader header; + bool composeOnPresentQueue; ///< flags indicating that composition will happen on the present queue +}; + +static inline uint32_t ffxApiGetSurfaceFormatVK(VkFormat fmt) +{ + switch (fmt) + { + case VK_FORMAT_R32G32B32A32_SFLOAT: + return FFX_API_SURFACE_FORMAT_R32G32B32A32_FLOAT; + case VK_FORMAT_R32G32B32_SFLOAT: + return FFX_API_SURFACE_FORMAT_R32G32B32_FLOAT; + case VK_FORMAT_R32G32B32A32_UINT: + return FFX_API_SURFACE_FORMAT_R32G32B32A32_UINT; + case VK_FORMAT_R16G16B16A16_SFLOAT: + return FFX_API_SURFACE_FORMAT_R16G16B16A16_FLOAT; + case VK_FORMAT_R32G32_SFLOAT: + return FFX_API_SURFACE_FORMAT_R32G32_FLOAT; + case VK_FORMAT_R32_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_X8_D24_UNORM_PACK32: + return FFX_API_SURFACE_FORMAT_R32_UINT; + case VK_FORMAT_R8G8B8A8_UNORM: + return FFX_API_SURFACE_FORMAT_R8G8B8A8_UNORM; + case VK_FORMAT_R8G8B8A8_SNORM: + return FFX_API_SURFACE_FORMAT_R8G8B8A8_SNORM; + case VK_FORMAT_R8G8B8A8_SRGB: + return FFX_API_SURFACE_FORMAT_R8G8B8A8_SRGB; + case VK_FORMAT_B8G8R8A8_UNORM: + return FFX_API_SURFACE_FORMAT_B8G8R8A8_UNORM; + case VK_FORMAT_B8G8R8A8_SRGB: + return FFX_API_SURFACE_FORMAT_B8G8R8A8_SRGB; + case VK_FORMAT_B10G11R11_UFLOAT_PACK32: + return FFX_API_SURFACE_FORMAT_R11G11B10_FLOAT; + case VK_FORMAT_A2B10G10R10_UNORM_PACK32: + return FFX_API_SURFACE_FORMAT_R10G10B10A2_UNORM; + case VK_FORMAT_R16G16_SFLOAT: + return FFX_API_SURFACE_FORMAT_R16G16_FLOAT; + case VK_FORMAT_R16G16_UINT: + return FFX_API_SURFACE_FORMAT_R16G16_UINT; + case VK_FORMAT_R16G16_SINT: + return FFX_API_SURFACE_FORMAT_R16G16_SINT; + case VK_FORMAT_R16_SFLOAT: + return FFX_API_SURFACE_FORMAT_R16_FLOAT; + case VK_FORMAT_R16_UINT: + return FFX_API_SURFACE_FORMAT_R16_UINT; + case VK_FORMAT_R16_UNORM: + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_D16_UNORM_S8_UINT: + return FFX_API_SURFACE_FORMAT_R16_UNORM; + case VK_FORMAT_R16_SNORM: + return FFX_API_SURFACE_FORMAT_R16_SNORM; + case VK_FORMAT_R8_UNORM: + return FFX_API_SURFACE_FORMAT_R8_UNORM; + case VK_FORMAT_R8_UINT: + case VK_FORMAT_S8_UINT: + return FFX_API_SURFACE_FORMAT_R8_UINT; + case VK_FORMAT_R8G8_UNORM: + return FFX_API_SURFACE_FORMAT_R8G8_UNORM; + case VK_FORMAT_R8G8_UINT: + return FFX_API_SURFACE_FORMAT_R8G8_UINT; + case VK_FORMAT_R32_SFLOAT: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return FFX_API_SURFACE_FORMAT_R32_FLOAT; + case VK_FORMAT_E5B9G9R9_UFLOAT_PACK32: + return FFX_API_SURFACE_FORMAT_R9G9B9E5_SHAREDEXP; + case VK_FORMAT_UNDEFINED: + return FFX_API_SURFACE_FORMAT_UNKNOWN; + + default: + // NOTE: we do not support typeless formats here + //FFX_ASSERT_MESSAGE(false, "Format not yet supported"); + return FFX_API_SURFACE_FORMAT_UNKNOWN; + } +} + +static inline uint32_t ffxApiGetSurfaceFormatToGamma(uint32_t fmt) +{ + switch (fmt) + { + case (FFX_API_SURFACE_FORMAT_R8G8B8A8_UNORM): + return FFX_API_SURFACE_FORMAT_R8G8B8A8_SRGB; + case (FFX_API_SURFACE_FORMAT_B8G8R8A8_UNORM): + return FFX_API_SURFACE_FORMAT_B8G8R8A8_SRGB; + default: + return fmt; + } +} + +static inline bool ffxApiIsDepthFormat(VkFormat fmt) +{ + switch (fmt) + { + case VK_FORMAT_D16_UNORM: + case VK_FORMAT_X8_D24_UNORM_PACK32: + case VK_FORMAT_D32_SFLOAT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return true; + + default: + return false; + } +} + +static inline bool ffxApiIsStencilFormat(VkFormat fmt) +{ + switch (fmt) + { + case VK_FORMAT_S8_UINT: + case VK_FORMAT_D16_UNORM_S8_UINT: + case VK_FORMAT_D24_UNORM_S8_UINT: + case VK_FORMAT_D32_SFLOAT_S8_UINT: + return true; + + default: + return false; + } +} + +static inline FfxApiResourceDescription ffxApiGetBufferResourceDescriptionVK(const VkBuffer buffer, + const VkBufferCreateInfo createInfo, + uint32_t additionalUsages) +{ + FfxApiResourceDescription resourceDescription = {}; + + // This is valid + if (buffer == VK_NULL_HANDLE) + return resourceDescription; + + resourceDescription.flags = FFX_API_RESOURCE_FLAGS_NONE; + resourceDescription.usage = additionalUsages; + resourceDescription.size = (uint32_t)createInfo.size; + resourceDescription.stride = 0; + resourceDescription.format = FFX_API_SURFACE_FORMAT_UNKNOWN; + + if ((createInfo.usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT) != 0) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_UAV; + if ((createInfo.usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT) != 0) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_INDIRECT; + + // What should we initialize this to?? No case for this yet + resourceDescription.depth = 0; + resourceDescription.mipCount = 0; + + // Set the type + resourceDescription.type = FFX_API_RESOURCE_TYPE_BUFFER; + + return resourceDescription; +} + +static inline FfxApiResourceDescription ffxApiGetImageResourceDescriptionVK(const VkImage image, const VkImageCreateInfo createInfo, uint32_t additionalUsages) +{ + FfxApiResourceDescription resourceDescription = {}; + + // This is valid + if (image == VK_NULL_HANDLE) + return resourceDescription; + + // Set flags properly for resource registration + resourceDescription.flags = FFX_API_RESOURCE_FLAGS_NONE; + resourceDescription.usage = FFX_API_RESOURCE_USAGE_READ_ONLY; + + // Check for depth stencil use + if (ffxApiIsDepthFormat(createInfo.format)) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_DEPTHTARGET; + if (ffxApiIsStencilFormat(createInfo.format)) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_STENCILTARGET; + + // Unordered access use + if ((createInfo.usage & VK_IMAGE_USAGE_STORAGE_BIT) != 0) + resourceDescription.usage |= FFX_API_RESOURCE_USAGE_UAV; + + // Resource-specific supplemental use flags + resourceDescription.usage |= additionalUsages; + + resourceDescription.width = createInfo.extent.width; + resourceDescription.height = createInfo.extent.height; + resourceDescription.mipCount = createInfo.mipLevels; + resourceDescription.format = ffxApiGetSurfaceFormatVK(createInfo.format); + + // if the mutable flag is present, assume that the real format is sRGB + if ((createInfo.flags & VK_IMAGE_CREATE_MUTABLE_FORMAT_BIT) != 0) + resourceDescription.format = ffxApiGetSurfaceFormatToGamma(resourceDescription.format); + + switch (createInfo.imageType) + { + case VK_IMAGE_TYPE_1D: + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE1D; + break; + case VK_IMAGE_TYPE_2D: + resourceDescription.depth = createInfo.arrayLayers; + if ((additionalUsages & FFX_API_RESOURCE_USAGE_ARRAYVIEW) != 0) + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE2D; + else if ((createInfo.flags & VK_IMAGE_CREATE_CUBE_COMPATIBLE_BIT) != 0) + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE_CUBE; + else + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE2D; + break; + case VK_IMAGE_TYPE_3D: + resourceDescription.depth = createInfo.extent.depth; + resourceDescription.type = FFX_API_RESOURCE_TYPE_TEXTURE3D; + break; + default: + //FFX_ASSERT_MESSAGE(false, "FFXInterface: VK: Unsupported texture dimension requested. Please implement."); + break; + } + + return resourceDescription; +} + +static inline FfxApiResource ffxApiGetResourceVK(void* vkResource, FfxApiResourceDescription ffxResDescription, uint32_t state) +{ + FfxApiResource resource = {}; + resource.resource = vkResource; + resource.state = state; + resource.description = ffxResDescription; + + return resource; +} diff --git a/Kits/AMDTK/ffx-api/include/ffx_api/vk/ffx_api_vk.hpp b/Kits/AMDTK/ffx-api/include/ffx_api/vk/ffx_api_vk.hpp new file mode 100644 index 00000000..6eb2cce7 --- /dev/null +++ b/Kits/AMDTK/ffx-api/include/ffx_api/vk/ffx_api_vk.hpp @@ -0,0 +1,83 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +#include "../ffx_api.hpp" +#include "ffx_api_vk.h" + +// Helper types for header initialization. Api definition is in .h file. + +namespace ffx +{ + +template<> +struct struct_type : std::integral_constant {}; + +struct CreateBackendVKDesc : public InitHelper {}; + +template<> +struct struct_type : std::integral_constant {}; + +struct CreateContextDescFrameGenerationSwapChainVK : public InitHelper {}; + +template<> +struct struct_type : std::integral_constant {}; + +struct CreateContextDescFrameGenerationSwapChainModeVK : public InitHelper {}; + +template<> +struct struct_type : std::integral_constant {}; + +struct ConfigureDescFrameGenerationSwapChainRegisterUiResourceVK : public InitHelper {}; + +template<> +struct struct_type : std::integral_constant {}; + +struct QueryDescFrameGenerationSwapChainInterpolationCommandListVK : public InitHelper {}; + +template<> +struct struct_type : std::integral_constant {}; + +struct QueryDescFrameGenerationSwapChainInterpolationTextureVK : public InitHelper {}; + +template<> +struct struct_type : std::integral_constant {}; + +struct QueryDescSwapchainReplacementFunctionsVK : public InitHelper {}; + +template <> +struct struct_type : std::integral_constant{}; + +struct DispatchDescFrameGenerationSwapChainWaitForPresentsVK : public InitHelper{}; + +template<> +struct struct_type : std::integral_constant {}; + +struct ConfigureDescFrameGenerationSwapChainKeyValueVK : public InitHelper {}; + +template<> +struct struct_type : std::integral_constant {}; + +struct QueryFrameGenerationSwapChainGetGPUMemoryUsageVK : public InitHelper {}; + +} diff --git a/Kits/AMDTK/ffx-api/src/backends.cpp b/Kits/AMDTK/ffx-api/src/backends.cpp new file mode 100644 index 00000000..b532a2e9 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/backends.cpp @@ -0,0 +1,125 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "backends.h" + +#ifdef FFX_BACKEND_DX12 +#include +#include +#endif // FFX_BACKEND_DX12 +#ifdef FFX_BACKEND_VK +#include +#include +#endif // #ifdef FFX_BACKEND_VK + +ffxReturnCode_t CreateBackend(const ffxCreateContextDescHeader *desc, bool& backendFound, FfxInterface *iface, size_t contexts, Allocator& alloc) +{ + for (const auto* it = desc->pNext; it; it = it->pNext) + { + switch (it->type) + { +#ifdef FFX_BACKEND_DX12 + case FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12: + { + // check for double backend just to make sure. + if (backendFound) + return FFX_API_RETURN_ERROR; + backendFound = true; + + const auto *backendDesc = reinterpret_cast(it); + FfxDevice device = ffxGetDeviceDX12(backendDesc->device); + size_t scratchBufferSize = ffxGetScratchMemorySizeDX12(contexts); + void* scratchBuffer = alloc.alloc(scratchBufferSize); + memset(scratchBuffer, 0, scratchBufferSize); + TRY2(ffxGetInterfaceDX12(iface, device, scratchBuffer, scratchBufferSize, contexts)); + break; + } +#elif FFX_BACKEND_VK + case FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK: + { + // check for double backend just to make sure. + if (backendFound) + return FFX_API_RETURN_ERROR; + backendFound = true; + + const auto *backendDesc = reinterpret_cast(it); + VkDeviceContext deviceContext = { backendDesc->vkDevice, backendDesc->vkPhysicalDevice, backendDesc->vkDeviceProcAddr }; + FfxDevice device = ffxGetDeviceVK(&deviceContext); + size_t scratchBufferSize = ffxGetScratchMemorySizeVK(backendDesc->vkPhysicalDevice, contexts); + void* scratchBuffer = alloc.alloc(scratchBufferSize); + memset(scratchBuffer, 0, scratchBufferSize); + TRY2(ffxGetInterfaceVK(iface, device, scratchBuffer, scratchBufferSize, contexts)); + break; + } +#endif // FFX_BACKEND_DX12 + } + } + return FFX_API_RETURN_OK; +} + +void* GetDevice(const ffxApiHeader* desc) +{ + for (const auto* it = desc; it; it = it->pNext) + { + switch (it->type) + { + case FFX_API_QUERY_DESC_TYPE_GET_VERSIONS: + { + return reinterpret_cast(it)->device; + } +#ifdef FFX_BACKEND_DX12 + case FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12: + { + return reinterpret_cast(it)->device; + } + case FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_FOR_HWND_DX12: + { + ID3D12Device* device = nullptr; + reinterpret_cast(it)->gameQueue->GetDevice(IID_PPV_ARGS(&device)); + device->Release(); + return device; + } + case FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_NEW_DX12: + { + ID3D12Device* device = nullptr; + reinterpret_cast(it)->gameQueue->GetDevice(IID_PPV_ARGS(&device)); + device->Release(); + return device; + } + case FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_WRAP_DX12: + { + ID3D12Device* device = nullptr; + reinterpret_cast(it)->gameQueue->GetDevice(IID_PPV_ARGS(&device)); + device->Release(); + return device; + } +#endif +#ifdef FFX_BACKEND_VK + case FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK: + { + return nullptr; // no idea what to return for now. + } +#endif + } + } + return nullptr; +} diff --git a/Kits/AMDTK/ffx-api/src/backends.h b/Kits/AMDTK/ffx-api/src/backends.h new file mode 100644 index 00000000..4ac2a546 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/backends.h @@ -0,0 +1,38 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#include "ffx_provider.h" +#include +#include + +ffxReturnCode_t CreateBackend(const ffxCreateContextDescHeader* desc, bool& backendFound, FfxInterface* iface, size_t contexts, Allocator& alloc); + +inline ffxReturnCode_t MustCreateBackend(const ffxCreateContextDescHeader* desc, FfxInterface* iface, size_t contexts, Allocator& alloc) +{ + bool backendFound = false; + TRY(CreateBackend(desc, backendFound, iface, contexts, alloc)); + VERIFY(backendFound, FFX_API_RETURN_ERROR); + return FFX_API_RETURN_OK; +} + +void* GetDevice(const ffxApiHeader* desc); diff --git a/Kits/AMDTK/ffx-api/src/dx12/ffx_provider_framegenerationswapchain_dx12.cpp b/Kits/AMDTK/ffx-api/src/dx12/ffx_provider_framegenerationswapchain_dx12.cpp new file mode 100644 index 00000000..9fac8eeb --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/dx12/ffx_provider_framegenerationswapchain_dx12.cpp @@ -0,0 +1,198 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifdef FFX_BACKEND_DX12 +#include "ffx_provider_framegenerationswapchain_dx12.h" +#include +#include +#include + +#include + +bool ffxProvider_FrameGenerationSwapChain_DX12::CanProvide(uint64_t type) const +{ + return (type & FFX_API_EFFECT_MASK) == FFX_API_EFFECT_ID_FRAMEGENERATIONSWAPCHAIN_DX12; +} + +struct InternalFgScContext +{ + InternalContextHeader header; + IDXGISwapChain4* fiSwapChain; +}; + +uint64_t ffxProvider_FrameGenerationSwapChain_DX12::GetId() const +{ + // FG SwapChain DX12, version 1.1.3 + return 0xF65C'DD12'01'001'003ui64; +} + +const char* ffxProvider_FrameGenerationSwapChain_DX12::GetVersionName() const +{ + return "1.1.3"; +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_DX12::CreateContext(ffxContext* context, + ffxCreateContextDescHeader* header, + Allocator& alloc) const +{ + if (auto desc = ffx::DynamicCast(header)) + { + InternalFgScContext* internal_context = alloc.construct(); + VERIFY(internal_context, FFX_API_RETURN_ERROR_MEMORY); + internal_context->header.provider = this; + + FfxSwapchain swapChain = ffxGetSwapchainDX12(*desc->swapchain); + TRY2(ffxReplaceSwapchainForFrameinterpolationDX12(desc->gameQueue, swapChain)); + internal_context->fiSwapChain = *desc->swapchain = ffxGetDX12SwapchainPtr(swapChain); + + // reference tracked by internal_context + internal_context->fiSwapChain->AddRef(); + + *context = internal_context; + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + InternalFgScContext* internal_context = alloc.construct(); + VERIFY(internal_context, FFX_API_RETURN_ERROR_MEMORY); + internal_context->header.provider = this; + + FfxSwapchain swapChain; + TRY2(ffxCreateFrameinterpolationSwapchainDX12(desc->desc, desc->gameQueue, desc->dxgiFactory, swapChain)); + internal_context->fiSwapChain = *desc->swapchain = ffxGetDX12SwapchainPtr(swapChain); + + // reference tracked by internal_context + internal_context->fiSwapChain->AddRef(); + + *context = internal_context; + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + InternalFgScContext* internal_context = alloc.construct(); + VERIFY(internal_context, FFX_API_RETURN_ERROR_MEMORY); + internal_context->header.provider = this; + + FfxSwapchain swapChain; + TRY2(ffxCreateFrameinterpolationSwapchainForHwndDX12(desc->hwnd, desc->desc, desc->fullscreenDesc, desc->gameQueue, desc->dxgiFactory, swapChain)); + internal_context->fiSwapChain = *desc->swapchain = ffxGetDX12SwapchainPtr(swapChain); + + // reference tracked by internal_context + internal_context->fiSwapChain->AddRef(); + + *context = internal_context; + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_DX12::DestroyContext(ffxContext* context, Allocator& alloc) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgScContext* internal_context = reinterpret_cast(*context); + + internal_context->fiSwapChain->Release(); + + alloc.dealloc(internal_context); + + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_DX12::Configure(ffxContext* context, const ffxConfigureDescHeader* header) const +{ + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgScContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + TRY2(ffxRegisterFrameinterpolationUiResourceDX12(ffxGetSwapchainDX12(internal_context->fiSwapChain), Convert(desc->uiResource), desc->flags)); + + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + TRY2(ffxConfigureFrameInterpolationSwapchainDX12(ffxGetSwapchainDX12(internal_context->fiSwapChain), static_cast (desc->key), desc->ptr)); + + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_PARAMETER; + } +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_DX12::Query(ffxContext* context, ffxQueryDescHeader* header) const +{ + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgScContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + FfxCommandList outCommandList{}; + TRY2(ffxGetFrameinterpolationCommandlistDX12(ffxGetSwapchainDX12(internal_context->fiSwapChain), outCommandList)); + *desc->pOutCommandList = outCommandList; + + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + *desc->pOutTexture = Convert(ffxGetFrameinterpolationTextureDX12(ffxGetSwapchainDX12(internal_context->fiSwapChain))); + + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + TRY2(ffxFrameInterpolationSwapchainGetGpuMemoryUsageDX12(ffxGetSwapchainDX12(internal_context->fiSwapChain), reinterpret_cast (desc->gpuMemoryUsageFrameGenerationSwapchain))); + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_PARAMETER; + } +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_DX12::Dispatch(ffxContext* context, const ffxDispatchDescHeader* header) const +{ + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + InternalFgScContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + ffxWaitForPresents(internal_context->fiSwapChain); + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR; + } +} + +ffxProvider_FrameGenerationSwapChain_DX12 ffxProvider_FrameGenerationSwapChain_DX12::Instance; +#endif // FFX_BACKEND_DX12 diff --git a/Kits/AMDTK/ffx-api/src/dx12/ffx_provider_framegenerationswapchain_dx12.h b/Kits/AMDTK/ffx-api/src/dx12/ffx_provider_framegenerationswapchain_dx12.h new file mode 100644 index 00000000..095b7866 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/dx12/ffx_provider_framegenerationswapchain_dx12.h @@ -0,0 +1,51 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#ifdef FFX_BACKEND_DX12 +#include "../ffx_provider.h" + +class ffxProvider_FrameGenerationSwapChain_DX12: public ffxProvider +{ +public: + ffxProvider_FrameGenerationSwapChain_DX12() = default; + virtual ~ffxProvider_FrameGenerationSwapChain_DX12() = default; + + virtual bool CanProvide(uint64_t type) const override; + + virtual uint64_t GetId() const override; + + virtual const char* GetVersionName() const override; + + virtual ffxReturnCode_t CreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, Allocator& alloc) const override; + + virtual ffxReturnCode_t DestroyContext(ffxContext* context, Allocator& alloc) const override; + + virtual ffxReturnCode_t Configure(ffxContext* context, const ffxConfigureDescHeader* desc) const override; + + virtual ffxReturnCode_t Query(ffxContext* context, ffxQueryDescHeader* desc) const override; + + virtual ffxReturnCode_t Dispatch(ffxContext* context, const ffxDispatchDescHeader* desc) const override; + + static ffxProvider_FrameGenerationSwapChain_DX12 Instance; +}; +#endif // FFX_BACKEND_DX12 diff --git a/Kits/AMDTK/ffx-api/src/ffx_api.cpp b/Kits/AMDTK/ffx-api/src/ffx_api.cpp new file mode 100644 index 00000000..9852e632 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_api.cpp @@ -0,0 +1,132 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include +#include +#include +#include "ffx_provider.h" +#include "backends.h" + +static uint64_t GetVersionOverride(const ffxApiHeader* header) +{ + for (auto it = header; it; it = it->pNext) + { + if (auto versionDesc = ffx::DynamicCast(it)) + { + return versionDesc->versionId; + } + } + return 0; +} + +FFX_API_ENTRY ffxReturnCode_t ffxCreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, const ffxAllocationCallbacks* memCb) +{ + VERIFY(desc != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + + *context = nullptr; + + const ffxProvider* provider = GetffxProvider(desc->type, GetVersionOverride(desc), GetDevice(desc)); + VERIFY(provider != nullptr, FFX_API_RETURN_NO_PROVIDER); + + Allocator alloc{memCb}; + return provider->CreateContext(context, desc, alloc); +} + +FFX_API_ENTRY ffxReturnCode_t ffxDestroyContext(ffxContext* context, const ffxAllocationCallbacks* memCb) +{ + VERIFY(context != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + + Allocator alloc{memCb}; + return GetAssociatedProvider(context)->DestroyContext(context, alloc); +} + +FFX_API_ENTRY ffxReturnCode_t ffxConfigure(ffxContext* context, const ffxConfigureDescHeader* desc) +{ + VERIFY(desc != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + + return GetAssociatedProvider(context)->Configure(context, desc); +} + +FFX_API_ENTRY ffxReturnCode_t ffxQuery(ffxContext* context, ffxQueryDescHeader* header) +{ + VERIFY(header != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + + if (context == nullptr) + { + if (auto desc = ffx::DynamicCast(header)) + { + // if output count is zero or no other pointer passed, count providers only + if (desc->outputCount && (*desc->outputCount == 0 || (!desc->versionIds && !desc->versionNames))) + { + *desc->outputCount = GetProviderCount(desc->createDescType, desc->device); + } + else if (desc->outputCount && *desc->outputCount > 0) + { + uint64_t capacity = *desc->outputCount; + *desc->outputCount = GetProviderVersions(desc->createDescType, desc->device, capacity, desc->versionIds, desc->versionNames); + } + return FFX_API_RETURN_OK; + } + else if (auto provider = GetffxProvider(header->type, GetVersionOverride(header), GetDevice(header))) + { + return provider->Query(nullptr, header); + } + else + { + return FFX_API_RETURN_NO_PROVIDER; + } + } + + if (auto desc = ffx::DynamicCast(header)) + { + if (context != nullptr) + { + auto provider = GetAssociatedProvider(context); + if (provider) + { + desc->versionId = provider->GetId(); + desc->versionName = provider->GetVersionName(); + return FFX_API_RETURN_OK; + } + } + else + { + return FFX_API_RETURN_ERROR_PARAMETER; + } + + desc->versionId = 0u; + desc->versionName = nullptr; + return FFX_API_RETURN_NO_PROVIDER; + } + + return GetAssociatedProvider(context)->Query(context, header); +} + +FFX_API_ENTRY ffxReturnCode_t ffxDispatch(ffxContext* context, const ffxDispatchDescHeader* desc) +{ + VERIFY(desc != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context != nullptr, FFX_API_RETURN_ERROR_PARAMETER); + + return GetAssociatedProvider(context)->Dispatch(context, desc); +} diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider.cpp b/Kits/AMDTK/ffx-api/src/ffx_provider.cpp new file mode 100644 index 00000000..d7c0e64b --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider.cpp @@ -0,0 +1,251 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_provider.h" + +#include "ffx_provider_fsr2.h" +#include "ffx_provider_fsr3upscale.h" +#include "ffx_provider_framegeneration.h" +#include "ffx_provider_external.h" + +#include +#include + +#include + +#ifdef FFX_BACKEND_DX12 +#include "dx12/ffx_provider_framegenerationswapchain_dx12.h" +#endif // FFX_BACKEND_DX12 + +#ifdef FFX_BACKEND_VK +#include "vk/ffx_provider_framegenerationswapchain_vk.h" +#endif // FFX_BACKEND_VK + +static constexpr ffxProvider* providers[] = { + &ffxProvider_FSR3Upscale::Instance, + &ffxProvider_FSR2::Instance, + &ffxProvider_FrameGeneration::Instance, +#ifdef FFX_BACKEND_DX12 + &ffxProvider_FrameGenerationSwapChain_DX12::Instance, +#endif // FFX_BACKEND_DX12 +#ifdef FFX_BACKEND_VK + &ffxProvider_FrameGenerationSwapChain_VK::Instance, +#endif // FFX_BACKEND_VK +}; +static constexpr size_t providerCount = _countof(providers); + +static std::array, 10> externalProviders = {}; + +MIDL_INTERFACE("b58d6601-7401-4234-8180-6febfc0e484c") +IAmdExtFfxApi : public IUnknown +{ +public: + // Update FFX API provider + virtual HRESULT UpdateFfxApiProvider(void* pData, uint32_t dataSizeInBytes) = 0; +}; + +struct ExternalProviderData +{ + uint32_t structVersion = 0; + uint64_t descType; + ffxProviderInterface provider; +}; +#define FFX_EXTERNAL_PROVIDER_STRUCT_VERSION 1u + +void GetExternalProviders(ID3D12Device* device, uint64_t descType) +{ + static IAmdExtFfxApi* apiExtension = nullptr; + + if (nullptr != device) + { + static bool ranOnce = false; + if (!ranOnce) + { + ranOnce = true; + static HMODULE hModule = GetModuleHandleA("amdxc64.dll"); + + if (device && hModule && !apiExtension) + { + typedef HRESULT(__cdecl * PFNAmdExtD3DCreateInterface)(IUnknown * pOuter, REFIID riid, void** ppvObject); + PFNAmdExtD3DCreateInterface AmdExtD3DCreateInterface = + static_cast((VOID*)GetProcAddress(hModule, "AmdExtD3DCreateInterface")); + if (AmdExtD3DCreateInterface) + { + HRESULT hr = AmdExtD3DCreateInterface(device, IID_PPV_ARGS(&apiExtension)); + + if (hr != S_OK) + { + if (apiExtension) + apiExtension->Release(); + apiExtension = nullptr; + } + } + } + } + } + + if (apiExtension) + { + ExternalProviderData data; + data.structVersion = FFX_EXTERNAL_PROVIDER_STRUCT_VERSION; + data.descType = descType; + HRESULT hr = apiExtension->UpdateFfxApiProvider(&data, sizeof(data)); + if (hr != S_OK) + return; + + for (auto& slot : externalProviders) + { + if (slot.has_value() && slot->GetId() == data.provider.versionId) + { + // we already have this provider saved. + break; + } + if (!slot.has_value()) + { + // first free slot. slots are filled start to end and never released. + // we do not have this provider yet, add it to the list. + slot = ffxProviderExternal{data.provider}; + break; + } + } + } + +} + +const ffxProvider* GetffxProvider(ffxStructType_t descType, uint64_t overrideId, void* device) +{ + // check driver-side providers + GetExternalProviders(reinterpret_cast(device), descType); + + // If we are overriding, do not make the best provider choice decision + if (overrideId) + { + for (const auto& provider : externalProviders) + { + if (provider.has_value()) + { + if (provider->GetId() == overrideId && provider->CanProvide(descType)) + return &*provider; + } + } + + for (size_t i = 0; i < providerCount; ++i) + { + if (providers[i]->GetId() == overrideId && providers[i]->CanProvide(descType)) + return providers[i]; + } + + } + else + { + const ffxProvider* bestExternalProvider = nullptr; + const ffxProvider* bestInternalProvider = nullptr; + + for (const auto& provider : externalProviders) + { + if (provider.has_value()) + { + if (provider->CanProvide(descType)) + { + bestExternalProvider = &*provider; + break; + } + } + } + + for (size_t i = 0; i < providerCount; ++i) + { + if (providers[i]->CanProvide(descType)) + { + bestInternalProvider = providers[i]; + break; + } + } + + if ((bestExternalProvider != nullptr) && (bestInternalProvider != nullptr)) + { + // Do a version check, and take the newest version. + // Id()s have lowest 31b valid - bit32 is reserved for "driver override" indication + uint64_t extId = bestExternalProvider->GetId() & (0x7FFFFFFFu); + uint64_t intId = bestInternalProvider->GetId() & (0x7FFFFFFFu); + + if (extId > intId) + { + return bestExternalProvider; + } + } + + return bestInternalProvider; + } + + return nullptr; +} + +const ffxProvider* GetAssociatedProvider(ffxContext* context) +{ + const InternalContextHeader* hdr = (const InternalContextHeader*)(*context); + const ffxProvider* provider = hdr->provider; + return provider; +} + +uint64_t GetProviderCount(ffxStructType_t descType, void* device) +{ + return GetProviderVersions(descType, device, UINT64_MAX, nullptr, nullptr); +} + +uint64_t GetProviderVersions(ffxStructType_t descType, void* device, uint64_t capacity, uint64_t* versionIds, const char** versionNames) +{ + uint64_t count = 0; + + // check driver-side providers + GetExternalProviders(reinterpret_cast(device), descType); + + for (const auto& provider : externalProviders) + { + if (count >= capacity) break; + if (provider.has_value() && provider->CanProvide(descType)) + { + auto index = count; + count++; + if (versionIds) + versionIds[index] = provider->GetId(); + if (versionNames) + versionNames[index] = provider->GetVersionName(); + } + } + + for (size_t i = 0; i < providerCount; ++i) + { + if (count >= capacity) break; + if (providers[i]->CanProvide(descType)) + { + auto index = count; + count++; + if (versionIds) + versionIds[index] = providers[i]->GetId(); + if (versionNames) + versionNames[index] = providers[i]->GetVersionName(); + } + } + + return count; +} diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider.h b/Kits/AMDTK/ffx-api/src/ffx_provider.h new file mode 100644 index 00000000..d501887e --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider.h @@ -0,0 +1,146 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#include +#include +#include + +#define VERIFY(_cond, _retcode) \ + if (!(_cond)) return _retcode + +#define TRY(_expr) \ + if (ffxReturnCode_t _rc = (_expr); _rc != FFX_API_RETURN_OK) return _rc + +#define TRY2(_expr) \ + if (FFX_OK != (_expr)) return FFX_API_RETURN_ERROR_RUNTIME_ERROR + +struct Allocator +{ + const ffxAllocationCallbacks* cb; + + void* alloc(size_t sz) + { + if (cb) + return cb->alloc(cb->pUserData, static_cast(sz)); + else + return malloc(sz); + } + + void dealloc(void* ptr) + { + if (cb) + cb->dealloc(cb->pUserData, ptr); + else + free(ptr); + } + + template + T* construct(Args&&... args) + { + void* addr = alloc(sizeof(T)); + return ::new(addr) T(std::forward(args)...); + } +}; + +class ffxProvider +{ +public: + virtual ~ffxProvider() = default; + + virtual bool CanProvide(uint64_t) const + { + return false; + } + + virtual uint64_t GetId() const = 0; + + virtual const char* GetVersionName() const = 0; + + virtual ffxReturnCode_t CreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, Allocator& alloc) const = 0; + + virtual ffxReturnCode_t DestroyContext(ffxContext* context, Allocator& alloc) const = 0; + + virtual ffxReturnCode_t Configure(ffxContext* context, const ffxConfigureDescHeader* desc) const = 0; + + virtual ffxReturnCode_t Query(ffxContext* context, ffxQueryDescHeader* desc) const = 0; + + virtual ffxReturnCode_t Dispatch(ffxContext* context, const ffxDispatchDescHeader* desc) const = 0; +}; + +const ffxProvider* GetffxProvider(ffxStructType_t descType, uint64_t overrideId, void* device); + +const ffxProvider* GetAssociatedProvider(ffxContext* context); + +uint64_t GetProviderCount(ffxStructType_t descType, void* device); + +uint64_t GetProviderVersions(ffxStructType_t descType, void* device, uint64_t capacity, uint64_t* versionIds, const char** versionNames); + +struct InternalContextHeader +{ + const ffxProvider* provider; +}; + +template +static inline T ConvertEnum(uint32_t enumVal) +{ + return static_cast(enumVal); +} + +template +static inline uint32_t ReverseConvertEnum(T enumVal) +{ + return static_cast(enumVal); +} + +static inline FfxResource Convert(const FfxApiResource& inRes) +{ + FfxResource outRes{}; + memset(outRes.name, 0, sizeof(outRes.name)); + outRes.resource = inRes.resource; + outRes.state = ConvertEnum(inRes.state); + outRes.description.type = ConvertEnum(inRes.description.type); + outRes.description.format = ConvertEnum(inRes.description.format); + outRes.description.width = inRes.description.width; + outRes.description.height = inRes.description.height; + outRes.description.depth = inRes.description.depth; + outRes.description.mipCount = inRes.description.mipCount; + outRes.description.flags = ConvertEnum(inRes.description.flags); + outRes.description.usage = ConvertEnum(inRes.description.usage); + return outRes; +} + +static inline FfxApiResource Convert(const FfxResource& inRes) +{ + FfxApiResource outRes{}; + outRes.resource = inRes.resource; + outRes.state = ReverseConvertEnum(inRes.state); + outRes.description.type = ReverseConvertEnum(inRes.description.type); + outRes.description.format = ReverseConvertEnum(inRes.description.format); + outRes.description.width = inRes.description.width; + outRes.description.height = inRes.description.height; + outRes.description.depth = inRes.description.depth; + outRes.description.mipCount = inRes.description.mipCount; + outRes.description.flags = ReverseConvertEnum(inRes.description.flags); + outRes.description.usage = ReverseConvertEnum(inRes.description.usage); + return outRes; +} diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider_external.h b/Kits/AMDTK/ffx-api/src/ffx_provider_external.h new file mode 100644 index 00000000..edaadffe --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider_external.h @@ -0,0 +1,95 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +#include +#include "ffx_provider.h" + +typedef uint32_t (*pfnCanProvide)(uint64_t typeId); +typedef uint32_t (*pfnCreateContext)(void* context, void* desc, const void* allocator); +typedef uint32_t (*pfnDestroyContext)(void* context, const void* allocator); +typedef uint32_t (*pfnConfigure)(void* context, const void* desc); +typedef uint32_t (*pfnQuery)(void* context, void* desc); +typedef uint32_t (*pfnDispatch)(void* context, const void* desc); + +struct ffxProviderInterface +{ + uint64_t versionId; + const char* versionName; + pfnCanProvide canProvide; + pfnCreateContext createContext; + pfnDestroyContext destroyContext; + pfnConfigure configure; + pfnQuery query; + pfnDispatch dispatch; +}; + +class ffxProviderExternal final : public ffxProvider { +public: + ffxProviderInterface data; + + ffxProviderExternal(ffxProviderInterface data) : data(data) {} + + bool CanProvide(uint64_t type) const override + { + return data.canProvide(type) != 0; + } + + uint64_t GetId() const override + { + return data.versionId; + } + + const char* GetVersionName() const override + { + return data.versionName; + } + + ffxReturnCode_t CreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, Allocator& alloc) const override + { + TRY(data.createContext(context, desc, alloc.cb)); + // Ensure the provider is set to this external wrapper class. + reinterpret_cast(*context)->provider = this; + return FFX_API_RETURN_OK; + } + + ffxReturnCode_t DestroyContext(ffxContext* context, Allocator& alloc) const override + { + return data.destroyContext(context, alloc.cb); + } + + ffxReturnCode_t Configure(ffxContext* context, const ffxConfigureDescHeader* desc) const override + { + return data.configure(context, desc); + } + + ffxReturnCode_t Query(ffxContext* context, ffxQueryDescHeader* desc) const override + { + return data.query(context, desc); + } + + ffxReturnCode_t Dispatch(ffxContext* context, const ffxDispatchDescHeader* desc) const override + { + return data.dispatch(context, desc); + } +}; diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider_framegeneration.cpp b/Kits/AMDTK/ffx-api/src/ffx_provider_framegeneration.cpp new file mode 100644 index 00000000..5b6e9d7a --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider_framegeneration.cpp @@ -0,0 +1,573 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_provider_framegeneration.h" +#include "backends.h" +#include +#include +#include +#include +#include + +#include + +bool ffxProvider_FrameGeneration::CanProvide(uint64_t type) const +{ + return (type & FFX_API_EFFECT_MASK) == FFX_API_EFFECT_ID_FRAMEGENERATION; +} + +const uint32_t MAX_QUEUED_FRAMES = 2; + +struct InternalFgContext +{ + InternalContextHeader header; + + FfxInterface backendInterfaceFi; + FfxInterface backendInterfaceShared; + FfxOpticalflowContext ofContext; + FfxFrameInterpolationContext fiContext; + FfxResourceInternal sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_COUNT]; + uint32_t sharedResoureFrameToggle; + uint32_t effectContextIdShared; + float deltaTime; + bool asyncWorkloadSupported; + + FfxResource HUDLessColor; + FfxResource distortionField; + + bool frameGenEnabled; + uint32_t frameGenFlags; + ffxDispatchDescFrameGenerationPrepare prepareDescriptions[MAX_QUEUED_FRAMES]; + + struct Callbacks { + FfxApiPresentCallbackFunc presentCallback; + void* presentCallbackUserContext; + FfxApiFrameGenerationDispatchFunc frameGenerationCallback; + void* frameGenerationCallbackUserContext; + } callbacks[MAX_QUEUED_FRAMES]; + + uint64_t lastConfigureFrameID; + ffxApiMessage fpMessage; + uint32_t debugLevel; +}; + +#define STRINGIFY_(X) #X +#define STRINGIFY(X) STRINGIFY_(X) +#define MAKE_VERSION_STRING(major, minor, patch) STRINGIFY major "." STRINGIFY minor "." STRINGIFY patch + +uint64_t ffxProvider_FrameGeneration::GetId() const +{ + // FG, version from header + return 0xF600'0000ui64 << 32u | (FFX_SDK_MAKE_VERSION(FFX_FRAMEINTERPOLATION_VERSION_MAJOR, FFX_FRAMEINTERPOLATION_VERSION_MINOR, FFX_FRAMEINTERPOLATION_VERSION_PATCH) & 0xFFFF'FFFF); +} + +const char* ffxProvider_FrameGeneration::GetVersionName() const +{ + return MAKE_VERSION_STRING(FFX_FRAMEINTERPOLATION_VERSION_MAJOR, FFX_FRAMEINTERPOLATION_VERSION_MINOR, FFX_FRAMEINTERPOLATION_VERSION_PATCH); +} + +ffxReturnCode_t ffxProvider_FrameGeneration::CreateContext(ffxContext* context, ffxCreateContextDescHeader* header, Allocator& alloc) const +{ + if (auto desc = ffx::DynamicCast(header)) + { + InternalFgContext* internal_context = alloc.construct(); + VERIFY(internal_context, FFX_API_RETURN_ERROR_MEMORY); + internal_context->header.provider = this; + + TRY(MustCreateBackend(header, &internal_context->backendInterfaceShared, 1, alloc)); + TRY(MustCreateBackend(header, &internal_context->backendInterfaceFi, 2, alloc)); + + { // copied from ffxFsr3ContextCreate, simplified. + internal_context->asyncWorkloadSupported = (desc->flags & FFX_FRAMEGENERATION_ENABLE_ASYNC_WORKLOAD_SUPPORT) != 0; + + TRY2(internal_context->backendInterfaceShared.fpCreateBackendContext(&internal_context->backendInterfaceShared, FFX_EFFECT_SHAREDAPIBACKEND, nullptr, &internal_context->effectContextIdShared)); + + FfxOpticalflowContextDescription ofDescription = {}; + ofDescription.backendInterface = internal_context->backendInterfaceFi; + ofDescription.resolution.width = desc->displaySize.width; + ofDescription.resolution.height = desc->displaySize.height; + + // set up Opticalflow + TRY2(ffxOpticalflowContextCreate(&internal_context->ofContext, &ofDescription)); + + FfxFrameInterpolationContextDescription fiDescription = {0}; + fiDescription.backendInterface = internal_context->backendInterfaceFi; + fiDescription.flags |= (desc->flags & FFX_FRAMEGENERATION_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) ? FFX_FRAMEINTERPOLATION_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS : 0; + fiDescription.flags |= (desc->flags & FFX_FRAMEGENERATION_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION) ? FFX_FRAMEINTERPOLATION_ENABLE_JITTER_MOTION_VECTORS : 0; + fiDescription.flags |= (desc->flags & FFX_FRAMEGENERATION_ENABLE_DEPTH_INVERTED) ? FFX_FRAMEINTERPOLATION_ENABLE_DEPTH_INVERTED : 0; + fiDescription.flags |= (desc->flags & FFX_FRAMEGENERATION_ENABLE_DEPTH_INFINITE) ? FFX_FRAMEINTERPOLATION_ENABLE_DEPTH_INFINITE : 0; + fiDescription.flags |= (desc->flags & FFX_FRAMEGENERATION_ENABLE_HIGH_DYNAMIC_RANGE) ? FFX_FRAMEINTERPOLATION_ENABLE_HDR_COLOR_INPUT : 0; + fiDescription.flags |= (desc->flags & FFX_FRAMEGENERATION_ENABLE_ASYNC_WORKLOAD_SUPPORT) ? FFX_FRAMEINTERPOLATION_ENABLE_ASYNC_SUPPORT : 0; + fiDescription.flags |= (desc->flags & FFX_FRAMEGENERATION_ENABLE_DEBUG_CHECKING) ? FFX_FRAMEINTERPOLATION_ENABLE_DEBUG_CHECKING : 0; + fiDescription.maxRenderSize.width = desc->maxRenderSize.width; + fiDescription.maxRenderSize.height = desc->maxRenderSize.height; + fiDescription.displaySize.width = desc->displaySize.width; + fiDescription.displaySize.height = desc->displaySize.height; + fiDescription.backBufferFormat = ConvertEnum(desc->backBufferFormat); + fiDescription.previousInterpolationSourceFormat = ConvertEnum(desc->backBufferFormat); + for (auto it = header; it; it = it->pNext) + { + if (auto descHudless = ffx::DynamicCast(it)) + { + fiDescription.previousInterpolationSourceFormat = ConvertEnum(descHudless->hudlessBackBufferFormat); + } + } + // set up Frameinterpolation + TRY2(ffxFrameInterpolationContextCreate(&internal_context->fiContext, &fiDescription)); + + // set up optical flow resources + FfxOpticalflowSharedResourceDescriptions ofResourceDescs = {}; + TRY2(ffxOpticalflowGetSharedResourceDescriptions(&internal_context->ofContext, &ofResourceDescs)); + + TRY2(internal_context->backendInterfaceShared.fpCreateResource(&internal_context->backendInterfaceShared, &ofResourceDescs.opticalFlowVector, internal_context->effectContextIdShared, &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_VECTOR])); + TRY2(internal_context->backendInterfaceShared.fpCreateResource(&internal_context->backendInterfaceShared, &ofResourceDescs.opticalFlowSCD, internal_context->effectContextIdShared, &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_SCD_OUTPUT])); + } + { + FfxFrameInterpolationSharedResourceDescriptions fiResourceDescs = {}; + TRY2(ffxFrameInterpolationGetSharedResourceDescriptions(&internal_context->fiContext, &fiResourceDescs)); + + internal_context->sharedResoureFrameToggle = 0; + wchar_t Name[256] = {}; + for (FfxUInt32 i = 0; i < 2; i++) + { + FfxCreateResourceDescription dilD = fiResourceDescs.dilatedDepth; + swprintf(Name, 255, L"%s%d", fiResourceDescs.dilatedDepth.name, i); + dilD.name = Name; + TRY2(internal_context->backendInterfaceShared.fpCreateResource( + &internal_context->backendInterfaceShared, + &dilD, + internal_context->effectContextIdShared, + &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_DEPTH_0 + (i * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)])); + + FfxCreateResourceDescription dilMVs = fiResourceDescs.dilatedMotionVectors; + swprintf(Name, 255, L"%s%d", fiResourceDescs.dilatedMotionVectors.name, i); + dilMVs.name = Name; + TRY2(internal_context->backendInterfaceShared.fpCreateResource( + &internal_context->backendInterfaceShared, + &dilMVs, + internal_context->effectContextIdShared, + &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS_0 + (i * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)])); + + FfxCreateResourceDescription recND = fiResourceDescs.reconstructedPrevNearestDepth; + swprintf(Name, 255, L"%s%d", fiResourceDescs.reconstructedPrevNearestDepth.name, i); + recND.name = Name; + TRY2(internal_context->backendInterfaceShared.fpCreateResource( + &internal_context->backendInterfaceShared, + &recND, + internal_context->effectContextIdShared, + &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH_0 + (i * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)])); + } + } + + *context = internal_context; + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } +} + +ffxReturnCode_t ffxProvider_FrameGeneration::DestroyContext(ffxContext* context, Allocator& alloc) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgContext* internal_context = reinterpret_cast(*context); + + { // copied from ffxFsr3ContextDestroy, simplified. + for (FfxUInt32 i = 0; i < FFX_FSR3_RESOURCE_IDENTIFIER_COUNT; i++) + { + TRY2(internal_context->backendInterfaceShared.fpDestroyResource(&internal_context->backendInterfaceShared, internal_context->sharedResources[i], internal_context->effectContextIdShared)); + } + + TRY2(ffxFrameInterpolationContextDestroy(&internal_context->fiContext)); + + TRY2(ffxOpticalflowContextDestroy(&internal_context->ofContext)); + + TRY2(internal_context->backendInterfaceShared.fpDestroyBackendContext(&internal_context->backendInterfaceShared, internal_context->effectContextIdShared)); + } + + alloc.dealloc(internal_context->backendInterfaceFi.scratchBuffer); + alloc.dealloc(internal_context->backendInterfaceShared.scratchBuffer); + alloc.dealloc(internal_context); + + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FrameGeneration::Configure(ffxContext* context, const ffxConfigureDescHeader* header) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + FfxFrameGenerationConfig config{}; + config.allowAsyncWorkloads = desc->allowAsyncWorkloads; + config.flags = desc->flags; + + size_t callbacksIndex = desc->frameID % MAX_QUEUED_FRAMES; + + bool const bPresentCallbackChanged = (internal_context->callbacks[callbacksIndex].presentCallback != desc->presentCallback) || (desc->presentCallback && (internal_context->callbacks[callbacksIndex].presentCallbackUserContext != desc->presentCallbackUserContext)); + bool const bFrameGenerationCallback = (internal_context->callbacks[callbacksIndex].frameGenerationCallback != desc->frameGenerationCallback) || (desc->frameGenerationCallback && (internal_context->callbacks[callbacksIndex].frameGenerationCallbackUserContext != desc->frameGenerationCallbackUserContext)); + internal_context->callbacks[callbacksIndex].presentCallback = desc->presentCallback; + internal_context->callbacks[callbacksIndex].frameGenerationCallback = desc->frameGenerationCallback; + internal_context->callbacks[callbacksIndex].presentCallbackUserContext = desc->presentCallbackUserContext; + internal_context->callbacks[callbacksIndex].frameGenerationCallbackUserContext = desc->frameGenerationCallbackUserContext; + + config.frameGenerationCallback = nullptr; + config.frameGenerationCallbackContext = nullptr; + if (desc->frameGenerationCallback != nullptr) + { + config.frameGenerationCallback = [](const FfxFrameGenerationDispatchDescription* desc, void* ctx) -> FfxErrorCode { + size_t callbacksIndex = desc->frameID % MAX_QUEUED_FRAMES; + InternalFgContext* internal_context = reinterpret_cast(ctx); + auto callbacks = &internal_context->callbacks[callbacksIndex]; + VERIFY(callbacks->frameGenerationCallback, FFX_ERROR_BACKEND_API_ERROR); + + ffx::DispatchDescFrameGeneration dispatchDesc{}; + + dispatchDesc.backbufferTransferFunction = desc->backBufferTransferFunction; + dispatchDesc.commandList = desc->commandList; + dispatchDesc.minMaxLuminance[0] = desc->minMaxLuminance[0]; + dispatchDesc.minMaxLuminance[1] = desc->minMaxLuminance[1]; + dispatchDesc.numGeneratedFrames = desc->numInterpolatedFrames; + dispatchDesc.outputs[0] = Convert(desc->outputs[0]); + dispatchDesc.outputs[1] = Convert(desc->outputs[1]); + dispatchDesc.outputs[2] = Convert(desc->outputs[2]); + dispatchDesc.outputs[3] = Convert(desc->outputs[3]); + dispatchDesc.presentColor = Convert(desc->presentColor); + dispatchDesc.reset = desc->reset; + dispatchDesc.generationRect.top = desc->interpolationRect.top; + dispatchDesc.generationRect.left = desc->interpolationRect.left; + dispatchDesc.generationRect.height = desc->interpolationRect.height; + dispatchDesc.generationRect.width = desc->interpolationRect.width; + dispatchDesc.frameID = desc->frameID; + + if (FFX_API_RETURN_OK != callbacks->frameGenerationCallback(&dispatchDesc, callbacks->frameGenerationCallbackUserContext)) + return FFX_ERROR_BACKEND_API_ERROR; + return FFX_OK; + }; + config.frameGenerationCallbackContext = internal_context; + } + + config.presentCallback = nullptr; + config.presentCallbackContext = nullptr; + if (desc->presentCallback != nullptr) + { + config.presentCallback = [](const FfxPresentCallbackDescription* params, void* ctx) -> FfxErrorCode { + size_t callbacksIndex = params->frameID % MAX_QUEUED_FRAMES; + InternalFgContext* internal_context = reinterpret_cast(ctx); + auto callbacks = &internal_context->callbacks[callbacksIndex]; + VERIFY(callbacks->presentCallback, FFX_ERROR_BACKEND_API_ERROR); + + ffxCallbackDescFrameGenerationPresent cbDesc{}; + cbDesc.header.pNext = nullptr; + cbDesc.header.type = FFX_API_CALLBACK_DESC_TYPE_FRAMEGENERATION_PRESENT; + + cbDesc.commandList = params->commandList; + cbDesc.currentBackBuffer = Convert(params->currentBackBuffer); + cbDesc.currentUI = Convert(params->currentUI); + cbDesc.device = params->device; + cbDesc.isGeneratedFrame = params->isInterpolatedFrame; + cbDesc.outputSwapChainBuffer = Convert(params->outputSwapChainBuffer); + cbDesc.frameID = params->frameID; + + if (FFX_API_RETURN_OK != callbacks->presentCallback(&cbDesc, callbacks->presentCallbackUserContext)) + return FFX_ERROR_BACKEND_API_ERROR; + return FFX_OK; + }; + config.presentCallbackContext = internal_context; + } + + config.drawDebugPacingLines = false; + if (desc->flags & FFX_FRAMEGENERATION_FLAG_DRAW_DEBUG_PACING_LINES) + { + config.drawDebugPacingLines = true; + } + + config.frameGenerationEnabled = desc->frameGenerationEnabled; + config.HUDLessColor = Convert(desc->HUDLessColor); + config.onlyPresentInterpolated = desc->onlyPresentGenerated; + config.swapChain = desc->swapChain; + + config.interpolationRect.top = desc->generationRect.top; + config.interpolationRect.left = desc->generationRect.left; + config.interpolationRect.width = desc->generationRect.width; + config.interpolationRect.height = desc->generationRect.height; + + config.frameID = desc->frameID; + + { // copied from ffxFsr3ConfigureFrameGeneration + internal_context->frameGenFlags = config.flags; + internal_context->HUDLessColor = config.HUDLessColor; + + if (config.flags & FFX_FRAMEGENERATION_FLAG_DRAW_DEBUG_VIEW) + { + config.onlyPresentInterpolated = true; + } + + internal_context->frameGenEnabled = config.frameGenerationEnabled; + + if (!(config.flags & FFX_FRAMEGENERATION_FLAG_NO_SWAPCHAIN_CONTEXT_NOTIFY)) + { + // When the frame ID is not incrementing by 1 we could end up overwriting a pointer that is in-use, so reset the swap-chain state + if (((internal_context->lastConfigureFrameID + 1) != desc->frameID) && (bPresentCallbackChanged || bFrameGenerationCallback)) + { + FfxFrameGenerationConfig resetConfig = config; + resetConfig.frameGenerationCallback = nullptr; + resetConfig.frameGenerationCallbackContext = nullptr; + resetConfig.presentCallback = nullptr; + resetConfig.presentCallbackContext = nullptr; + + TRY2(internal_context->backendInterfaceShared.fpSwapChainConfigureFrameGeneration(&resetConfig)); + } + + TRY2(internal_context->backendInterfaceShared.fpSwapChainConfigureFrameGeneration(&config)); + + internal_context->lastConfigureFrameID = desc->frameID; + } + } + + internal_context->distortionField = FfxResource({}); + for (auto it = header; it; it = it->pNext) + { + if (auto distortionFieldDesc = ffx::DynamicCast(it)) + { + if (distortionFieldDesc->distortionField.resource) + { + internal_context->distortionField = Convert(distortionFieldDesc->distortionField); + } + } + } + + return FFX_API_RETURN_OK; + } + if (auto desc = ffx::DynamicCast(header)) + { + TRY2(ffxFrameInterpolationSetGlobalDebugMessage( reinterpret_cast(desc->fpMessage), + desc->debugLevel)); + + // Grab this fp for use in extensions later + internal_context->fpMessage = desc->fpMessage; + internal_context->debugLevel = desc->debugLevel; + + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_PARAMETER; + } +} + +ffxReturnCode_t ffxProvider_FrameGeneration::Query(ffxContext* context, ffxQueryDescHeader* header) const +{ + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + FfxEffectMemoryUsage pGpuMemoryUsageFrameGeneration; + FfxEffectMemoryUsage pGpuMemoryUsageOpticalFlow; + FfxEffectMemoryUsage pGpuMemoryUsageShared; + + TRY2(ffxFrameInterpolationContextGetGpuMemoryUsage(&internal_context->fiContext, &pGpuMemoryUsageFrameGeneration)); + TRY2(ffxOpticalflowContextGetGpuMemoryUsage(&internal_context->ofContext, &pGpuMemoryUsageOpticalFlow)); + TRY2(ffxSharedContextGetGpuMemoryUsage(&internal_context->backendInterfaceShared, &pGpuMemoryUsageShared)); + desc->gpuMemoryUsageFrameGeneration->totalUsageInBytes = pGpuMemoryUsageFrameGeneration.totalUsageInBytes + pGpuMemoryUsageOpticalFlow.totalUsageInBytes + pGpuMemoryUsageShared.totalUsageInBytes; + desc->gpuMemoryUsageFrameGeneration->aliasableUsageInBytes = pGpuMemoryUsageFrameGeneration.aliasableUsageInBytes + pGpuMemoryUsageOpticalFlow.aliasableUsageInBytes + pGpuMemoryUsageShared.aliasableUsageInBytes; + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } +} + +ffxReturnCode_t ffxProvider_FrameGeneration::Dispatch(ffxContext* context, const ffxDispatchDescHeader* header) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + const ffxDispatchDescFrameGenerationPrepare* prepDesc = &internal_context->prepareDescriptions[desc->frameID % MAX_QUEUED_FRAMES]; + + // Optical flow + { + FfxOpticalflowDispatchDescription ofDispatchDesc{}; + ofDispatchDesc.commandList = desc->commandList; + ofDispatchDesc.color = Convert(desc->presentColor); + if (internal_context->HUDLessColor.resource) + { + ofDispatchDesc.color = internal_context->HUDLessColor; + } + ofDispatchDesc.reset = desc->reset; + ofDispatchDesc.backbufferTransferFunction = desc->backbufferTransferFunction; + ofDispatchDesc.minMaxLuminance.x = desc->minMaxLuminance[0]; + ofDispatchDesc.minMaxLuminance.y = desc->minMaxLuminance[1]; + ofDispatchDesc.opticalFlowVector = internal_context->backendInterfaceShared.fpGetResource(&internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_VECTOR]); + ofDispatchDesc.opticalFlowSCD = internal_context->backendInterfaceShared.fpGetResource(&internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_SCD_OUTPUT]); + + TRY2(ffxOpticalflowContextDispatch(&internal_context->ofContext, &ofDispatchDesc)); + } + + // Frame interpolation + { + FfxFrameInterpolationDispatchDescription fiDispatchDesc{0}; + + // don't dispatch interpolation async for now: use the same commandlist for copy and interpolate + fiDispatchDesc.commandList = desc->commandList; + fiDispatchDesc.displaySize.width = desc->presentColor.description.width; + fiDispatchDesc.displaySize.height = desc->presentColor.description.height; + fiDispatchDesc.currentBackBuffer = Convert(desc->presentColor); + fiDispatchDesc.currentBackBuffer_HUDLess = internal_context->HUDLessColor; + fiDispatchDesc.reset = desc->reset; + + fiDispatchDesc.renderSize.width = prepDesc->renderSize.width; + fiDispatchDesc.renderSize.height = prepDesc->renderSize.height; + fiDispatchDesc.output = Convert(desc->outputs[0]); + fiDispatchDesc.opticalFlowVector = internal_context->backendInterfaceShared.fpGetResource(&internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_VECTOR]); + fiDispatchDesc.opticalFlowSceneChangeDetection = internal_context->backendInterfaceShared.fpGetResource(&internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_OPTICAL_FLOW_SCD_OUTPUT]); + fiDispatchDesc.opticalFlowBlockSize = 8; + fiDispatchDesc.opticalFlowScale = { 1.f / fiDispatchDesc.displaySize.width, 1.f / fiDispatchDesc.displaySize.height }; + fiDispatchDesc.frameTimeDelta = prepDesc->frameTimeDelta; + fiDispatchDesc.cameraNear = prepDesc->cameraNear; + fiDispatchDesc.cameraFar = prepDesc->cameraFar; + fiDispatchDesc.viewSpaceToMetersFactor = prepDesc->viewSpaceToMetersFactor; + fiDispatchDesc.cameraFovAngleVertical = prepDesc->cameraFovAngleVertical; + + fiDispatchDesc.dilatedDepth = internal_context->backendInterfaceShared.fpGetResource( &internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_DEPTH_0 + (internal_context->sharedResoureFrameToggle * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)]); + fiDispatchDesc.dilatedMotionVectors = internal_context->backendInterfaceShared.fpGetResource( &internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS_0 + (internal_context->sharedResoureFrameToggle * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)]); + fiDispatchDesc.reconstructedPrevDepth = internal_context->backendInterfaceShared.fpGetResource( &internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH_0 + (internal_context->sharedResoureFrameToggle * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)]); + + if (desc->generationRect.height == 0 && desc->generationRect.width == 0) + { + fiDispatchDesc.interpolationRect.left = 0; + fiDispatchDesc.interpolationRect.top = 0; + fiDispatchDesc.interpolationRect.width = desc->presentColor.description.width; + fiDispatchDesc.interpolationRect.height = desc->presentColor.description.height; + } + else + { + fiDispatchDesc.interpolationRect.top = desc->generationRect.top; + fiDispatchDesc.interpolationRect.left = desc->generationRect.left; + fiDispatchDesc.interpolationRect.width = desc->generationRect.width; + fiDispatchDesc.interpolationRect.height = desc->generationRect.height; + } + + if (internal_context->frameGenFlags & FFX_FRAMEGENERATION_FLAG_DRAW_DEBUG_TEAR_LINES) + { + fiDispatchDesc.flags |= FFX_FRAMEINTERPOLATION_DISPATCH_DRAW_DEBUG_TEAR_LINES; + } + + + if (internal_context->frameGenFlags & FFX_FRAMEGENERATION_FLAG_DRAW_DEBUG_RESET_INDICATORS) + { + fiDispatchDesc.flags |= FFX_FRAMEINTERPOLATION_DISPATCH_DRAW_DEBUG_RESET_INDICATORS; + } + + if (internal_context->frameGenFlags & FFX_FRAMEGENERATION_FLAG_DRAW_DEBUG_VIEW) + { + fiDispatchDesc.flags |= FFX_FRAMEINTERPOLATION_DISPATCH_DRAW_DEBUG_VIEW; + } + + if (internal_context->frameGenFlags & FFX_FRAMEGENERATION_FLAG_RESERVED_1) + { + fiDispatchDesc.flags |= FFX_FRAMEINTERPOLATION_DISPATCH_RESERVED_1; + } + + if (internal_context->frameGenFlags & FFX_FRAMEGENERATION_FLAG_RESERVED_2) + { + fiDispatchDesc.flags |= FFX_FRAMEINTERPOLATION_DISPATCH_RESERVED_2; + } + + fiDispatchDesc.backBufferTransferFunction = ConvertEnum(desc->backbufferTransferFunction); + fiDispatchDesc.minMaxLuminance[0] = desc->minMaxLuminance[0]; + fiDispatchDesc.minMaxLuminance[1] = desc->minMaxLuminance[1]; + + fiDispatchDesc.frameID = desc->frameID; + + if (internal_context->distortionField.resource) + { + fiDispatchDesc.distortionField = internal_context->distortionField; + } + TRY2(ffxFrameInterpolationDispatch(&internal_context->fiContext, &fiDispatchDesc)); + } + + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + internal_context->prepareDescriptions[desc->frameID % MAX_QUEUED_FRAMES] = *desc; + + internal_context->sharedResoureFrameToggle = (internal_context->sharedResoureFrameToggle + 1) & 1; + + FfxFrameInterpolationPrepareDescription dispatchDesc{0}; + dispatchDesc.flags = desc->flags; // TODO: flag conversion? + dispatchDesc.commandList = desc->commandList; + dispatchDesc.renderSize.width = desc->renderSize.width; + dispatchDesc.renderSize.height = desc->renderSize.height; + dispatchDesc.jitterOffset.x = desc->jitterOffset.x; + dispatchDesc.jitterOffset.y = desc->jitterOffset.y; + dispatchDesc.motionVectorScale.x = desc->motionVectorScale.x; + dispatchDesc.motionVectorScale.y = desc->motionVectorScale.y; + dispatchDesc.frameTimeDelta = desc->frameTimeDelta; + dispatchDesc.cameraNear = desc->cameraNear; + dispatchDesc.cameraFar = desc->cameraFar; + dispatchDesc.viewSpaceToMetersFactor = desc->viewSpaceToMetersFactor; + dispatchDesc.cameraFovAngleVertical = desc->cameraFovAngleVertical; + dispatchDesc.depth = Convert(desc->depth); + dispatchDesc.motionVectors = Convert(desc->motionVectors); + dispatchDesc.frameID = desc->frameID; + + dispatchDesc.dilatedDepth = internal_context->backendInterfaceShared.fpGetResource( &internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_DEPTH_0 + (internal_context->sharedResoureFrameToggle * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)]); + dispatchDesc.dilatedMotionVectors = internal_context->backendInterfaceShared.fpGetResource( &internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS_0 + (internal_context->sharedResoureFrameToggle * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)]); + dispatchDesc.reconstructedPrevDepth = internal_context->backendInterfaceShared.fpGetResource( &internal_context->backendInterfaceShared, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH_0 + (internal_context->sharedResoureFrameToggle * FFX_FSR3_RESOURCE_IDENTIFIER_UPSCALED_COUNT)]); + + for (auto it = header; it; it = it->pNext) + { + if (auto cameraInfoDesc = ffx::DynamicCast(it)) + { + memcpy(dispatchDesc.cameraPosition, &cameraInfoDesc->cameraPosition, sizeof(FfxFloat32x3)); + memcpy(dispatchDesc.cameraUp, &cameraInfoDesc->cameraUp, sizeof(FfxFloat32x3)); + memcpy(dispatchDesc.cameraRight, &cameraInfoDesc->cameraRight, sizeof(FfxFloat32x3)); + memcpy(dispatchDesc.cameraForward, &cameraInfoDesc->cameraForward, sizeof(FfxFloat32x3)); + } + } + + TRY2(ffxFrameInterpolationPrepare(&internal_context->fiContext, &dispatchDesc)); + + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_PARAMETER; + } +} + +ffxProvider_FrameGeneration ffxProvider_FrameGeneration::Instance; diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider_framegeneration.h b/Kits/AMDTK/ffx-api/src/ffx_provider_framegeneration.h new file mode 100644 index 00000000..c02514f9 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider_framegeneration.h @@ -0,0 +1,49 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#include "ffx_provider.h" + +class ffxProvider_FrameGeneration: public ffxProvider +{ +public: + ffxProvider_FrameGeneration() = default; + virtual ~ffxProvider_FrameGeneration() = default; + + virtual bool CanProvide(uint64_t type) const override; + + virtual uint64_t GetId() const override; + + virtual const char* GetVersionName() const override; + + virtual ffxReturnCode_t CreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, Allocator& alloc) const override; + + virtual ffxReturnCode_t DestroyContext(ffxContext* context, Allocator& alloc) const override; + + virtual ffxReturnCode_t Configure(ffxContext* context, const ffxConfigureDescHeader* desc) const override; + + virtual ffxReturnCode_t Query(ffxContext* context, ffxQueryDescHeader* desc) const override; + + virtual ffxReturnCode_t Dispatch(ffxContext* context, const ffxDispatchDescHeader* desc) const override; + + static ffxProvider_FrameGeneration Instance; +}; diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider_fsr2.cpp b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr2.cpp new file mode 100644 index 00000000..1c9e5514 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr2.cpp @@ -0,0 +1,317 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_provider_fsr2.h" +#include "backends.h" +#include +#include + +#include + +static FfxFsr2QualityMode ConvertQuality(uint32_t apiMode) +{ + switch (apiMode) + { + case FFX_UPSCALE_QUALITY_MODE_QUALITY: + return FFX_FSR2_QUALITY_MODE_QUALITY; + case FFX_UPSCALE_QUALITY_MODE_BALANCED: + return FFX_FSR2_QUALITY_MODE_BALANCED; + case FFX_UPSCALE_QUALITY_MODE_PERFORMANCE: + return FFX_FSR2_QUALITY_MODE_PERFORMANCE; + case FFX_UPSCALE_QUALITY_MODE_ULTRA_PERFORMANCE: + return FFX_FSR2_QUALITY_MODE_ULTRA_PERFORMANCE; + default: + // convert representation through int. + return (FfxFsr2QualityMode)(int)apiMode; + } +} + +static uint32_t ConvertFlags(uint32_t apiFlags) +{ + uint32_t outFlags = 0; + if (apiFlags & FFX_UPSCALE_ENABLE_HIGH_DYNAMIC_RANGE) + outFlags |= FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE; + if (apiFlags & FFX_UPSCALE_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) + outFlags |= FFX_FSR2_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS; + if (apiFlags & FFX_UPSCALE_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION) + outFlags |= FFX_FSR2_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION; + if (apiFlags & FFX_UPSCALE_ENABLE_DEPTH_INVERTED) + outFlags |= FFX_FSR2_ENABLE_DEPTH_INVERTED; + if (apiFlags & FFX_UPSCALE_ENABLE_DEPTH_INFINITE) + outFlags |= FFX_FSR2_ENABLE_DEPTH_INFINITE; + if (apiFlags & FFX_UPSCALE_ENABLE_AUTO_EXPOSURE) + outFlags |= FFX_FSR2_ENABLE_AUTO_EXPOSURE; + if (apiFlags & FFX_UPSCALE_ENABLE_DYNAMIC_RESOLUTION) + outFlags |= FFX_FSR2_ENABLE_DYNAMIC_RESOLUTION; + if (apiFlags & FFX_UPSCALE_ENABLE_DEBUG_CHECKING) + outFlags |= FFX_FSR2_ENABLE_DEBUG_CHECKING; + return outFlags; +} + +bool ffxProvider_FSR2::CanProvide(uint64_t type) const +{ + return (type & FFX_API_EFFECT_MASK) == FFX_API_EFFECT_ID_UPSCALE; +} + +#define STRINGIFY_(X) #X +#define STRINGIFY(X) STRINGIFY_(X) +#define MAKE_VERSION_STRING(major, minor, patch) STRINGIFY major "." STRINGIFY minor "." STRINGIFY patch + +uint64_t ffxProvider_FSR2::GetId() const +{ + // FSR Scale, version from header + return 0xF5A5'CA1Eui64 << 32 | (FFX_SDK_MAKE_VERSION(FFX_FSR2_VERSION_MAJOR, FFX_FSR2_VERSION_MINOR, FFX_FSR2_VERSION_PATCH) & 0xFFFF'FFFF); +} + +const char* ffxProvider_FSR2::GetVersionName() const +{ + return MAKE_VERSION_STRING(FFX_FSR2_VERSION_MAJOR, FFX_FSR2_VERSION_MINOR, FFX_FSR2_VERSION_PATCH); +} + +struct InternalFsr2Context +{ + InternalContextHeader header; + FfxInterface backendInterface; + FfxFsr2Context context; + ffxApiMessage fpMessage; + uint32_t debugLevel; +}; + +ffxReturnCode_t ffxProvider_FSR2::CreateContext(ffxContext* context, ffxCreateContextDescHeader* header, Allocator& alloc) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + + if (auto desc = ffx::DynamicCast(header)) + { + InternalFsr2Context* internal_context = alloc.construct(); + VERIFY(internal_context, FFX_API_RETURN_ERROR_MEMORY); + internal_context->header.provider = this; + + TRY(MustCreateBackend(header, &internal_context->backendInterface, FFX_FSR2_CONTEXT_COUNT, alloc)); + + FfxFsr2ContextDescription initializationParameters = {0}; + initializationParameters.backendInterface = internal_context->backendInterface; + initializationParameters.maxRenderSize.width = desc->maxRenderSize.width; + initializationParameters.maxRenderSize.height = desc->maxRenderSize.height; + initializationParameters.displaySize.width = desc->maxUpscaleSize.width; + initializationParameters.displaySize.height = desc->maxUpscaleSize.height; + initializationParameters.flags = ConvertFlags(desc->flags); + // Calling this casted function is undefined behaviour, but it's probably safe. + initializationParameters.fpMessage = reinterpret_cast(desc->fpMessage); + + // Grab this fp for use in extensions later + internal_context->fpMessage = desc->fpMessage; + + // Create the FSR2 context + TRY(ffxFsr2ContextCreate(&internal_context->context, &initializationParameters)); + + ffxFsr2SetGlobalDebugMessage(reinterpret_cast(desc->fpMessage), 0); + + *context = internal_context; + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } +} + +ffxReturnCode_t ffxProvider_FSR2::DestroyContext(ffxContext* context, Allocator& alloc) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFsr2Context* internal_context = reinterpret_cast(*context); + + TRY2(ffxFsr2ContextDestroy(&internal_context->context)); + + alloc.dealloc(internal_context->backendInterface.scratchBuffer); + alloc.dealloc(internal_context); + + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FSR2::Configure(ffxContext* context, const ffxConfigureDescHeader* header) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + InternalFsr2Context* internal_context = reinterpret_cast(*context); + switch (header->type) + { + case FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1: + { + auto desc = reinterpret_cast(header); + TRY2(ffxFsr2SetGlobalDebugMessage( reinterpret_cast(desc->fpMessage), desc->debugLevel)); + internal_context->fpMessage = desc->fpMessage; + internal_context->debugLevel = desc->debugLevel; + } + break; + } + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FSR2::Query(ffxContext* context, ffxQueryDescHeader* header) const +{ + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + + switch (header->type) + { + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTEROFFSET: + { + auto desc = reinterpret_cast(header); + float jitterX, jitterY; + TRY2(ffxFsr2GetJitterOffset(&jitterX, &jitterY, desc->index, desc->phaseCount)); + if (desc->pOutX != nullptr) + { + *desc->pOutX = jitterX; + } + if (desc->pOutY != nullptr) + { + *desc->pOutY = jitterY; + } + break; + } + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTERPHASECOUNT: + { + auto desc = reinterpret_cast(header); + const int32_t jitterPhaseCount = ffxFsr2GetJitterPhaseCount(desc->renderWidth, desc->displayWidth); + + if (desc->pOutPhaseCount != nullptr) + { + *desc->pOutPhaseCount = jitterPhaseCount; + } + break; + } + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETRENDERRESOLUTIONFROMQUALITYMODE: + { + auto desc = reinterpret_cast(header); + uint32_t renderWidth; + uint32_t renderHeight; + + TRY2(ffxFsr2GetRenderResolutionFromQualityMode(&renderWidth, &renderHeight, desc->displayWidth, desc->displayHeight, ConvertQuality(desc->qualityMode))); + if (desc->pOutRenderWidth != nullptr) + { + *desc->pOutRenderWidth = renderWidth; + } + if (desc->pOutRenderHeight != nullptr) + { + *desc->pOutRenderHeight = renderHeight; + } + break; + } + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETUPSCALERATIOFROMQUALITYMODE: + { + auto desc = reinterpret_cast(header); + float ratio = ffxFsr2GetUpscaleRatioFromQualityMode(ConvertQuality(desc->qualityMode)); + + if (desc->pOutUpscaleRatio != nullptr) + { + *desc->pOutUpscaleRatio = ratio; + } + break; + } + default: + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } + + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FSR2::Dispatch(ffxContext* context, const ffxDispatchDescHeader* header) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFsr2Context* internal_context = (InternalFsr2Context*)context[0]; + + ffxDispatchDescHeader* descExt = header->pNext; + + switch (header->type) + { + case FFX_API_DISPATCH_DESC_TYPE_UPSCALE: + { + auto desc = reinterpret_cast(header); + + FfxFsr2DispatchDescription dispatchParameters = {}; + dispatchParameters.commandList = desc->commandList; + dispatchParameters.color = Convert(desc->color); + dispatchParameters.depth = Convert(desc->depth); + dispatchParameters.motionVectors = Convert(desc->motionVectors); + dispatchParameters.exposure = Convert(desc->exposure); + dispatchParameters.output = Convert(desc->output); + dispatchParameters.reactive = Convert(desc->reactive); + dispatchParameters.transparencyAndComposition = Convert(desc->transparencyAndComposition); + dispatchParameters.jitterOffset.x = desc->jitterOffset.x; + dispatchParameters.jitterOffset.y = desc->jitterOffset.y; + dispatchParameters.motionVectorScale.x = desc->motionVectorScale.x; + dispatchParameters.motionVectorScale.y = desc->motionVectorScale.y; + dispatchParameters.reset = desc->reset; + dispatchParameters.enableSharpening = desc->enableSharpening; + dispatchParameters.sharpness = desc->sharpness; + dispatchParameters.frameTimeDelta = desc->frameTimeDelta; + dispatchParameters.preExposure = desc->preExposure; + dispatchParameters.renderSize.width = desc->renderSize.width; + dispatchParameters.renderSize.height = desc->renderSize.height; + dispatchParameters.cameraFovAngleVertical = desc->cameraFovAngleVertical; + dispatchParameters.cameraFar = desc->cameraFar; + dispatchParameters.cameraNear = desc->cameraNear; + dispatchParameters.viewSpaceToMetersFactor = desc->viewSpaceToMetersFactor; + + // Check for and process extensions + //if (descExt != nullptr) + //{ + // TRY(ProcessExtensionsPreDispatch(internal_context, &dispatchParameters, &descExt)); + //} + + TRY2(ffxFsr2ContextDispatch(&internal_context->context, &dispatchParameters)); + break; + } + case FFX_API_DISPATCH_DESC_TYPE_UPSCALE_GENERATEREACTIVEMASK: + { + auto desc = reinterpret_cast(header); + + FfxFsr2GenerateReactiveDescription dispatchParameters = {}; + dispatchParameters.commandList = desc->commandList; + dispatchParameters.colorOpaqueOnly = Convert(desc->colorOpaqueOnly); + dispatchParameters.colorPreUpscale = Convert(desc->colorPreUpscale); + dispatchParameters.outReactive = Convert(desc->outReactive); + dispatchParameters.renderSize.width = desc->renderSize.width; + dispatchParameters.renderSize.height = desc->renderSize.height; + dispatchParameters.scale = desc->scale; + dispatchParameters.cutoffThreshold = desc->cutoffThreshold; + dispatchParameters.binaryValue = desc->binaryValue; + dispatchParameters.flags = desc->flags; + + TRY2(ffxFsr2ContextGenerateReactiveMask(&internal_context->context, &dispatchParameters)); + break; + } + default: + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } + + return FFX_API_RETURN_OK; +} + +ffxProvider_FSR2 ffxProvider_FSR2::Instance; diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider_fsr2.h b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr2.h new file mode 100644 index 00000000..6a60827a --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr2.h @@ -0,0 +1,50 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#include "ffx_provider.h" + +class ffxProvider_FSR2: public ffxProvider +{ +public: + ffxProvider_FSR2() = default; + virtual ~ffxProvider_FSR2() = default; + + virtual bool CanProvide(uint64_t type) const override; + + virtual uint64_t GetId() const override; + + virtual const char* GetVersionName() const override; + + virtual ffxReturnCode_t CreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, Allocator& alloc) const override; + + virtual ffxReturnCode_t DestroyContext(ffxContext* context, Allocator& alloc) const override; + + virtual ffxReturnCode_t Configure(ffxContext* context, const ffxConfigureDescHeader* desc) const override; + + virtual ffxReturnCode_t Query(ffxContext* context, ffxQueryDescHeader* desc) const override; + + virtual ffxReturnCode_t Dispatch(ffxContext* context, const ffxDispatchDescHeader* desc) const override; + + static ffxProvider_FSR2 Instance; + +}; diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider_fsr3upscale.cpp b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr3upscale.cpp new file mode 100644 index 00000000..c1e140c2 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr3upscale.cpp @@ -0,0 +1,388 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_provider_fsr3upscale.h" +#include "backends.h" +#include "validation.h" +#include +#ifdef FFX_BACKEND_DX12 +#include +#endif // FFX_BACKEND_DX12 +#ifdef FFX_BACKEND_VK +#include +#endif // #ifdef FFX_BACKEND_VK +#include +#include + +#include + +static uint32_t ConvertFlags(uint32_t apiFlags) +{ + uint32_t outFlags = 0; + if (apiFlags & FFX_UPSCALE_ENABLE_HIGH_DYNAMIC_RANGE) + outFlags |= FFX_FSR3UPSCALER_ENABLE_HIGH_DYNAMIC_RANGE; + if (apiFlags & FFX_UPSCALE_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS) + outFlags |= FFX_FSR3UPSCALER_ENABLE_DISPLAY_RESOLUTION_MOTION_VECTORS; + if (apiFlags & FFX_UPSCALE_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION) + outFlags |= FFX_FSR3UPSCALER_ENABLE_MOTION_VECTORS_JITTER_CANCELLATION; + if (apiFlags & FFX_UPSCALE_ENABLE_DEPTH_INVERTED) + outFlags |= FFX_FSR3UPSCALER_ENABLE_DEPTH_INVERTED; + if (apiFlags & FFX_UPSCALE_ENABLE_DEPTH_INFINITE) + outFlags |= FFX_FSR3UPSCALER_ENABLE_DEPTH_INFINITE; + if (apiFlags & FFX_UPSCALE_ENABLE_AUTO_EXPOSURE) + outFlags |= FFX_FSR3UPSCALER_ENABLE_AUTO_EXPOSURE; + if (apiFlags & FFX_UPSCALE_ENABLE_DYNAMIC_RESOLUTION) + outFlags |= FFX_FSR3UPSCALER_ENABLE_DYNAMIC_RESOLUTION; + if (apiFlags & FFX_UPSCALE_ENABLE_DEBUG_CHECKING) + outFlags |= FFX_FSR3UPSCALER_ENABLE_DEBUG_CHECKING; + return outFlags; +} + +bool ffxProvider_FSR3Upscale::CanProvide(uint64_t type) const +{ + return (type & FFX_API_EFFECT_MASK) == FFX_API_EFFECT_ID_UPSCALE; +} + +#define STRINGIFY_(X) #X +#define STRINGIFY(X) STRINGIFY_(X) +#define MAKE_VERSION_STRING(major, minor, patch) STRINGIFY major "." STRINGIFY minor "." STRINGIFY patch + +uint64_t ffxProvider_FSR3Upscale::GetId() const +{ + // FSR Scale, version from header + return 0xF5A5'CA1Eui64 << 32 | (FFX_SDK_MAKE_VERSION(FFX_FSR3UPSCALER_VERSION_MAJOR, FFX_FSR3UPSCALER_VERSION_MINOR, FFX_FSR3UPSCALER_VERSION_PATCH) & 0xFFFF'FFFF); +} + +const char* ffxProvider_FSR3Upscale::GetVersionName() const +{ + return MAKE_VERSION_STRING(FFX_FSR3UPSCALER_VERSION_MAJOR, FFX_FSR3UPSCALER_VERSION_MINOR, FFX_FSR3UPSCALER_VERSION_PATCH); +} + +struct InternalFsr3UpscalerUContext +{ + InternalContextHeader header; + FfxInterface backendInterface; + FfxResourceInternal sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_COUNT]; + FfxFsr3UpscalerContext context; + ffxApiMessage fpMessage; + uint32_t debugLevel; +}; + +ffxReturnCode_t ffxProvider_FSR3Upscale::CreateContext(ffxContext* context, ffxCreateContextDescHeader* header, Allocator& alloc) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + + if (auto desc = ffx::DynamicCast(header)) + { + if (desc->fpMessage) + { +#ifdef FFX_BACKEND_DX12 + Validator{desc->fpMessage, header}.AcceptExtensions({FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12, FFX_API_DESC_TYPE_OVERRIDE_VERSION}); +#elif FFX_BACKEND_VK + Validator{ desc->fpMessage, header }.AcceptExtensions({ FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK, FFX_API_DESC_TYPE_OVERRIDE_VERSION }); +#endif // FFX_BACKEND_DX12 + } + InternalFsr3UpscalerUContext* internal_context = alloc.construct(); + VERIFY(internal_context, FFX_API_RETURN_ERROR_MEMORY); + internal_context->header.provider = this; + + TRY(MustCreateBackend(header, &internal_context->backendInterface, 1, alloc)); + + FfxFsr3UpscalerContextDescription initializationParameters = {0}; + initializationParameters.backendInterface = internal_context->backendInterface; + initializationParameters.maxRenderSize.width = desc->maxRenderSize.width; + initializationParameters.maxRenderSize.height = desc->maxRenderSize.height; + initializationParameters.maxUpscaleSize.width = desc->maxUpscaleSize.width; + initializationParameters.maxUpscaleSize.height = desc->maxUpscaleSize.height; + initializationParameters.flags = ConvertFlags(desc->flags); + // Calling this casted function is undefined behaviour, but it's probably safe. + initializationParameters.fpMessage = reinterpret_cast(desc->fpMessage); + + // Grab this fp for use in extensions later + internal_context->fpMessage = desc->fpMessage; + + // Create the FSR3UPSCALER context + TRY2(ffxFsr3UpscalerContextCreate(&internal_context->context, &initializationParameters)); + + ffxFsr3UpscalerSetGlobalDebugMessage(reinterpret_cast(desc->fpMessage), 0); + + // set up FSR3Upscaler "shared" resources (no resource sharing in the upscaler provider though, since providers are fully independent and we can't guarantee all upscale providers will be compatible with other effects) + { + FfxFsr3UpscalerSharedResourceDescriptions fs3UpscalerResourceDescs = {}; + TRY2(ffxFsr3UpscalerGetSharedResourceDescriptions(&internal_context->context, &fs3UpscalerResourceDescs)); + + { + FfxCreateResourceDescription dilD = fs3UpscalerResourceDescs.dilatedDepth; + dilD.name = fs3UpscalerResourceDescs.dilatedDepth.name; + TRY2(internal_context->backendInterface.fpCreateResource( + &internal_context->backendInterface, + &dilD, + 0, + &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_DEPTH_0])); + + FfxCreateResourceDescription dilMVs = fs3UpscalerResourceDescs.dilatedMotionVectors; + dilD.name = fs3UpscalerResourceDescs.dilatedMotionVectors.name; + TRY2(internal_context->backendInterface.fpCreateResource( + &internal_context->backendInterface, + &dilMVs, + 0, + &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS_0])); + + FfxCreateResourceDescription recND = fs3UpscalerResourceDescs.reconstructedPrevNearestDepth; + recND.name = fs3UpscalerResourceDescs.reconstructedPrevNearestDepth.name; + TRY2(internal_context->backendInterface.fpCreateResource( + &internal_context->backendInterface, + &recND, + 0, + &internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH_0])); + } + } + + *context = internal_context; + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } +} + +ffxReturnCode_t ffxProvider_FSR3Upscale::DestroyContext(ffxContext* context, Allocator& alloc) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFsr3UpscalerUContext* internal_context = reinterpret_cast(*context); + + for (FfxUInt32 i = 0; i < FFX_FSR3_RESOURCE_IDENTIFIER_COUNT; i++) + { + TRY2(internal_context->backendInterface.fpDestroyResource( + &internal_context->backendInterface, internal_context->sharedResources[i], 0)); + } + + TRY2(ffxFsr3UpscalerContextDestroy(&internal_context->context)); + + alloc.dealloc(internal_context->backendInterface.scratchBuffer); + alloc.dealloc(internal_context); + + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FSR3Upscale::Configure(ffxContext* context, const ffxConfigureDescHeader* header) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + InternalFsr3UpscalerUContext* internal_context = reinterpret_cast(*context); + switch (header->type) + { + case FFX_API_CONFIGURE_DESC_TYPE_UPSCALE_KEYVALUE: + { + auto desc = reinterpret_cast(header); + TRY2(ffxFsr3UpscalerSetConstant(&internal_context->context, static_cast(desc->key), desc->ptr)); + break; + } + case FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1: + { + auto desc = reinterpret_cast(header); + TRY2(ffxFsr3UpscalerSetGlobalDebugMessage( reinterpret_cast(desc->fpMessage), + desc->debugLevel)); + internal_context->fpMessage = desc->fpMessage; + internal_context->debugLevel = desc->debugLevel; + break; + } + default: + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FSR3Upscale::Query(ffxContext* context, ffxQueryDescHeader* header) const +{ + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + + if (context) + { + InternalFsr3UpscalerUContext* internal_context = reinterpret_cast(*context); + if (internal_context->fpMessage) + { + Validator{internal_context->fpMessage, header}.NoExtensions(); + } + } + + switch (header->type) + { + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTEROFFSET: + { + auto desc = reinterpret_cast(header); + float jitterX, jitterY; + TRY2(ffxFsr3UpscalerGetJitterOffset(&jitterX, &jitterY, desc->index, desc->phaseCount)); + if (desc->pOutX != nullptr) + { + *desc->pOutX = jitterX; + } + if (desc->pOutY != nullptr) + { + *desc->pOutY = jitterY; + } + break; + } + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTERPHASECOUNT: + { + auto desc = reinterpret_cast(header); + const int32_t jitterPhaseCount = ffxFsr3UpscalerGetJitterPhaseCount(desc->renderWidth, desc->displayWidth); + + if (desc->pOutPhaseCount != nullptr) + { + *desc->pOutPhaseCount = jitterPhaseCount; + } + break; + } + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETRENDERRESOLUTIONFROMQUALITYMODE: + { + auto desc = reinterpret_cast(header); + uint32_t renderWidth; + uint32_t renderHeight; + + TRY2(ffxFsr3UpscalerGetRenderResolutionFromQualityMode(&renderWidth, &renderHeight, desc->displayWidth, desc->displayHeight, ConvertEnum(desc->qualityMode))); + if (desc->pOutRenderWidth != nullptr) + { + *desc->pOutRenderWidth = renderWidth; + } + if (desc->pOutRenderHeight != nullptr) + { + *desc->pOutRenderHeight = renderHeight; + } + break; + } + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GETUPSCALERATIOFROMQUALITYMODE: + { + auto desc = reinterpret_cast(header); + float ratio = ffxFsr3UpscalerGetUpscaleRatioFromQualityMode(ConvertEnum(desc->qualityMode)); + + if (desc->pOutUpscaleRatio != nullptr) + { + *desc->pOutUpscaleRatio = ratio; + } + break; + } + case FFX_API_QUERY_DESC_TYPE_UPSCALE_GPU_MEMORY_USAGE: + { + InternalFsr3UpscalerUContext* internal_context = reinterpret_cast(*context); + auto desc = reinterpret_cast(header); + + TRY2(ffxFsr3UpscalerContextGetGpuMemoryUsage(&internal_context->context, reinterpret_cast (desc->gpuMemoryUsageUpscaler))); + break; + } + default: + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } + + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FSR3Upscale::Dispatch(ffxContext* context, const ffxDispatchDescHeader* header) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFsr3UpscalerUContext* internal_context = reinterpret_cast(*context); + if (internal_context->fpMessage) + { + Validator{internal_context->fpMessage, header}.NoExtensions(); + } + + switch (header->type) + { + case FFX_API_DISPATCH_DESC_TYPE_UPSCALE: + { + auto desc = reinterpret_cast(header); + + FfxFsr3UpscalerDispatchDescription dispatchParameters = {}; + dispatchParameters.commandList = desc->commandList; + dispatchParameters.color = Convert(desc->color); + dispatchParameters.depth = Convert(desc->depth); + dispatchParameters.motionVectors = Convert(desc->motionVectors); + dispatchParameters.exposure = Convert(desc->exposure); + dispatchParameters.output = Convert(desc->output); + dispatchParameters.reactive = Convert(desc->reactive); + dispatchParameters.transparencyAndComposition = Convert(desc->transparencyAndComposition); + dispatchParameters.jitterOffset.x = desc->jitterOffset.x; + dispatchParameters.jitterOffset.y = desc->jitterOffset.y; + dispatchParameters.motionVectorScale.x = desc->motionVectorScale.x; + dispatchParameters.motionVectorScale.y = desc->motionVectorScale.y; + dispatchParameters.reset = desc->reset; + dispatchParameters.enableSharpening = desc->enableSharpening; + dispatchParameters.sharpness = desc->sharpness; + dispatchParameters.frameTimeDelta = desc->frameTimeDelta; + dispatchParameters.preExposure = desc->preExposure; + dispatchParameters.renderSize.width = desc->renderSize.width; + dispatchParameters.renderSize.height = desc->renderSize.height; + dispatchParameters.upscaleSize.width = desc->upscaleSize.width; + dispatchParameters.upscaleSize.height = desc->upscaleSize.height; + dispatchParameters.cameraFovAngleVertical = desc->cameraFovAngleVertical; + dispatchParameters.cameraFar = desc->cameraFar; + dispatchParameters.cameraNear = desc->cameraNear; + dispatchParameters.viewSpaceToMetersFactor = desc->viewSpaceToMetersFactor; + dispatchParameters.flags = 0; + + dispatchParameters.dilatedDepth = internal_context->backendInterface.fpGetResource( &internal_context->backendInterface, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_DEPTH_0]); + dispatchParameters.dilatedMotionVectors = internal_context->backendInterface.fpGetResource( &internal_context->backendInterface, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_DILATED_MOTION_VECTORS_0]); + dispatchParameters.reconstructedPrevNearestDepth = internal_context->backendInterface.fpGetResource( &internal_context->backendInterface, internal_context->sharedResources[FFX_FSR3_RESOURCE_IDENTIFIER_RECONSTRUCTED_PREVIOUS_NEAREST_DEPTH_0]); + + if (desc->flags & FFX_UPSCALE_FLAG_DRAW_DEBUG_VIEW) + { + dispatchParameters.flags |= FFX_FSR3UPSCALER_DISPATCH_DRAW_DEBUG_VIEW; + } + + TRY2(ffxFsr3UpscalerContextDispatch(&internal_context->context, &dispatchParameters)); + break; + } + case FFX_API_DISPATCH_DESC_TYPE_UPSCALE_GENERATEREACTIVEMASK: + { + auto desc = reinterpret_cast(header); + + FfxFsr3UpscalerGenerateReactiveDescription dispatchParameters = {}; + dispatchParameters.commandList = desc->commandList; + dispatchParameters.colorOpaqueOnly = Convert(desc->colorOpaqueOnly); + dispatchParameters.colorPreUpscale = Convert(desc->colorPreUpscale); + dispatchParameters.outReactive = Convert(desc->outReactive); + dispatchParameters.renderSize.width = desc->renderSize.width; + dispatchParameters.renderSize.height = desc->renderSize.height; + dispatchParameters.scale = desc->scale; + dispatchParameters.cutoffThreshold = desc->cutoffThreshold; + dispatchParameters.binaryValue = desc->binaryValue; + dispatchParameters.flags = desc->flags; + + TRY2(ffxFsr3UpscalerContextGenerateReactiveMask(&internal_context->context, &dispatchParameters)); + break; + } + default: + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } + + return FFX_API_RETURN_OK; +} + +ffxProvider_FSR3Upscale ffxProvider_FSR3Upscale::Instance; diff --git a/Kits/AMDTK/ffx-api/src/ffx_provider_fsr3upscale.h b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr3upscale.h new file mode 100644 index 00000000..14bce1b2 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/ffx_provider_fsr3upscale.h @@ -0,0 +1,50 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#include "ffx_provider.h" + +class ffxProvider_FSR3Upscale: public ffxProvider +{ +public: + ffxProvider_FSR3Upscale() = default; + virtual ~ffxProvider_FSR3Upscale() = default; + + virtual bool CanProvide(uint64_t type) const override; + + virtual uint64_t GetId() const override; + + virtual const char* GetVersionName() const override; + + virtual ffxReturnCode_t CreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, Allocator& alloc) const override; + + virtual ffxReturnCode_t DestroyContext(ffxContext* context, Allocator& alloc) const override; + + virtual ffxReturnCode_t Configure(ffxContext* context, const ffxConfigureDescHeader* desc) const override; + + virtual ffxReturnCode_t Query(ffxContext* context, ffxQueryDescHeader* desc) const override; + + virtual ffxReturnCode_t Dispatch(ffxContext* context, const ffxDispatchDescHeader* desc) const override; + + static ffxProvider_FSR3Upscale Instance; + +}; diff --git a/Kits/AMDTK/ffx-api/src/resource/ffx_api_dll.rc b/Kits/AMDTK/ffx-api/src/resource/ffx_api_dll.rc new file mode 100644 index 00000000..81c0df6d Binary files /dev/null and b/Kits/AMDTK/ffx-api/src/resource/ffx_api_dll.rc differ diff --git a/Kits/AMDTK/ffx-api/src/resource/resource.h b/Kits/AMDTK/ffx-api/src/resource/resource.h new file mode 100644 index 00000000..e330b3f3 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/resource/resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by ffx_api_dll.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/Kits/AMDTK/ffx-api/src/validation.cpp b/Kits/AMDTK/ffx-api/src/validation.cpp new file mode 100644 index 00000000..6c638be2 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/validation.cpp @@ -0,0 +1,146 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "validation.h" + +#ifdef FFX_BACKEND_DX12 +#include +#endif // FFX_BACKEND_DX12 +#ifdef FFX_BACKEND_VK +#include +#endif // #ifdef FFX_BACKEND_VK + +#include +#include + +#include +#include +#include + +#define MAP_ENUM_NAME(_value) {_value, #_value} + +#ifdef FFXAPI_VALIDATION + +static std::unordered_map EnumNameMap{ +#ifdef FFX_BACKEND_DX12 + MAP_ENUM_NAME(FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATION), + MAP_ENUM_NAME(FFX_API_CONFIGURE_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_REGISTERUIRESOURCE_DX12), + MAP_ENUM_NAME(FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_DX12), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATION), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_DX12), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_UPSCALE), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_GET_VERSIONS), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_INTERPOLATIONCOMMANDLIST_DX12), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FRAMEGENERATIONSWAPCHAIN_INTERPOLATIONTEXTURE_DX12), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTEROFFSET), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_UPSCALE_GETJITTERPHASECOUNT), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_UPSCALE_GETRENDERRESOLUTIONFROMQUALITYMODE), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_UPSCALE_GETUPSCALERATIOFROMQUALITYMODE), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_FRAMEGENERATION_PREPARE), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_UPSCALE_GENERATEREACTIVEMASK), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_UPSCALE), + MAP_ENUM_NAME(FFX_API_CONFIGURE_DESC_TYPE_UPSCALE_KEYVALUE), +#elif FFX_BACKEND_VK + MAP_ENUM_NAME(FFX_API_CONFIGURE_DESC_TYPE_FG), + MAP_ENUM_NAME(FFX_API_CONFIGURE_DESC_TYPE_FGSWAPCHAIN_REGISTERUIRESOURCE_VK), + MAP_ENUM_NAME(FFX_API_CONFIGURE_DESC_TYPE_GLOBALDEBUG1), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_BACKEND_VK), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_FG), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_FGSWAPCHAIN_VK), + MAP_ENUM_NAME(FFX_API_CREATE_CONTEXT_DESC_TYPE_FSR_UPSCALE), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_GET_VERSIONS), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FGSWAPCHAIN_FUNCTIONS_VK), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FGSWAPCHAIN_INTERPOLATIONCOMMANDLIST_VK), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FGSWAPCHAIN_INTERPOLATIONTEXTURE_DX12), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FGSWAPCHAIN_INTERPOLATIONTEXTURE_VK), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FSR_GETJITTEROFFSET), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FSR_GETJITTERPHASECOUNT), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FSR_GETRENDERRESOLUTIONFROMQUALITYMODE), + MAP_ENUM_NAME(FFX_API_QUERY_DESC_TYPE_FSR_GETUPSCALERATIOFROMQUALITYMODE), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_FG), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_FG_PREPARE), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_FSR_GENERATEREACTIVEMASK), + MAP_ENUM_NAME(FFX_API_DISPATCH_DESC_TYPE_FSR_UPSCALE), +#endif // FFX_BACKEND_VK +}; + +static const char* GetEnumName(uint64_t value) +{ + auto it = EnumNameMap.find(value); + if (it == EnumNameMap.end()) return "INVALID_ENUM"; + return it->second; +} + +#endif + +Validator& Validator::NoExtensions() +{ +#ifdef FFXAPI_VALIDATION + for (auto *it = header->pNext; it; it = it->pNext) + { + // invalid extension! + std::wostringstream message{}; + message << "After header " << GetEnumName(header->type) << ": ignoring unexpected extension " << GetEnumName(it->type); + callback(FFX_API_MESSAGE_TYPE_WARNING, message.str().c_str()); + } +#endif + return *this; +} + +Validator& Validator::AcceptExtensions(std::initializer_list extensionsOnce, std::initializer_list extensionsMany) +{ +#ifdef FFXAPI_VALIDATION + std::vector seenOnce(extsOnce.size(), false); + for (auto *it = header->pNext; it; it = it->pNext) + { + bool canHave = extsMany.end() == std::find(extsMany.begin(), extsMany.end(), it->type); + if (!canHave) + { + auto it_once = std::find(extsOnce.begin(), extsOnce.end(), it->type); + if (it_once != extsOnce.end()) + { + canHave = true; // prevent error further down even if present more than once. + auto idx = std::distance(extsOnce.begin(), it_once); + if (seenOnce[idx]) + { + // extension present more than once! + std::wostringstream message{}; + message << "After header " << GetEnumName(header->type) << ": extension " << GetEnumName(it->type) << " present more than once"; + callback(FFX_API_MESSAGE_TYPE_WARNING, message.str().c_str()); + } + seenOnce[idx] = true; + } + } + if (!canHave) + { + // invalid extension! + std::wostringstream message{}; + message << "After header " << GetEnumName(header->type) << ": ignoring unexpected extension " << GetEnumName(it->type); + callback(FFX_API_MESSAGE_TYPE_WARNING, message.str().c_str()); + } + } +#endif + + return *this; +} diff --git a/Kits/AMDTK/ffx-api/src/validation.h b/Kits/AMDTK/ffx-api/src/validation.h new file mode 100644 index 00000000..93730b90 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/validation.h @@ -0,0 +1,38 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +#include +#include + +class Validator +{ + ffxApiMessage callback; + const ffxApiHeader* header; + +public: + Validator(ffxApiMessage callback, const ffxApiHeader* header) : callback(callback), header(header) {} + + Validator& AcceptExtensions(std::initializer_list extensionsOnce, std::initializer_list extensionsMany = {}); + Validator& NoExtensions(); +}; diff --git a/Kits/AMDTK/ffx-api/src/vk/ffx_provider_framegenerationswapchain_vk.cpp b/Kits/AMDTK/ffx-api/src/vk/ffx_provider_framegenerationswapchain_vk.cpp new file mode 100644 index 00000000..9239318b --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/vk/ffx_provider_framegenerationswapchain_vk.cpp @@ -0,0 +1,273 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_provider_framegenerationswapchain_vk.h" +#include +#include +#include + +#include + +struct InternalFgScContext +{ + InternalContextHeader header; + VkFrameInterpolationInfoFFX frameInterpolationInfo; + VkSwapchainKHR fiSwapChain; + FfxSwapchainReplacementFunctions replacementFunctions; +}; + +////////////////////////////////////////////// +/// Vulkan FFX API overridden functions +////////////////////////////////////////////// + +VkResult vkCreateSwapchainFFXAPI( + VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain, void* pContext) +{ + if (pCreateInfo == nullptr || pContext == nullptr) + return VK_ERROR_INITIALIZATION_FAILED; + + InternalFgScContext* internal_context = reinterpret_cast(pContext); + + if (internal_context->fiSwapChain != VK_NULL_HANDLE) + return VK_ERROR_INITIALIZATION_FAILED; + + VkResult result = VK_ERROR_INITIALIZATION_FAILED; + if (internal_context != nullptr && internal_context->replacementFunctions.createSwapchainFFX != nullptr) + { + result = internal_context->replacementFunctions.createSwapchainFFX( + device, pCreateInfo, pAllocator, &internal_context->fiSwapChain, &internal_context->frameInterpolationInfo); + } + + if (result == VK_SUCCESS) + *pSwapchain = reinterpret_cast(internal_context->fiSwapChain); + + return result; +} + +void vkDestroySwapchainFFXAPI(VkDevice device, VkSwapchainKHR swapchain, const VkAllocationCallbacks* pAllocator, void* pContext) +{ + if (swapchain != VK_NULL_HANDLE) + { + InternalFgScContext* internal_context = reinterpret_cast(pContext); + if (swapchain != internal_context->fiSwapChain) + return; + + if (internal_context != nullptr && internal_context->fiSwapChain != VK_NULL_HANDLE && + internal_context->replacementFunctions.destroySwapchainKHR != nullptr) + { + internal_context->replacementFunctions.destroySwapchainKHR(device, internal_context->fiSwapChain, pAllocator); + internal_context->fiSwapChain = VK_NULL_HANDLE; + } + } +} + +/////////////////////////////////////////////////////////////// +/// ffxProvider_FrameGenerationSwapChain_VK implementation +/////////////////////////////////////////////////////////////// + +bool ffxProvider_FrameGenerationSwapChain_VK::CanProvide(uint64_t type) const +{ + return (type & FFX_API_EFFECT_MASK) == FFX_API_EFFECT_ID_FGSC_VK; +} + +uint64_t ffxProvider_FrameGenerationSwapChain_VK::GetId() const +{ + // FG SwapChain VK, version 1.1.3 + return 0xF65D'564B'01'001'003ui64; +} + +const char* ffxProvider_FrameGenerationSwapChain_VK::GetVersionName() const +{ + return "1.1.3"; +} + +inline VkQueueInfoFFX convertQueueInfo(VkQueueInfoFFXAPI queueInfo) +{ + VkQueueInfoFFX info; + info.queue = queueInfo.queue; + info.familyIndex = queueInfo.familyIndex; + info.submitFunc = queueInfo.submitFunc; + return info; +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_VK::CreateContext(ffxContext* context, ffxCreateContextDescHeader* header, Allocator& alloc) const +{ + if (auto desc = ffx::DynamicCast(header)) + { + InternalFgScContext* internal_context = alloc.construct(); + VERIFY(internal_context, FFX_API_RETURN_ERROR_MEMORY); + internal_context->header.provider = this; + + internal_context->frameInterpolationInfo.physicalDevice = desc->physicalDevice; + internal_context->frameInterpolationInfo.device = desc->device; + internal_context->frameInterpolationInfo.gameQueue = convertQueueInfo(desc->gameQueue); + internal_context->frameInterpolationInfo.asyncComputeQueue = convertQueueInfo(desc->asyncComputeQueue); + internal_context->frameInterpolationInfo.presentQueue = convertQueueInfo(desc->presentQueue); + internal_context->frameInterpolationInfo.imageAcquireQueue = convertQueueInfo(desc->imageAcquireQueue); + internal_context->frameInterpolationInfo.pAllocator = desc->allocator; + + // set the default values + internal_context->frameInterpolationInfo.compositionMode = VK_COMPOSITION_MODE_NOT_FORCED_FFX; + + // get the extensions + for (auto it = header->pNext; it != nullptr; it = it->pNext) + { + if (auto mode = ffx::DynamicCast(it)) + { + if (mode->composeOnPresentQueue) + internal_context->frameInterpolationInfo.compositionMode = VK_COMPOSITION_MODE_PRESENT_QUEUE_FFX; + else + internal_context->frameInterpolationInfo.compositionMode = VK_COMPOSITION_MODE_GAME_QUEUE_FFX; + } + } + + FfxSwapchain swapChain = ffxGetSwapchainVK(*desc->swapchain); + TRY2(ffxReplaceSwapchainForFrameinterpolationVK(desc->gameQueue.queue, swapChain, &desc->createInfo, &internal_context->frameInterpolationInfo)); + internal_context->fiSwapChain = *desc->swapchain = ffxGetVKSwapchain(swapChain); + + internal_context->replacementFunctions = {}; + TRY2(ffxGetSwapchainReplacementFunctionsVK(internal_context->frameInterpolationInfo.device, &internal_context->replacementFunctions)); + + *context = internal_context; + + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_UNKNOWN_DESCTYPE; + } +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_VK::DestroyContext(ffxContext* context, Allocator& alloc) const +{ + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgScContext* internal_context = reinterpret_cast(*context); + + // call the correct function to release the frame interpolation swapchain + FfxSwapchainReplacementFunctions functions = {}; + ffxGetSwapchainReplacementFunctionsVK(internal_context->frameInterpolationInfo.device, &functions); + + if (functions.destroySwapchainKHR != nullptr) + { + functions.destroySwapchainKHR( + internal_context->frameInterpolationInfo.device, internal_context->fiSwapChain, internal_context->frameInterpolationInfo.pAllocator); + internal_context->fiSwapChain = VK_NULL_HANDLE; + } + else + { + vkDestroySwapchainKHR( + internal_context->frameInterpolationInfo.device, internal_context->fiSwapChain, internal_context->frameInterpolationInfo.pAllocator); + internal_context->fiSwapChain = VK_NULL_HANDLE; + } + + alloc.dealloc(internal_context); + + return FFX_API_RETURN_OK; +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_VK::Configure(ffxContext* context, const ffxConfigureDescHeader* header) const +{ + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgScContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + TRY2(ffxRegisterFrameinterpolationUiResourceVK(ffxGetSwapchainVK(internal_context->fiSwapChain), Convert(desc->uiResource), desc->flags)); + + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + TRY2(ffxConfigureFrameInterpolationSwapchainVK(ffxGetSwapchainVK(internal_context->fiSwapChain), static_cast (desc->key), desc->ptr)); + + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_PARAMETER; + } +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_VK::Query(ffxContext* context, ffxQueryDescHeader* header) const +{ + VERIFY(header, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(context, FFX_API_RETURN_ERROR_PARAMETER); + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + + InternalFgScContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + FfxCommandList outCommandList{}; + TRY2(ffxGetFrameinterpolationCommandlistVK(ffxGetSwapchainVK(internal_context->fiSwapChain), outCommandList)); + *desc->pOutCommandList = outCommandList; + + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + *desc->pOutTexture = Convert(ffxGetFrameinterpolationTextureVK(ffxGetSwapchainVK(internal_context->fiSwapChain))); + + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + TRY2(ffxFrameInterpolationSwapchainGetGpuMemoryUsageVK(ffxGetSwapchainVK(internal_context->fiSwapChain), reinterpret_cast (desc->gpuMemoryUsageFrameGenerationSwapchain))); + return FFX_API_RETURN_OK; + } + else if (auto desc = ffx::DynamicCast(header)) + { + desc->pOutCreateSwapchainFFXAPI = vkCreateSwapchainFFXAPI; + desc->pOutDestroySwapchainFFXAPI = vkDestroySwapchainFFXAPI; + desc->pOutGetSwapchainImagesKHR = internal_context->replacementFunctions.getSwapchainImagesKHR; + desc->pOutAcquireNextImageKHR = internal_context->replacementFunctions.acquireNextImageKHR; + desc->pOutQueuePresentKHR = internal_context->replacementFunctions.queuePresentKHR; + desc->pOutSetHdrMetadataEXT = internal_context->replacementFunctions.setHdrMetadataEXT; + desc->pOutGetLastPresentCountFFXAPI = internal_context->replacementFunctions.getLastPresentCountFFX; // Same signature so no need for indirection + + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR_PARAMETER; + } +} + +ffxReturnCode_t ffxProvider_FrameGenerationSwapChain_VK::Dispatch(ffxContext* context, const ffxDispatchDescHeader* header) const +{ + VERIFY(*context, FFX_API_RETURN_ERROR_PARAMETER); + InternalFgScContext* internal_context = reinterpret_cast(*context); + if (auto desc = ffx::DynamicCast(header)) + { + ffxWaitForPresents(internal_context->fiSwapChain); + return FFX_API_RETURN_OK; + } + else + { + return FFX_API_RETURN_ERROR; + } +} + +ffxProvider_FrameGenerationSwapChain_VK ffxProvider_FrameGenerationSwapChain_VK::Instance; diff --git a/Kits/AMDTK/ffx-api/src/vk/ffx_provider_framegenerationswapchain_vk.h b/Kits/AMDTK/ffx-api/src/vk/ffx_provider_framegenerationswapchain_vk.h new file mode 100644 index 00000000..dcebf4f6 --- /dev/null +++ b/Kits/AMDTK/ffx-api/src/vk/ffx_provider_framegenerationswapchain_vk.h @@ -0,0 +1,49 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once +#include "../ffx_provider.h" + +class ffxProvider_FrameGenerationSwapChain_VK: public ffxProvider +{ +public: + ffxProvider_FrameGenerationSwapChain_VK() = default; + virtual ~ffxProvider_FrameGenerationSwapChain_VK() = default; + + virtual bool CanProvide(uint64_t type) const override; + + virtual uint64_t GetId() const override; + + virtual const char* GetVersionName() const override; + + virtual ffxReturnCode_t CreateContext(ffxContext* context, ffxCreateContextDescHeader* desc, Allocator& alloc) const override; + + virtual ffxReturnCode_t DestroyContext(ffxContext* context, Allocator& alloc) const override; + + virtual ffxReturnCode_t Configure(ffxContext* context, const ffxConfigureDescHeader* desc) const override; + + virtual ffxReturnCode_t Query(ffxContext* context, ffxQueryDescHeader* desc) const override; + + virtual ffxReturnCode_t Dispatch(ffxContext* context, const ffxDispatchDescHeader* desc) const override; + + static ffxProvider_FrameGenerationSwapChain_VK Instance; +}; diff --git a/Kits/AMDTK/fidelityfx/BuildFidelityFXSDK.bat b/Kits/AMDTK/fidelityfx/BuildFidelityFXSDK.bat new file mode 100644 index 00000000..5cb3cbb4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/BuildFidelityFXSDK.bat @@ -0,0 +1,84 @@ +:: This file is part of the FidelityFX SDK. +:: +:: Copyright (C) 2024 Advanced Micro Devices, Inc. +:: +:: 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. + +@echo off +setlocal enabledelayedexpansion + +echo =============================================================== +echo. +echo FidelityFX Build System +echo. +echo =============================================================== + +echo Checking pre-requisites... + +:: Check if cmake is installed +cmake --version > nul 2>&1 +if %errorlevel% NEQ 0 ( + echo Cannot find path to CMake. Is CMake installed? Exiting... + exit /b -1 +) else ( + echo CMake Ready. +) + +echo. +echo Building FidelityFX SDK (Standalone) +echo. + +:: Check directories exist and create if not +if not exist build\ ( + mkdir build +) + +cd build + +:: Clear out CMakeCache +if exist CMakeFiles\ ( + rmdir /S /Q CMakeFiles +) +if exist CMakeCache.txt ( + del /S /Q CMakeCache.txt +) + +:: determine architecture +if /i "%PROCESSOR_ARCHITECTURE%" == "ARM64" ( + set arch=ARM64 +) else ( + set arch=X64 +) +echo architecture %arch% detected +echo. + +:: Check if any parameters were passed in and if not, default to DX12 build +if "%~1"=="" ( + set cmake_options=-DFFX_API_BACKEND=DX12_%arch% -DFFX_ALL=ON -DFFX_AUTO_COMPILE_SHADERS=1 +) else ( + set cmake_options=%* +) +echo CMake options: %cmake_options% +cmake .. %cmake_options% + +cmake --build ./ --config Debug --parallel 4 -- /p:CL_MPcount=16 +cmake --build ./ --config Release --parallel 4 -- /p:CL_MPcount=16 +cmake --build ./ --config RelWithDebInfo --parallel 4 -- /p:CL_MPcount=16 + +cd .. diff --git a/Kits/AMDTK/fidelityfx/BuildFidelityFXSDKSolutionDX12.bat b/Kits/AMDTK/fidelityfx/BuildFidelityFXSDKSolutionDX12.bat new file mode 100644 index 00000000..9ebb384c --- /dev/null +++ b/Kits/AMDTK/fidelityfx/BuildFidelityFXSDKSolutionDX12.bat @@ -0,0 +1,139 @@ +:: This file is part of the FidelityFX SDK. +:: +:: Copyright (C) 2024 Advanced Micro Devices, Inc. +:: +:: 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. + +@echo off +setlocal enabledelayedexpansion + +echo =============================================================== +echo. +echo FidelityFX Build System +echo. +echo =============================================================== +echo. + +set build_as_dll= +set /P build_as_dll=Build the SDK as DLL [y/n]? + +set sdk_build_options= +if /i "%build_as_dll%" == "Y" ( + set sdk_build_options=-DFFX_BUILD_AS_DLL=1 +) + +set auto_compile_shaders= +set /P auto_compile_shaders=Auto-compile shaders [y/n]? +if /i "%auto_compile_shaders%" == "N" ( + set auto_compile_shaders=-DFFX_AUTO_COMPILE_SHADERS=0 +) else ( + set auto_compile_shaders=-DFFX_AUTO_COMPILE_SHADERS=1 +) + +ECHO 1. ALL +ECHO 2. BLUR +ECHO 3. BREADCRUMBS +ECHO 4. BRIXELIZER +ECHO 5. CACAO +ECHO 6. CAS +ECHO 7. CLASSIFIER +ECHO 8. DENOISER +ECHO 9. DOF +ECHO 10. FSR 1 +ECHO 11. FSR 2 +ECHO 12. FSR 3 +ECHO 13. LENS +ECHO 14. LPM +ECHO 15. PARALLEL SORT +ECHO 16. SPD +ECHO 17. SSSR +ECHO 18. VRS +ECHO. + +set /P samples=Enter numbers of which effects to build [space delimitted]: +:loop +for /f "tokens=1*" %%a in ("%samples%") do ( + if %%a == 1 set sdk_build_options=-DFFX_ALL=ON %sdk_build_options% + if %%a == 2 set sdk_build_options=-DFFX_BLUR=ON %sdk_build_options% + if %%a == 3 set sdk_build_options=-DFFX_BREADCRUMBS=ON %sdk_build_options% + if %%a == 4 set sdk_build_options=-DFFX_BRIXELIZER=ON %sdk_build_options% + if %%a == 5 set sdk_build_options=-DFFX_CACAO=ON %sdk_build_options% + if %%a == 6 set sdk_build_options=-DFFX_CAS=ON %sdk_build_options% + if %%a == 7 set sdk_build_options=-DFFX_CLASSIFIER=ON %sdk_build_options% + if %%a == 8 set sdk_build_options=-DFFX_DENOISER=ON %sdk_build_options% + if %%a == 9 set sdk_build_options=-DFFX_DOF=ON %sdk_build_options% + if %%a == 10 set sdk_build_options=-DFFX_FSR1=ON %sdk_build_options% + if %%a == 11 set sdk_build_options=-DFFX_FSR2=ON %sdk_build_options% + if %%a == 12 set sdk_build_options=-DFFX_FSR3=ON %sdk_build_options% + if %%a == 13 set sdk_build_options=-DFFX_LENS=ON %sdk_build_options% + if %%a == 14 set sdk_build_options=-DFFX_LPM=ON %sdk_build_options% + if %%a == 15 set sdk_build_options=-DFFX_PARALLEL_SORT=ON %sdk_build_options% + if %%a == 16 set sdk_build_options=-DFFX_SPD=ON %sdk_build_options% + if %%a == 17 set sdk_build_options=-DFFX_SSSR=ON -DFFX_DENOISER=ON %sdk_build_options% + if %%a == 18 set sdk_build_options=-DFFX_VRS=ON %sdk_build_options% + set samples=%%b +) +if defined samples goto :loop + +echo Checking pre-requisites... + +:: Check if cmake is installed +cmake --version > nul 2>&1 +if %errorlevel% NEQ 0 ( + echo Cannot find path to CMake. Is CMake installed? Exiting... + exit /b -1 +) else ( + echo CMake Ready. +) + +echo. +echo Building FidelityFX SDK DX12 (Standalone) %sdk_build_options% %auto_compile_shaders% +echo. + +:: Check directories exist and create if not +if not exist build\ ( + mkdir build +) + +cd build + +:: Clear out CMakeCache +if exist CMakeFiles\ ( + rmdir /S /Q CMakeFiles +) +if exist CMakeCache.txt ( + del /S /Q CMakeCache.txt +) + +:: determine architecture +echo. +echo architecture %PROCESSOR_ARCHITECTURE% detected +echo. +if /i "%PROCESSOR_ARCHITECTURE%" == "ARM64" ( + set arch=ARM64 +) else ( + set arch=X64 +) + +cmake .. -DFFX_API_BACKEND=DX12_%arch% %sdk_build_options% %auto_compile_shaders% + +cd.. + +:: Pause so the user can acknowledge any errors or other outputs from the build process +pause diff --git a/Kits/AMDTK/fidelityfx/BuildFidelityFXSDKSolutionVK.bat b/Kits/AMDTK/fidelityfx/BuildFidelityFXSDKSolutionVK.bat new file mode 100644 index 00000000..3bdbcd55 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/BuildFidelityFXSDKSolutionVK.bat @@ -0,0 +1,136 @@ +:: This file is part of the FidelityFX SDK. +:: +:: Copyright (C) 2024 Advanced Micro Devices, Inc. +:: +:: 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. + +@echo off +setlocal enabledelayedexpansion + +echo =============================================================== +echo. +echo FidelityFX Build System +echo. +echo =============================================================== +echo. + +set build_as_dll= +set /P build_as_dll=Build the SDK as DLL [y/n]? + +set sdk_build_options= +if /i "%build_as_dll%" == "Y" ( + set sdk_build_options=-DFFX_BUILD_AS_DLL=1 +) + +set auto_compile_shaders= +set /P auto_compile_shaders=Auto-compile shaders [y/n]? +if /i "%auto_compile_shaders%" == "N" ( + set auto_compile_shaders=-DFFX_AUTO_COMPILE_SHADERS=0 +) else ( + set auto_compile_shaders=-DFFX_AUTO_COMPILE_SHADERS=1 +) + +ECHO 1. ALL +ECHO 2. BLUR +ECHO 3. BREADCRUMBS +ECHO 4. BRIXELIZER +ECHO 5. CACAO +ECHO 6. CAS +ECHO 7. CLASSIFIER +ECHO 8. DENOISER +ECHO 9. DOF +ECHO 10. FSR 1 +ECHO 11. FSR 2 +ECHO 12. FSR 3 +ECHO 13. LENS +ECHO 14. LPM +ECHO 15. PARALLEL SORT +ECHO 16. SPD +ECHO 17. SSSR +ECHO 18. VRS +ECHO. + +set /P samples=Enter numbers of which effects to build [space delimitted]: +:loop +for /f "tokens=1*" %%a in ("%samples%") do ( + if %%a == 1 set sdk_build_options=-DFFX_ALL=ON %sdk_build_options% + if %%a == 2 set sdk_build_options=-DFFX_BLUR=ON %sdk_build_options% + if %%a == 3 set sdk_build_options=-DFFX_BREADCRUMBS=ON %sdk_build_options% + if %%a == 4 set sdk_build_options=-DFFX_BRIXELIZER=ON %sdk_build_options% + if %%a == 5 set sdk_build_options=-DFFX_CACAO=ON %sdk_build_options% + if %%a == 6 set sdk_build_options=-DFFX_CAS=ON %sdk_build_options% + if %%a == 7 set sdk_build_options=-DFFX_CLASSIFIER=ON %sdk_build_options% + if %%a == 8 set sdk_build_options=-DFFX_DENOISER=ON %sdk_build_options% + if %%a == 9 set sdk_build_options=-DFFX_DOF=ON %sdk_build_options% + if %%a == 10 set sdk_build_options=-DFFX_FSR1=ON %sdk_build_options% + if %%a == 11 set sdk_build_options=-DFFX_FSR2=ON %sdk_build_options% + if %%a == 12 set sdk_build_options=-DFFX_FSR3=ON %sdk_build_options% + if %%a == 13 set sdk_build_options=-DFFX_LENS=ON %sdk_build_options% + if %%a == 14 set sdk_build_options=-DFFX_LPM=ON %sdk_build_options% + if %%a == 15 set sdk_build_options=-DFFX_PARALLEL_SORT=ON %sdk_build_options% + if %%a == 16 set sdk_build_options=-DFFX_SPD=ON %sdk_build_options% + if %%a == 17 set sdk_build_options=-DFFX_SSSR=ON -DFFX_DENOISER=ON %sdk_build_options% + if %%a == 18 set sdk_build_options=-DFFX_VRS=ON %sdk_build_options% + set samples=%%b +) +if defined samples goto :loop + +echo Checking pre-requisites... + +:: Check if cmake is installed +cmake --version > nul 2>&1 +if %errorlevel% NEQ 0 ( + echo Cannot find path to CMake. Is CMake installed? Exiting... + exit /b -1 +) else ( + echo CMake Ready. +) + +:: Check if VULKAN_SDK is installed but don't bail out +if "%VULKAN_SDK%"=="" ( + echo Vulkan SDK is not installed -Environment variable VULKAN_SDK is not defined- : Please install the latest Vulkan SDK from LunarG. +) else ( + echo Vulkan SDK - Ready : %VULKAN_SDK% +) + +echo. +echo Building FidelityFX SDK VK (Standalone) %sdk_build_options% %auto_compile_shaders% +echo. + +:: Check directories exist and create if not +if not exist build\ ( + mkdir build +) + +cd build + +:: Clear out CMakeCache +if exist CMakeFiles\ ( + rmdir /S /Q CMakeFiles +) +if exist CMakeCache.txt ( + del /S /Q CMakeCache.txt +) + +cmake .. -DFFX_API_BACKEND=VK_X64 %sdk_build_options% %auto_compile_shaders% + +cd.. + +:: Pause so the user can acknowledge any errors or other outputs from the build process +pause diff --git a/Kits/AMDTK/fidelityfx/CMakeLists.txt b/Kits/AMDTK/fidelityfx/CMakeLists.txt new file mode 100644 index 00000000..bfa13493 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/CMakeLists.txt @@ -0,0 +1,271 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +cmake_minimum_required(VERSION 3.23) + +if(POLICY CMP0147) + # parallel custom command builds (used for shader compilation) + cmake_policy(SET CMP0147 NEW) +endif() + +# Clean a bit before +unset(FFX_GDK CACHE) + +message(STATUS "FFX_API_BACKEND is ${FFX_API_BACKEND}") + +if(FFX_API_BACKEND STREQUAL VK_X64 OR + FFX_API_BACKEND STREQUAL DX12_X64 OR + FFX_API_BACKEND STREQUAL DX12_ARM64 OR + FFX_API_BACKEND STREQUAL DX12_ARM64EC OR + FFX_API_BACKEND STREQUAL GDK_SCARLETT_X64 OR + FFX_API_BACKEND STREQUAL GDK_XBOXONE_X64) + set(FFX_CUSTOM_API OFF) +else() + set(FFX_CUSTOM_API ON) +endif() + +# Set configuration types based on what we are building for +if (NOT FFX_CUSTOM_API) + + # Are we buiding the GDK? + if (FFX_API_BACKEND STREQUAL GDK_SCARLETT_X64 OR FFX_API_BACKEND STREQUAL GDK_XBOXONE_X64) + set(FFX_GDK ON) + endif() + + # Pull in tool chain definitions + include(toolchain.cmake) + + # If we are NOT building the GDK, queue up DX12/VK solution for building + if (NOT FFX_GDK) + if (FFX_API_BACKEND STREQUAL DX12_X64 OR + FFX_API_BACKEND STREQUAL DX12_ARM64 OR + FFX_API_BACKEND STREQUAL DX12_ARM64EC) + message(STATUS "Building FidelityFX SDK with DX12 backend") + elseif(FFX_API_BACKEND STREQUAL VK_X64) + message(STATUS "Building FidelityFX SDK with VK backend") + endif() + else() + # List the API we are building for + if(FFX_API_BACKEND STREQUAL GDK_SCARLETT_X64) + message(STATUS "Building FidelityFX SDK with GDK Gaming.Scarlett.x64 backend") + elseif(FFX_API_BACKEND STREQUAL GDK_XBOXONE_X64) + message(STATUS "Building FidelityFX SDK with GDK Gaming.XboxOne.x64 backend") + else() + message(FATAL_ERROR "Requesting unsupported GDK build of FidelityFX SDK!") + endif() + endif() +endif() + +# Set platform +if(CMAKE_GENERATOR_PLATFORM STREQUAL "Gaming.Xbox.Scarlett.x64") + set(FFX_PLATFORM_NAME gdk_scarlett_x64) +elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "Gaming.Xbox.XboxOne.x64") + set(FFX_PLATFORM_NAME gdk_xboxone_x64) +elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "x64" OR CMAKE_EXE_LINKER_FLAGS STREQUAL "/machine:x64") + set(FFX_PLATFORM_NAME x64) +elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "Win32" OR CMAKE_EXE_LINKER_FLAGS STREQUAL "/machine:X86") + set(FFX_PLATFORM_NAME x86) +elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64" OR CMAKE_EXE_LINKER_FLAGS STREQUAL "/machine:ARM64") + set(FFX_PLATFORM_NAME arm64) +elseif(CMAKE_GENERATOR_PLATFORM STREQUAL "arm64ec" OR CMAKE_EXE_LINKER_FLAGS STREQUAL "/machine:ARM64EC") + set(FFX_PLATFORM_NAME arm64ec) +else() + message(FATAL_ERROR "Unsupported target platform \"${CMAKE_GENERATOR_PLATFORM}\"") +endif() + +# Pre-compile shaders +set(FFX_AUTO_COMPILE_SHADERS ON CACHE BOOL "Compile shaders automatically as a prebuild step.") + +if(CMAKE_GENERATOR STREQUAL "Ninja") + set(USE_DEPFILE TRUE) +else() + set(USE_DEPFILE FALSE) +endif() + +# Set Visual Studio version +if(CMAKE_GENERATOR STREQUAL "Visual Studio 14 2015") + set(FFX_VS_VERSION 2015) +elseif(CMAKE_GENERATOR STREQUAL "Visual Studio 15 2017") + set(FFX_VS_VERSION 2017) +elseif(CMAKE_GENERATOR STREQUAL "Visual Studio 16 2019") + set(FFX_VS_VERSION 2019) +elseif(CMAKE_GENERATOR STREQUAL "Visual Studio 17 2022") + set(FFX_VS_VERSION 2022) +endif() + +# Set configuration types based on what we are building for +if (NOT FFX_CUSTOM_API) + + # Embed PDBs in the debug versions of the libs + set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /Z7 /Od") + + # Write debug, profile, and release versions of the static libs to the /bin folder as they are uniquely named + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_DEBUG ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELEASE ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + + + if (FFX_BUILD_AS_DLL) + # Write both debug and release versions of the dlls to the /bin folder as they are uniquely named + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS FFX_BUILD_AS_DLL) + endif() +else() + + # Ouput the static libs to the /bin folder as they are uniquely named + set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${BIN_OUTPUT}/ffx_sdk) + foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) + string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) + set( CMAKE_ARCHIVE_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${BIN_OUTPUT}/ffx_sdk/ ) + if (FFX_BUILD_AS_DLL) + # Write both debug and release versions of the dlls to the /bin folder as they are uniquely named + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELWITHDEBINFO ${CMAKE_HOME_DIRECTORY}/bin/ffx_sdk/) + endif() + endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) + +endif() + +if (FFX_FSR3) + option(FFX_FSR3UPSCALER "Build FFX FSR3 Upscaler API" ON) + option(FFX_FI "Build FFX Frame Interpolation API" ON) + option(FFX_OF "Build FFX Optical Flow API" ON) +endif() + +if (FFX_SSSR) + option(FFX_DENOISER "Build FFX Denoiser API" ON) +endif() + +# Add requred compile definitions +add_compile_definitions(_UNICODE) +add_compile_definitions(UNICODE) +add_compile_definitions(_DISABLE_CONSTEXPR_MUTEX_CONSTRUCTOR) + +if(FFX_VS_VERSION STREQUAL 2015 OR FFX_VS_VERSION STREQUAL 2017) + message(NOTICE "Forcing the SDK path for VS 2015 and VS 2017") + set(CMAKE_VS_WINDOWS_TARGET_PLATFORM_VERSION "10.0.18362.0") +endif() + +# Setup common variables +set(FFX_SC_EXECUTABLE ${CMAKE_CURRENT_SOURCE_DIR}/tools/binary_store/FidelityFX_SC.exe) +set(FFX_INCLUDE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include) +set(FFX_LIB_PATH ${CMAKE_CURRENT_SOURCE_DIR}/libs) +set(FFX_BIN_PATH ${CMAKE_CURRENT_SOURCE_DIR}/bin/ffx_sdk) +set(FFX_SHARED_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/shared) +set(FFX_HOST_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include/FidelityFX/host) +set(FFX_GPU_PATH ${CMAKE_CURRENT_SOURCE_DIR}/include/FidelityFX/gpu) +set(FFX_COMPONENTS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/components) +set(FFX_HOST_BACKENDS_PATH ${FFX_HOST_PATH}/backends) +set(FFX_SRC_BACKENDS_PATH ${CMAKE_CURRENT_SOURCE_DIR}/src/backends) + +# ------------------------------------------------------ +# Define common source groupings used by all effects + +# Set shared and global public sources +file(GLOB FFX_SHARED_SOURCES + "${FFX_SHARED_PATH}/*.cpp" + "${FFX_SHARED_PATH}/*.h") + +set(FFX_PUBLIC_SOURCES + "${FFX_HOST_PATH}/ffx_assert.h" + "${FFX_HOST_PATH}/ffx_message.h" + "${FFX_HOST_PATH}/ffx_error.h" + "${FFX_HOST_PATH}/ffx_fx.h" + "${FFX_HOST_PATH}/ffx_interface.h" + "${FFX_HOST_PATH}/ffx_types.h" + "${FFX_HOST_PATH}/ffx_util.h") + +# Init shader sources (for easy viewing) +set(FFX_PUBLIC_SHADER_SOURCES + "${FFX_GPU_PATH}/ffx_common_types.h" + "${FFX_GPU_PATH}/ffx_core.h" + "${FFX_GPU_PATH}/ffx_core_cpu.h" + "${FFX_GPU_PATH}/ffx_core_glsl.h" + "${FFX_GPU_PATH}/ffx_core_gpu_common.h" + "${FFX_GPU_PATH}/ffx_core_gpu_common_half.h" + "${FFX_GPU_PATH}/ffx_core_hlsl.h" + "${FFX_GPU_PATH}/ffx_core_portability.h") + +if(FFX_API_BACKEND STREQUAL DX12_X64) + message(STATUS "Creating project FidelityFX-SDK_DX12_x64") + project(FidelityFX-SDK_DX12_x64) +elseif(FFX_API_BACKEND STREQUAL DX12_ARM64) + message(STATUS "Creating project FidelityFX-SDK_DX12_arm64") + project (FidelityFX-SDK_DX12_arm64) +elseif(FFX_API_BACKEND STREQUAL DX12_ARM64EC) + message(STATUS "Creating project FidelityFX-SDK_DX12_arm64ec") + project (FidelityFX-SDK_DX12_arm64ec) +elseif (FFX_API_BACKEND STREQUAL VK_X64) + message(STATUS "Creating project FidelityFX-SDK_VK_x64") + project(FidelityFX-SDK_VK_x64) +elseif(FFX_API_BACKEND STREQUAL GDK_SCARLETT_X64) + message(STATUS "Creating project FidelityFX-SDK_GDK_Scarlett_x64") + project(FidelityFX-SDK_GDK_Scarlett_x64) +elseif(FFX_API_BACKEND STREQUAL GDK_XBOXONE_X64) + message(STATUS "Creating project FidelityFX-SDK_GDK_XboxOne_x64") + project (FidelityFX-SDK_GDK_XboxOne_x64) +else() + # This is likely a custom include + project (FidelityFX-SDK) +endif() + +# Components +add_subdirectory(${FFX_COMPONENTS_PATH}/opticalflow) +add_subdirectory(${FFX_COMPONENTS_PATH}/frameinterpolation) +add_subdirectory(${FFX_COMPONENTS_PATH}/fsr3) +add_subdirectory(${FFX_COMPONENTS_PATH}/fsr3upscaler) +add_subdirectory(${FFX_COMPONENTS_PATH}/fsr2) +add_subdirectory(${FFX_COMPONENTS_PATH}/fsr1) +add_subdirectory(${FFX_COMPONENTS_PATH}/spd) +add_subdirectory(${FFX_COMPONENTS_PATH}/cacao) +add_subdirectory(${FFX_COMPONENTS_PATH}/lpm) +add_subdirectory(${FFX_COMPONENTS_PATH}/blur) +add_subdirectory(${FFX_COMPONENTS_PATH}/vrs) +add_subdirectory(${FFX_COMPONENTS_PATH}/cas) +add_subdirectory(${FFX_COMPONENTS_PATH}/dof) +add_subdirectory(${FFX_COMPONENTS_PATH}/lens) +add_subdirectory(${FFX_COMPONENTS_PATH}/parallelsort) +add_subdirectory(${FFX_COMPONENTS_PATH}/denoiser) +add_subdirectory(${FFX_COMPONENTS_PATH}/sssr) +add_subdirectory(${FFX_COMPONENTS_PATH}/brixelizer) +add_subdirectory(${FFX_COMPONENTS_PATH}/brixelizergi) +add_subdirectory(${FFX_COMPONENTS_PATH}/classifier) +add_subdirectory(${FFX_COMPONENTS_PATH}/breadcrumbs) + +# Add appropriate graphics backend if requested +if(FFX_API_BACKEND STREQUAL DX12_X64 OR + FFX_API_BACKEND STREQUAL DX12_ARM64 OR + FFX_API_BACKEND STREQUAL DX12_ARM64EC) + add_subdirectory(${FFX_LIB_PATH}/pix) + add_subdirectory(${FFX_SRC_BACKENDS_PATH}/dx12) +endif() + +if (FFX_API_BACKEND STREQUAL VK_X64) + add_subdirectory(${FFX_SRC_BACKENDS_PATH}/vk) +endif() + +if(FFX_API_BACKEND STREQUAL GDK_SCARLETT_X64 OR FFX_API_BACKEND STREQUAL GDK_XBOXONE_X64) + add_subdirectory(${FFX_SRC_BACKENDS_PATH}/gdk) +endif() diff --git a/Kits/AMDTK/fidelityfx/LICENSE.txt b/Kits/AMDTK/fidelityfx/LICENSE.txt new file mode 100644 index 00000000..3712e34a --- /dev/null +++ b/Kits/AMDTK/fidelityfx/LICENSE.txt @@ -0,0 +1,21 @@ +This file is part of the FidelityFX SDK. + +Copyright (C) 2024 Advanced Micro Devices, Inc. + +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/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/CMakeCompileShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/CMakeCompileShaders.txt new file mode 100644 index 00000000..ac1088d0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/CMakeCompileShaders.txt @@ -0,0 +1,141 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Function to compile a set of shaders using the FidelityFX shader compiler driver. +# +# EXECUTABLE Path to the FidelityFX SC tool executable. +# BASE_ARGS The base arguments for the compiler. +# API_BASE_ARGS API (DX12 or Vulkan) specific base args. +# PERMUTATION_ARGS Permutation set to compile for. +# SHADER_FILES A list of shader files to compile using the permutation matrix expanded from SC_PERMUTATION_ARGS. +# OUTPUT_PATH Path to store compiled shader output. +# +# Returns +# A list of header files generated by the FidelityFX Shader Compiler driver. +function(compile_shaders_with_depfile + EXECUTABLE BASE_ARGS API_BASE_ARGS + PERMUTATION_ARGS INCLUDES_ARGS + SHADER_FILES OUTPUT_PATH + PERMUTATION_OUTPUTS) + + #message(STATUS "OUTPUT_PATH=${OUTPUT_PATH}") + #message(STATUS "EXE=${EXECUTABLE}") + #message(STATUS "BASE=${BASE_ARGS}") + #message(STATUS "API=${API_BASE_ARGS}") + #message(STATUS "PERMS=${PERMUTATION_ARGS}") + #message(STATUS "INCLUDES=${INCLUDES_ARGS}") + #message(STATUS "SHADER_FILES=${SHADER_FILES}") + + # Figure out if this HLSL or GLSL + list(GET SHADER_FILES 0 FIRST_SHADER_FILE) + get_filename_component(SHADER_EXT "${FIRST_SHADER_FILE}" LAST_EXT) + string(TOUPPER "${SHADER_EXT}" SHADER_EXT) + set(INCLUDE_SPACE ) + set(HLSL_WAVE64_ARGS ) + set(HLSL_WAVE32_ARGS ) + set(HLSL_16BIT_ARGS ) + if (SHADER_EXT STREQUAL ".HLSL") + set(INCLUDE_SPACE " ") + set(HLSL_WAVE64_ARGS "-DFFX_PREFER_WAVE64=\"[WaveSize(64)]\"" "-DFFX_HLSL_SM=66" -T cs_6_6) + set(HLSL_WAVE32_ARGS "-DFFX_HLSL_SM=62" -T cs_6_2) + set(HLSL_16BIT_ARGS "-enable-16bit-types") + endif() + # GLSL requires no spaces: -I -I etc. + # HLSL requires spaces: -I -I etc. + set(COMPILE_INCLUDE_ARGS ) + foreach(INC ${INCLUDES_ARGS}) + list(APPEND COMPILE_INCLUDE_ARGS "-I${INCLUDE_SPACE}${INC}") + endforeach(INC) + + if (FFX_API_BACKEND STREQUAL GDK_DESKTOP_X64) + set(FFX_GDK_OPTION -compiler=gdk.desktop.x64) + elseif (FFX_API_BACKEND STREQUAL GDK_SCARLETT_X64) + set(FFX_GDK_OPTION -compiler=gdk.scarlett.x64) + else() + set(FFX_GDK_OPTION ) + endif() + + foreach(PASS_SHADER ${SHADER_FILES}) + get_filename_component(PASS_SHADER_FILENAME ${PASS_SHADER} NAME_WE) + get_filename_component(PASS_SHADER_TARGET ${PASS_SHADER} NAME_WLE) + + set(WAVE32_PERMUTATION_HEADER ${OUTPUT_PATH}/${PASS_SHADER_TARGET}_permutations.h) + set(WAVE64_PERMUTATION_HEADER ${OUTPUT_PATH}/${PASS_SHADER_TARGET}_wave64_permutations.h) + set(WAVE32_16BIT_PERMUTATION_HEADER ${OUTPUT_PATH}/${PASS_SHADER_TARGET}_16bit_permutations.h) + set(WAVE64_16BIT_PERMUTATION_HEADER ${OUTPUT_PATH}/${PASS_SHADER_TARGET}_wave64_16bit_permutations.h) + + # combine base and permutation args + set(SC_ARGS ${BASE_ARGS} ${API_BASE_ARGS} ${PERMUTATION_ARGS}) + + # Wave32 + add_custom_command( + OUTPUT ${WAVE32_PERMUTATION_HEADER} + COMMAND ${EXECUTABLE} ${FFX_GDK_OPTION} ${SC_ARGS} -name=${PASS_SHADER_FILENAME} -DFFX_HALF=0 ${HLSL_WAVE32_ARGS} ${COMPILE_INCLUDE_ARGS} -output=${OUTPUT_PATH} ${PASS_SHADER} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${PASS_SHADER} + DEPFILE ${WAVE32_PERMUTATION_HEADER}.d + ) + list(APPEND PERMUTATION_OUTPUTS ${WAVE32_PERMUTATION_HEADER}) + + # Wave64 + add_custom_command( + OUTPUT ${WAVE64_PERMUTATION_HEADER} + COMMAND ${EXECUTABLE} ${FFX_GDK_OPTION} ${SC_ARGS} -name=${PASS_SHADER_FILENAME}_wave64 -DFFX_HALF=0 ${HLSL_WAVE64_ARGS} ${COMPILE_INCLUDE_ARGS} -output=${OUTPUT_PATH} ${PASS_SHADER} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${PASS_SHADER} + DEPFILE ${WAVE64_PERMUTATION_HEADER}.d + ) + list(APPEND PERMUTATION_OUTPUTS ${WAVE64_PERMUTATION_HEADER}) + + # Wave32 16-bit + add_custom_command( + OUTPUT ${WAVE32_16BIT_PERMUTATION_HEADER} + COMMAND ${EXECUTABLE} ${FFX_GDK_OPTION} ${SC_ARGS} -name=${PASS_SHADER_FILENAME}_16bit -DFFX_HALF=1 ${HLSL_16BIT_ARGS} ${HLSL_WAVE32_ARGS} ${COMPILE_INCLUDE_ARGS} -output=${OUTPUT_PATH} ${PASS_SHADER} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${PASS_SHADER} + DEPFILE ${WAVE32_16BIT_PERMUTATION_HEADER}.d + ) + list(APPEND PERMUTATION_OUTPUTS ${WAVE32_16BIT_PERMUTATION_HEADER}) + + # Wave64 16-bit + add_custom_command( + OUTPUT ${WAVE64_16BIT_PERMUTATION_HEADER} + COMMAND ${EXECUTABLE} ${FFX_GDK_OPTION} ${SC_ARGS} -name=${PASS_SHADER_FILENAME}_wave64_16bit -DFFX_HALF=1 ${HLSL_16BIT_ARGS} ${HLSL_WAVE64_ARGS} ${COMPILE_INCLUDE_ARGS} -output=${OUTPUT_PATH} ${PASS_SHADER} + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + DEPENDS ${PASS_SHADER} + DEPFILE ${WAVE64_16BIT_PERMUTATION_HEADER}.d + ) + list(APPEND PERMUTATION_OUTPUTS ${WAVE64_16BIT_PERMUTATION_HEADER}) + endforeach(PASS_SHADER) + + set(${PERMUTATION_OUTPUTS} ${PERMUTATION_OUTPUTS} PARENT_SCOPE) +endfunction() + +# macro to add shader output files to a list for dependencies +macro (add_shader_output) + foreach (_SHADER_SRC ${ARGN}) + #message (STATUS ${_SHADER_SRC}) + list (APPEND FFX_SC_PERMUTATION_OUTPUTS "${_SHADER_SRC}") + endforeach() + + set (FFX_SC_PERMUTATION_OUTPUTS ${FFX_SC_PERMUTATION_OUTPUTS} PARENT_SCOPE) +endmacro() \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/CMakeCompileBlurShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/CMakeCompileBlurShaders.txt new file mode 100644 index 00000000..7fe0d7ae --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/CMakeCompileBlurShaders.txt @@ -0,0 +1,48 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(BLUR_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(BLUR_PERMUTATION_ARGS + -DFFX_BLUR_OPTION_KERNEL_DIMENSION={3,5,7,9,11,13,15,17,19,21} + -DFFX_BLUR_OPTION_KERNEL_PERMUTATION={0,1,2}) + +set(BLUR_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/blur") + +if (NOT BLUR_SHADER_EXT) + set(BLUR_SHADER_EXT *) +endif() + +file(GLOB BLUR_SHADERS + "shaders/blur/ffx_blur_pass.${BLUR_SHADER_EXT}") + +# compile all the shaders +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${BLUR_BASE_ARGS}" "${BLUR_API_BASE_ARGS}" "${BLUR_PERMUTATION_ARGS}" "${BLUR_INCLUDE_ARGS}" + "${BLUR_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" BLUR_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${BLUR_PERMUTATION_OUTPUTS}") \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur.h new file mode 100644 index 00000000..f982b99e --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur.h @@ -0,0 +1,937 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BLUR_H +#define FFX_BLUR_H +//_____________________________________________________________/\_______________________________________________________________ +//============================================================================================================================== +// +// [FFX BLUR] Blur +// +//============================================================================================================================== +// +/// @defgroup FfxGPUBlur FidelityFX BLUR +/// FidelityFX Blur GPU documentation +/// +/// @ingroup FfxGPUEffects + +//------------------------------------------------------------------------------------------------------------------------------ +// +// ABOUT +// ===== +// AMD FidelityFX Blur is a collection of blurring effects implemented on compute shaders, hand-optimized for maximum performance. +// FFX-Blur includes +// - Gaussian Blur w/ large kernel support (up to 21x21) +// +//============================================================================================================================== + +//============================================================================================================================== +// BLUR SETUP +//============================================================================================================================== + + +/// FFX_BLUR_TILE_SIZE_Y: Tile Y dimensions that the local threadgroup will work on. +/// Note: each threadgroup is responsible for blurring a tile of the input image. +/// +/// @ingroup FfxGPUBlur +#ifndef FFX_BLUR_TILE_SIZE_Y +#define FFX_BLUR_TILE_SIZE_Y 8 +#endif + +/// FFX_BLUR_TILE_SIZE_X: Tile X dimensions that the local threadgroup will work on. +/// Note: each threadgroup is responsible for blurring a tile of the input image. +/// +/// @ingroup FfxGPUBlur +#ifndef FFX_BLUR_TILE_SIZE_X +#define FFX_BLUR_TILE_SIZE_X 8 +#endif + +/// FFX_BLUR_DISPATCH_Y: Y dimension of the Blur compute dispatch. +/// The compute dispatch on the CPU side uses this value when invoking Dispatch. +/// +/// @ingroup FfxGPUBlur +#define FFX_BLUR_DISPATCH_Y 8 + +#ifndef FFX_CPU + +/// FFX_BLUR_OPTION_KERNEL_DIMENSION needs to be defined by the client application +/// App should define e.g the following for 5x5 blur: +/// #define FFX_BLUR_OPTION_KERNEL_DIMENSION 5 +/// +/// @ingroup FfxGPUBlur +#ifndef FFX_BLUR_OPTION_KERNEL_DIMENSION +#error Please define FFX_BLUR_OPTION_KERNEL_DIMENSION +#endif + +/// FFX_BLUR_KERNEL_RANGE is defined relative to FFX_BLUR_OPTION_KERNEL_DIMENSION +/// See ffx_blur_callbacks_*.h for details. +/// +/// @ingroup FfxGPUBlur +#ifndef FFX_BLUR_KERNEL_RANGE +#error Please define FFX_BLUR_KERNEL_RANGE +#endif + +//-------------------------------------------------------------------------------------- +// BLUR CONFIG +//-------------------------------------------------------------------------------------- +// hardcoded variants +#define BLUR_DEBUG_PREFILL_OUTPUT_CACHE_WITH_COLOR 0 +#define BLUR_GROUPSHARED_MEMORY_SOA 0 // [Deprecated] improves LDS but too high traffic still +#define BLUR_GROUPSHARED_MEMORY_HALF 0 // [Deprecated] LOTS of LDS traffic (1x ds_read per channel), need to pack with FfxUInt32 +#define BLUR_GROUPSHARED_MEMORY_PK_UINT 1 // 1x ds_read2st64_b32 for all three channels +#define BLUR_FP16_KERNEL_LOOPS 1 // use fp16 for kernel loop counters and lds indexing (increases VGPR due to sdwa) +#define BLUR_FP16_CLAMP 1 // ensure fp16 min/max is used for clamp() +// cpu-driven variants +#ifndef BLUR_ENABLE_INPUT_CACHE +#define BLUR_ENABLE_INPUT_CACHE 0 // currently only slows the algorithm :( +#endif +#ifndef BLUR_DISABLE_CLAMP +#define BLUR_DISABLE_CLAMP 0 // Generates incorrect image at the image borders (no clamp), for testing theoretical speed +#endif +#ifndef BLUR_OPTIMIZED_CLAMP +#define BLUR_OPTIMIZED_CLAMP 0 // [Experimental] Testing a new optimized clamp ISA +#endif + +// constants +#define BLUR_TILE_SIZE_Y_INV (1.0 / FFX_BLUR_TILE_SIZE_Y) + +//-------------------------------------------------------------------------------------- +// GROUPSHARED MEMORY +//-------------------------------------------------------------------------------------- +// Define CacheTypes +#if BLUR_GROUPSHARED_MEMORY_SOA + #if BLUR_GROUPSHARED_MEMORY_HALF + #ifdef FFX_HLSL + #define BLUR_GROUPSHARED_MEMORY_TYPE groupshared FfxFloat16 + #else + #define BLUR_GROUPSHARED_MEMORY_TYPE shared FfxFloat16 + #endif + #else + #ifdef FFX_HLSL + #define BLUR_GROUPSHARED_MEMORY_TYPE groupshared FfxFloat32 + #else + #define BLUR_GROUPSHARED_MEMORY_TYPE shared FfxFloat32 + #endif + #endif +#else // BLUR_GROUPSHARED_MEMORY_SOA + #if BLUR_GROUPSHARED_MEMORY_HALF + #ifdef FFX_HLSL + #define BLUR_GROUPSHARED_MEMORY_TYPE groupshared FfxFloat16x3 + #else + #define BLUR_GROUPSHARED_MEMORY_TYPE shared FfxFloat16x3 + #endif + #else + #ifdef FFX_HLSL + #define BLUR_GROUPSHARED_MEMORY_TYPE groupshared FfxFloat32x3 + #else + #define BLUR_GROUPSHARED_MEMORY_TYPE shared FfxFloat32x3 + #endif + #endif +#endif // BLUR_GROUPSHARED_MEMORY_SOA + +//============================================================================================================================== +// MATH HELPERS +//============================================================================================================================== +#define DIV_AND_ROUND_UP(x, y) (((x) + ((y)-1)) / ((y))) +// Fast modulo operator for powers of two values for Y: x % y == x & (y-1) +#define FAST_MOD(x, y) ((x) & (y - 1)) +#if FFX_HALF +#define FAST_MOD16(x, y) ((x) & (y - FfxInt16(1))) +#endif + +// OUTPUT CACHE ######################################## +/* +# Notes from Jordan's Presentation +src: https://gpuopen.com/gdc-presentations/2019/gdc-2019-s5-blend-of-gcn-optimization-and-color-processing.pdf +Use 2^n tiles to use bitwise AND in place of the more ALU-expensive % operator, see #define FAST_MOD above +MinTiles -> Ceil(HalfKernel / TileSize) * 2 + 1 +*/ +#if FFX_BLUR_OPTION_KERNEL_DIMENSION > 7 +#define NUM_TILES_OUTPUT_CACHE 8 +#else +#define NUM_TILES_OUTPUT_CACHE 4 +#endif + +#define NUM_PIXELS_OUTPUT_CACHE (FFX_BLUR_TILE_SIZE_Y * FFX_BLUR_TILE_SIZE_X * NUM_TILES_OUTPUT_CACHE) + + +#if BLUR_GROUPSHARED_MEMORY_PK_UINT +#ifdef FFX_HLSL + groupshared FfxUInt32 OutputCacheRG[NUM_PIXELS_OUTPUT_CACHE]; // RG: 2x fp16's are packed into 32bit unsigned int + groupshared FfxFloat32 OutputCacheB [NUM_PIXELS_OUTPUT_CACHE]; // B : don't use fp16 for B to avoid bank conflicts +#else + shared FfxUInt32 OutputCacheRG[NUM_PIXELS_OUTPUT_CACHE]; // RG: 2x fp16's are packed into 32bit unsigned int + shared FfxFloat32 OutputCacheB [NUM_PIXELS_OUTPUT_CACHE]; // B : don't use fp16 for B to avoid bank conflicts +#endif +#else + #if BLUR_GROUPSHARED_MEMORY_SOA + BLUR_GROUPSHARED_MEMORY_TYPE OutputCache[NUM_PIXELS_OUTPUT_CACHE * 3]; // stores rrrrrr...ggggggg...bbbbb... + #else + BLUR_GROUPSHARED_MEMORY_TYPE OutputCache[NUM_PIXELS_OUTPUT_CACHE]; // stores rgbrgbrgbrgbrgbrgbrgbrgb... + #endif // BLUR_GROUPSHARED_MEMORY_SOA +#endif // BLUR_GROUPSHARED_MEMORY_PK_UINT + +// Based on the FFX_BLUR_OPTION_KERNEL_DIMENSION, we will need to pre-fill a number of tiles. +// e.g. TILE_SIZE_Y=8 +// ----------------------------------------- +// kernel = 3 | NUM_PREFILL_TILES_OUTPUT_CACHE = 1 | +// kernel = 5 | NUM_PREFILL_TILES_OUTPUT_CACHE = 1 | +// kernel = 7 | NUM_PREFILL_TILES_OUTPUT_CACHE = 1 | +// kernel = 9* | NUM_PREFILL_TILES_OUTPUT_CACHE = 2*| +// kernel = 11 | NUM_PREFILL_TILES_OUTPUT_CACHE = 2 | +// kernel = 13 | NUM_PREFILL_TILES_OUTPUT_CACHE = 2 | +// kernel = 15 | NUM_PREFILL_TILES_OUTPUT_CACHE = 2 | +// kernel = 17*| NUM_PREFILL_TILES_OUTPUT_CACHE = 3*| +// kernel = 19 | NUM_PREFILL_TILES_OUTPUT_CACHE = 3 | +// kernel = 21 | NUM_PREFILL_TILES_OUTPUT_CACHE = 3 | +// kernel = 23 | NUM_PREFILL_TILES_OUTPUT_CACHE = 3 | +// ----------------------------------------- +#define NUM_PREFILL_TILES_OUTPUT_CACHE DIV_AND_ROUND_UP(FFX_BLUR_OPTION_KERNEL_DIMENSION, FFX_BLUR_TILE_SIZE_Y) + + +// INPUT CACHE ######################################## +#if BLUR_ENABLE_INPUT_CACHE + #define INPUT_CACHE_TILE_SIZE_X (FFX_BLUR_TILE_SIZE_X + FFX_BLUR_OPTION_KERNEL_DIMENSION - 1) + #define NUM_TILES_INPUT_CACHE 1 + #define NUM_PIXELS_INPUT_CACHE ((INPUT_CACHE_TILE_SIZE_X * FFX_BLUR_TILE_SIZE_Y) * NUM_TILES_INPUT_CACHE) + + #if BLUR_GROUPSHARED_MEMORY_PK_UINT + #ifdef FFX_HLSL + groupshared FfxUInt32 InputCacheRG[NUM_PIXELS_INPUT_CACHE]; // RG: 2x fp16's are packed into 32bit unsigned int + groupshared FfxFloat32 InputCacheB [NUM_PIXELS_INPUT_CACHE]; // B : don't use fp16 for B to avoid bank conflicts + #else + shared FfxUInt32 InputCacheRG[NUM_PIXELS_INPUT_CACHE]; // RG: 2x fp16's are packed into 32bit unsigned int + shared FfxFloat32 InputCacheB [NUM_PIXELS_INPUT_CACHE]; // B : don't use fp16 for B to avoid bank conflicts + #endif + #else + #if BLUR_GROUPSHARED_MEMORY_SOA + BLUR_GROUPSHARED_MEMORY_TYPE InputCache[NUM_PIXELS_INPUT_CACHE * 3]; // stores rrrrrr...ggggggg...bbbbb... + #else + BLUR_GROUPSHARED_MEMORY_TYPE InputCache[NUM_PIXELS_INPUT_CACHE]; // stores rgbrgbrgbrgbrgbrgbrgbrgb... + #endif // BLUR_GROUPSHARED_MEMORY_SOA + #endif //BLUR_GROUPSHARED_MEMORY_PK_UINT +#endif // BLUR_ENABLE_INPUT_CACHE + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// + +//============================================================================================================================== +// GROUPSHARED MEMORY MAPPING FUNCTIONS +//============================================================================================================================== +// LDS ops ---------------------------------------------------------------------------------- +// LDS TILES : FFX_BLUR_TILE_SIZE_X * FFX_BLUR_TILE_SIZE_Y sized tiles +// e.g. FFX_BLUR_TILE_SIZE_X = 8 +// +// <------------ FFX_BLUR_TILE_SIZE_X --------------> +// ^ OutputCache[0-7] +// | OutputCache[8-15] +// | +// | // TILE #1 +// | +// | +// v OutputCache[56-63] +// <------------------------------------------------> +// | +// <------------ FFX_BLUR_TILE_SIZE_X --------------> +// ^ OutputCache[64-71] +// | +// | +// | // TILE #2 +// | +// | +// v +// <------------------------------------------------> +// | +//... +FfxUInt32 PackF2(FfxFloat32x2 c) { return (ffxF32ToF16(c.r) << 16) | ffxF32ToF16(c.g); } +FfxFloat32x2 UnpackToF2(FfxUInt32 packedRG) +{ +#ifdef FFX_HLSL + return f16tof32(FfxUInt32x2(packedRG >> 16, packedRG & 0xFFFF)); +#else + return unpackHalf2x16(packedRG).yx; +#endif +} +#if FFX_HALF +FfxUInt32 PackH2(FfxFloat16x2 c) { return (ffxF32ToF16(FfxFloat32(c.r)) << 16) | ffxF32ToF16(FfxFloat32(c.g)); } // TODO: is there a cast fp16->FfxUInt32 and skip fp16->fp32 promotion? +FfxFloat16x2 UnpackToH2(FfxUInt32 packedRG){ return FfxFloat16x2(UnpackToF2(packedRG)); } +#endif + +#ifdef FFX_HLSL +inline FfxUInt32 FlattenIndex(FfxInt32x2 Index, FfxInt32 ElementStride) +#else +FfxUInt32 FlattenIndex(FfxInt32x2 Index, FfxInt32 ElementStride) +#endif +{ + return Index.x + Index.y * ElementStride; +} + +#if BLUR_GROUPSHARED_MEMORY_SOA + void SetOutputCache(FfxInt32x2 index, FfxFloat32x3 value) + { + FfxInt32 iLDS = index.x + index.y * BLUR_TILE_SIZE_X; + OutputCache[iLDS + NUM_PIXELS_OUTPUT_CACHE * 0] = value.r; + OutputCache[iLDS + NUM_PIXELS_OUTPUT_CACHE * 1] = value.g; + OutputCache[iLDS + NUM_PIXELS_OUTPUT_CACHE * 2] = value.b; + } + FfxFloat32x3 GetOutputCache(FfxInt32x2 index) + { + FfxInt32 iLDS = index.x + index.y * FFX_BLUR_TILE_SIZE_X; + FfxFloat32x3 c; + c.r = OutputCache[iLDS + NUM_PIXELS_OUTPUT_CACHE * 0]; + c.g = OutputCache[iLDS + NUM_PIXELS_OUTPUT_CACHE * 1]; + c.b = OutputCache[iLDS + NUM_PIXELS_OUTPUT_CACHE * 2]; + return c; + } + #if BLUR_ENABLE_INPUT_CACHE + void SetInputCache(FfxInt32x2 index, FfxFloat32x3 value) + { + FfxInt32 iLDS = index.x + index.y * INPUT_CACHE_TILE_SIZE_X; + InputCache[iLDS + NUM_PIXELS_INPUT_CACHE * 0] = value.r; + InputCache[iLDS + NUM_PIXELS_INPUT_CACHE * 1] = value.g; + InputCache[iLDS + NUM_PIXELS_INPUT_CACHE * 2] = value.b; + } + FfxFloat32x3 GetInputCache(FfxInt32x2 index) + { + FfxInt32 iLDS = index.x + index.y * INPUT_CACHE_TILE_SIZE_X; + FfxFloat32x3 c; + c.r = InputCache[iLDS + NUM_PIXELS_INPUT_CACHE * 0]; + c.g = InputCache[iLDS + NUM_PIXELS_INPUT_CACHE * 1]; + c.b = InputCache[iLDS + NUM_PIXELS_INPUT_CACHE * 2]; + return c; + } + #endif // BLUR_ENABLE_INPUT_CACHE +#else + #if BLUR_GROUPSHARED_MEMORY_PK_UINT + #if FFX_HALF + void SetOutputCache(FfxInt32x2 index, FfxFloat16x3 value) + { + FfxInt32 iLDS = index.x + index.y * FFX_BLUR_TILE_SIZE_X; + OutputCacheRG[iLDS] = PackH2(value.rg); + OutputCacheB[iLDS] = value.b; + } + FfxFloat16x3 GetOutputCache(FfxInt32x2 index) + { + FfxInt32 iLDS = index.x + index.y * FFX_BLUR_TILE_SIZE_X; + FfxFloat16x2 RG = UnpackToH2(OutputCacheRG[iLDS]); + return FfxFloat16x3(RG.r, RG.g, OutputCacheB[iLDS]); + } + #else + void SetOutputCache(FfxInt32x2 index, FfxFloat32x3 value) + { + FfxInt32 iLDS = index.x + index.y * FFX_BLUR_TILE_SIZE_X; + OutputCacheRG[iLDS] = PackF2(value.rg); + OutputCacheB[iLDS] = value.b; + } + FfxFloat32x3 GetOutputCache(FfxInt32x2 index) + { + FfxInt32 iLDS = index.x + index.y * FFX_BLUR_TILE_SIZE_X; + FfxFloat32x2 RG = UnpackToF2(OutputCacheRG[iLDS]); + return FfxFloat32x3(RG.r, RG.g, OutputCacheB[iLDS]); + } + #endif // FFX_HALF + #else + #if FFX_HALF + void SetOutputCache(FfxInt32x2 index, FfxFloat16x3 value) + { + const FfxUInt32 iLDS = FlattenIndex(index, FFX_BLUR_TILE_SIZE_X); + OutputCache[iLDS] = value; + } + FfxFloat16x3 GetOutputCache(FfxInt32x2 index) + { + const FfxUInt32 iLDS = FlattenIndex(index, FFX_BLUR_TILE_SIZE_X); + return OutputCache[iLDS]; + } + #else + void SetOutputCache(FfxInt32x2 index, FfxFloat32x3 value) + { + const FfxUInt32 iLDS = FlattenIndex(index, FFX_BLUR_TILE_SIZE_X); + OutputCache[iLDS] = value; + } + FfxFloat32x3 GetOutputCache(FfxInt32x2 index) + { + const FfxUInt32 iLDS = FlattenIndex(index, FFX_BLUR_TILE_SIZE_X); + return OutputCache[iLDS]; + } + #endif // FFX_HALF + #endif // BLUR_GROUPSHARED_MEMORY_PK_UINT + + + #if BLUR_ENABLE_INPUT_CACHE + #if BLUR_GROUPSHARED_MEMORY_PK_UINT + #if FFX_HALF + void SetInputCache(FfxInt32x2 index, FfxFloat16x3 value) + { + FfxInt32 iLDS = FlattenIndex(index, INPUT_CACHE_TILE_SIZE_X); + InputCacheRG[iLDS] = PackH2(value.rg); + InputCacheB[iLDS] = value.b; + } + FfxFloat16x3 GetInputCache(FfxInt32x2 index) + { + FfxInt32 iLDS = FlattenIndex(index, INPUT_CACHE_TILE_SIZE_X); + FfxFloat16x2 RG = UnpackToH2(InputCacheRG[iLDS]); + return FfxFloat16x3(RG.r, RG.g, InputCacheB[iLDS]); + } + #else + void SetInputCache(FfxInt32x2 index, FfxFloat32x3 value) + { + //FfxInt32 iLDS = FlattenIndex(index, INPUT_CACHE_TILE_SIZE_X); + FfxInt32 iLDS = index.x + index.y * INPUT_CACHE_TILE_SIZE_X; + InputCacheRG[iLDS] = PackF2(value.rg); + InputCacheB[iLDS] = value.b; + } + FfxFloat32x3 GetInputCache(FfxInt32x2 index) + { + //FfxInt32 iLDS = FlattenIndex(index, INPUT_CACHE_TILE_SIZE_X); + FfxInt32 iLDS = index.x + index.y * INPUT_CACHE_TILE_SIZE_X; + + FfxFloat32x2 RG = UnpackToF2(InputCacheRG[iLDS]); + return FfxFloat32x3(RG.r, RG.g, InputCacheB[iLDS]); + } + #endif // FFX_HALF + #else + void SetInputCache(FfxInt32x2 index, FfxFloat32x3 value) { InputCache[index.x + index.y * INPUT_CACHE_TILE_SIZE_X].rgb = value; } + FfxFloat32x3 GetInputCache(FfxInt32x2 index) { return InputCache[index.x + index.y * INPUT_CACHE_TILE_SIZE_X].rgb; } + #endif // BLUR_GROUPSHARED_MEMORY_PK_UINT + #endif // BLUR_ENABLE_INPUT_CACHE + +#endif // BLUR_GROUPSHARED_MEMORY_SOA + + +void LDSBarrier() +{ + FFX_GROUP_MEMORY_BARRIER; +} + +// index of the LDS tile in the ring buffer +#if FFX_HALF + #if BLUR_FP16_KERNEL_LOOPS + FfxInt16 GetOutputCacheTile(FfxInt16 iTile) { return FAST_MOD16(iTile, FfxInt16(NUM_TILES_OUTPUT_CACHE)); } + void CacheInOutputTile(FfxInt32x2 threadID, FfxInt16 iTile, FfxFloat16x3 color) + { + FfxInt16 iLDSTile = GetOutputCacheTile(iTile); + FfxInt16x2 TileOffset = FfxInt16x2(0, FfxInt16(FFX_BLUR_TILE_SIZE_Y) * iLDSTile); + FfxInt16x2 iLDS = FfxInt16x2(threadID) + TileOffset; + SetOutputCache(iLDS, color); + } + FfxFloat16x3 LoadFromCachedOutputTile(FfxInt32x2 threadID, FfxInt16 iTile) + { + FfxInt16 iLDSTile = GetOutputCacheTile(iTile); + FfxInt16x2 TileOffset = FfxInt16x2(0, FfxInt16(FFX_BLUR_TILE_SIZE_Y) * iLDSTile); + FfxInt16x2 iLDS = FfxInt16x2(threadID) + TileOffset; + return GetOutputCache(iLDS); + } + #else // BLUR_FP16_KERNEL_LOOPS + FfxInt32 GetOutputCacheTile(FfxInt32 iTile) { return FAST_MOD(iTile, NUM_TILES_OUTPUT_CACHE); } + void CacheInOutputTile(FfxInt32x2 threadID, FfxInt32 iTile, FfxFloat16x3 color) + { + FfxInt32 iLDSTile = GetOutputCacheTile(iTile); + FfxInt32x2 TileOffset = FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iLDSTile); + FfxInt32x2 iLDS = threadID + TileOffset; + SetOutputCache(iLDS, color); + } + FfxFloat32x3 LoadFromCachedOutputTile(FfxInt32x2 threadID, FfxInt32 iTile) + { + FfxInt32 iLDSTile = GetOutputCacheTile(iTile); + FfxInt32x2 TileOffset = FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iLDSTile); + FfxInt32x2 iLDS = threadID + TileOffset; + return GetOutputCache(iLDS); + } + #endif // BLUR_FP16_KERNEL_LOOPS + +#else + FfxInt32 GetOutputCacheTile(FfxInt32 iTile) { return FAST_MOD(iTile, NUM_TILES_OUTPUT_CACHE); } + void CacheInOutputTile(FfxInt32x2 threadID, FfxInt32 iTile, FfxFloat32x3 color) + { + FfxInt32 iLDSTile = GetOutputCacheTile(iTile); // map image tile to LDS ring buffered tiles + FfxInt32x2 TileOffset = FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iLDSTile); // pixel offset for this tile + FfxInt32x2 iLDS = threadID + TileOffset; // 2D LDS coord based on local thread ID + SetOutputCache(iLDS, color); + } + FfxFloat32x3 LoadFromCachedOutputTile(FfxInt32x2 threadID, FfxInt32 iTile) + { + FfxInt32 iLDSTile = GetOutputCacheTile(iTile); // map image tile to LDS ring buffered tiles + FfxInt32x2 TileOffset = FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iLDSTile); // pixel offset for this tile + FfxInt32x2 iLDS = threadID + TileOffset; // 2D LDS coord based on local thread ID + return GetOutputCache(iLDS); + } +#endif // FFX_HALF + +#if BLUR_ENABLE_INPUT_CACHE + #if FFX_HALF + void CacheInInputTile(FfxInt32x2 threadID, FfxInt32 KernelOffset, FfxFloat16x3 c) + #else + void CacheInInputTile(FfxInt32x2 threadID, FfxInt32 KernelOffset, FfxFloat32x3 c) + #endif + { + FfxInt32x2 InputCacheCoord = threadID + FfxInt32x2(KernelOffset, 0) + FfxInt32x2(FFX_BLUR_KERNEL_RANGE-1, 0); + SetInputCache(InputCacheCoord, c); + } + + #if FFX_HALF + FfxFloat16x3 LoadFromCachedInputTile(FfxInt32x2 threadID, FfxInt32 KernelOffset) + #else + FfxFloat32x3 LoadFromCachedInputTile(FfxInt32x2 threadID, FfxInt32 KernelOffset) + #endif + { + FfxInt32x2 InputCacheCoord = threadID + FfxInt32x2(KernelOffset,0) + FfxInt32x2(FFX_BLUR_KERNEL_RANGE-1, 0); + return GetInputCache(InputCacheCoord); + } +#endif // BLUR_ENABLE_INPUT_CACHE + + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//============================================================================================================================== +// BLUR FUNCTIONS +//============================================================================================================================== +#if FFX_HALF +FfxFloat16x3 HorizontalBlurFromTexture(FfxInt32x2 CenterPixelLocation, FfxInt32x2 ImageSize) +{ +#if BLUR_FP16_CLAMP // this uses 4 less VGPRs but not faster + const FfxInt16 ImageSizeClampValueX = FfxInt16(ImageSize.x - 1); + FfxFloat16x3 BlurredImage = BlurLoadInput(FfxInt16x2(CenterPixelLocation)) * BlurLoadKernelWeight(0); + for (FfxInt32 i = 1; i < FFX_BLUR_KERNEL_RANGE; ++i) + { + FfxInt32x2 Offset = FfxInt32x2(i, 0); + FfxInt16x2 SampleCoordXX = FfxInt16x2(CenterPixelLocation.x + i, CenterPixelLocation.x - i); +#if !BLUR_DISABLE_CLAMP + SampleCoordXX = clamp(SampleCoordXX, FfxInt16x2(0, 0), FfxInt16x2(ImageSizeClampValueX, ImageSizeClampValueX)); +#endif + BlurredImage += BlurLoadInput(FfxInt16x2(SampleCoordXX[0], CenterPixelLocation.y)) * BlurLoadKernelWeight(i); + BlurredImage += BlurLoadInput(FfxInt16x2(SampleCoordXX[1], CenterPixelLocation.y)) * BlurLoadKernelWeight(i); + } +#else + FfxFloat16x3 BlurredImage = FfxFloat16x3(0.f, 0.f, 0.f); + for (FfxInt32 i = -FFX_BLUR_KERNEL_RANGE + 1; i < FFX_BLUR_KERNEL_RANGE; ++i) + { + FfxInt32x2 SampleCoord = CenterPixelLocation + FfxInt32x2(i, 0); // horizontal blur +#if !BLUR_DISABLE_CLAMP + SampleCoord.x = clamp(SampleCoord.x, 0, ImageSize.x-1); // clamp +#endif + FfxFloat16x3 c = BlurLoadInput(SampleCoord); + BlurredImage += c * BlurLoadKernelWeight(abs(i)); + } +#endif // BLUR_FP16_CLAMP + return BlurredImage; +} +#else // FFX_HALF +FfxFloat32x3 HorizontalBlurFromTexture(FfxInt32x2 CenterPixelLocation, FfxInt32x2 ImageSize) +{ + FfxFloat32x3 BlurredImage = FfxFloat32x3(0.f, 0.f, 0.f); + for (FfxInt32 i = -FFX_BLUR_KERNEL_RANGE + 1; i < FFX_BLUR_KERNEL_RANGE; ++i) + { + FfxInt32x2 SampleCoord = CenterPixelLocation + FfxInt32x2(i, 0); // horizontal blur +#if !BLUR_DISABLE_CLAMP + SampleCoord.x = clamp(SampleCoord.x, 0, ImageSize.x-1); // clamp +#endif + FfxFloat32x3 c = BlurLoadInput(SampleCoord); + BlurredImage += c * BlurLoadKernelWeight(abs(i)); + } + return BlurredImage; +} +#endif // FFX_HALF + +#if BLUR_ENABLE_INPUT_CACHE +#if FFX_HALF +FfxFloat16x3 HorizontalBlurFromCachedInput(FfxInt32x2 threadID) +#else +FfxFloat32x3 HorizontalBlurFromCachedInput(FfxInt32x2 threadID) +#endif +{ + #if FFX_HALF + FfxFloat16x3 BlurredImage = FfxFloat16x3(0.f, 0.f, 0.f); + #else + FfxFloat32x3 BlurredImage = FfxFloat32x3(0.f, 0.f, 0.f); + #endif // FFX_HALF + + for (FfxInt32 i = -FFX_BLUR_KERNEL_RANGE + 1; i < FFX_BLUR_KERNEL_RANGE; ++i) + { + BlurredImage += LoadFromCachedInputTile(threadID, i) * BlurLoadKernelWeight(abs(i)); + } + return BlurredImage; +} +#endif // BLUR_ENABLE_INPUT_CACHE + +#if FFX_HALF + #if BLUR_FP16_KERNEL_LOOPS + FfxFloat16x3 VerticalBlurFromCachedOutput(FfxInt32x2 ThreadID, FfxInt32x2 WorkGroupID,FfxInt16x2 CenterPixelLocation, FfxInt16x2 ImageSize) + { + const FfxInt16x2 ImageSizeClampValueXY = ImageSize.xy - FfxInt16x2(1, 1); + const FfxUInt32 iTileCount = DIV_AND_ROUND_UP(FfxUInt32(ImageSize.y), FFX_BLUR_TILE_SIZE_Y * FFX_BLUR_DISPATCH_Y); + FfxFloat16x3 value = FfxFloat16x3(0, 0, 0); + #ifndef FFX_HLSL + // For some reason using 16 bit integer for this loop in glsl does not work. It seems to be due to the use of + // a negative value as a starting value that is compared to a positive value, which seems to incorrectly cause + // the condition to always be false. + for (FfxInt32 i = (FfxInt32(-FFX_BLUR_KERNEL_RANGE) + FfxInt32(1)); i < FfxInt32(FFX_BLUR_KERNEL_RANGE); ++i) + #else + for (FfxInt16 i = (FfxInt16(-FFX_BLUR_KERNEL_RANGE) + FfxInt16(1)); i < FfxInt16(FFX_BLUR_KERNEL_RANGE); ++i) + #endif + { + FfxInt16x2 KernelSampleLocation = CenterPixelLocation + FfxInt16x2(0, i); +#if !BLUR_DISABLE_CLAMP + KernelSampleLocation.xy = clamp(KernelSampleLocation.xy, FfxInt16x2(0, 0), ImageSizeClampValueXY); +#endif + + const FfxInt16 iTile_ImageSpace = FfxInt16(KernelSampleLocation.y * BLUR_TILE_SIZE_Y_INV); + const FfxInt16 iTile = FfxInt16(iTile_ImageSpace - iTileCount * WorkGroupID.y); + FfxInt16x2 TileThreadID = FfxInt16x2(ThreadID.x, FAST_MOD16(KernelSampleLocation.y, FfxInt16(FFX_BLUR_TILE_SIZE_Y))); + + FfxFloat16x3 c = LoadFromCachedOutputTile(TileThreadID, iTile); + value += c * BlurLoadKernelWeight(abs(i)); + } + return value; + } + #else + FfxFloat16x3 VerticalBlurFromCachedOutput(FfxInt32x2 ThreadID, FfxInt32x2 WorkGroupID, FfxInt32x2 CenterPixelLocation, FfxInt32x2 ImageSize) + { + const FfxUInt32 iTileCount = DIV_AND_ROUND_UP(ImageSize.y, FFX_BLUR_TILE_SIZE_Y * FFX_BLUR_DISPATCH_Y); + FfxFloat16x3 value = FfxFloat16x3(0, 0, 0); + #if BLUR_FP16_CLAMP + const FfxInt16x2 ClampUpperLimitXY = ImageSize.xy - 1; + for (FfxInt16 i = -FFX_BLUR_KERNEL_RANGE + 1; i < FFX_BLUR_KERNEL_RANGE; ++i) + { + FfxInt16x2 KernelSampleLocation = CenterPixelLocation + FfxInt16x2(0, i); +#if !BLUR_DISABLE_CLAMP +#if BLUR_OPTIMIZED_CLAMP + bool bNegative = firstbithigh(KernelSampleLocation.x) == 31; + KernelSampleLocation.y = bNegative ? 0 : KernelSampleLocation.y; +#else + KernelSampleLocation.xy = clamp(KernelSampleLocation.xy, FfxInt16x2(0, 0), ClampUpperLimitXY); +#endif // BLUR_OPTIMIZED_CLAMP +#endif + const FfxInt16 iTile_ImageSpace = FfxInt16(KernelSampleLocation.y * FFX_BLUR_TILE_SIZE_Y_INV); + const FfxInt16 iTile = iTile_ImageSpace - iTileCount * WorkGroupID.y; + FfxInt16x2 TileThreadID = FfxInt16x2(ThreadID.x, FAST_MOD16(KernelSampleLocation.y, FfxInt16(FFX_BLUR_TILE_SIZE_Y))); + + FfxFloat16x3 c = LoadFromCachedOutputTile(TileThreadID, iTile); + value += c * BlurLoadKernelWeight(abs(i)); + } + #else + for (FfxInt32 i = -FFX_BLUR_KERNEL_RANGE + 1; i < FFX_BLUR_KERNEL_RANGE; ++i) + { + FfxInt32x2 KernelSampleLocation = CenterPixelLocation + FfxInt32x2(0, i); +#if !BLUR_DISABLE_CLAMP +#if BLUR_OPTIMIZED_CLAMP + bool bNegative = firstbithigh(KernelSampleLocation.x) == 31; + KernelSampleLocation.y = bNegative ? 0 : KernelSampleLocation.y; +#else + KernelSampleLocation.xy = clamp(KernelSampleLocation.xy, 0, ImageSize.xy-1); +#endif // BLUR_OPTIMIZED_CLAMP +#endif + + const FfxInt32 iTile_ImageSpace = FfxInt32(KernelSampleLocation.y * FFX_BLUR_TILE_SIZE_Y_INV); + const FfxInt32 iTile = iTile_ImageSpace - (iTileCountPerWorkgroup * WorkGroupID.y); + + FfxInt32x2 TileThreadID = FfxInt32x2(ThreadID.x, FAST_MOD(KernelSampleLocation.y, FFX_BLUR_TILE_SIZE_Y)); + + FfxFloat16x3 c = LoadFromCachedOutputTile(TileThreadID, iTile); + value += c * BlurLoadKernelWeight(abs(i)); + } + #endif // BLUR_FP16_CLAMP + return value; + } + #endif // BLUR_FP16_KERNEL_LOOPS +#else // FFX_HALF + FfxFloat32x3 VerticalBlurFromCachedOutput(FfxInt32x2 ThreadID, FfxInt32x2 WorkGroupID,FfxInt32x2 CenterPixelLocation, FfxInt32x2 ImageSize) + { + const FfxInt32 iTileCountPerWorkgroup = DIV_AND_ROUND_UP(ImageSize.y, FFX_BLUR_TILE_SIZE_Y * FFX_BLUR_DISPATCH_Y); + + FfxFloat32x3 value = FfxFloat32x3(0,0,0); + for (FfxInt32 i = -FFX_BLUR_KERNEL_RANGE + 1; i < FFX_BLUR_KERNEL_RANGE; ++i) + { + FfxInt32x2 KernelSampleLocation = CenterPixelLocation + FfxInt32x2(0, i); +#if !BLUR_DISABLE_CLAMP + KernelSampleLocation.xy = clamp(KernelSampleLocation.xy, FfxInt32x2(0, 0), ImageSize.xy-1); +#endif + + // which 'global' tile in the image space + const FfxInt32 iTile_ImageSpace = FfxInt32(KernelSampleLocation.y * BLUR_TILE_SIZE_Y_INV); + + // local tile in this workgroup - apply the offset to convert to local space tile coordinates + // this is needed for workgroups that have WorkgroupID.y > 0: the previous workgroup's + // tile mapping doesn't have to align with the current one's depending on the FFX_BLUR_TILE_SIZE_XY. + // e.g. WorkGroupID=1's first tile will map to 0 in local space, but could be some non-0 index + // in the local space of the previous workgroup (WorkGroupID=0). + // Not correcting for this mapping will result in a chopped image on the workgroup borders. + const FfxInt32 iTile = iTile_ImageSpace - (iTileCountPerWorkgroup * WorkGroupID.y); + + FfxInt32x2 TileThreadID = FfxInt32x2(ThreadID.x, FAST_MOD(KernelSampleLocation.y, FFX_BLUR_TILE_SIZE_Y)); + //FfxInt32x2 TileThreadID = FfxInt32x2(ThreadID.x, KernelSampleLocation.y % BLUR_TILE_SIZE_Y); + + value += LoadFromCachedOutputTile(TileThreadID, iTile) * BlurLoadKernelWeight(abs(i)); + } + return value; + } +#endif // FFX_HALF +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//============================================================================================================================== +// INPUT/OUTPUT CACHE HELPERS +//============================================================================================================================== +// +#if BLUR_ENABLE_INPUT_CACHE +// Fills the input cache with the corresponding rgion from the image + kernel extents + void FillInputCache(in FfxInt32x2 lxy, FfxInt32x2 CenterPixelLocation, FfxInt32x2 ImageSize) + { +#if FFX_HALF + FfxFloat16x3 c = FfxFloat16x3(0, 0, 0); +#else + FfxFloat32x3 c = FfxFloat32x3(0, 0, 0); +#endif + + // slide the thread group over the InputCache + const FfxInt32 iNumLoops = DIV_AND_ROUND_UP(INPUT_CACHE_TILE_SIZE_X, FFX_BLUR_TILE_SIZE_X); + for (FfxInt32 i = 0; i < iNumLoops; ++i) + { + FfxInt32x2 LDSCoord = lxy - FfxInt32x2(FFX_BLUR_KERNEL_RANGE - 1, 0) + FfxInt32x2(i * FFX_BLUR_TILE_SIZE_X, 0); + FfxInt32x2 SamplePosition = CenterPixelLocation - FfxInt32x2(FFX_BLUR_KERNEL_RANGE - 1, 0) + FfxInt32x2(i * FFX_BLUR_TILE_SIZE_X, 0); +#if !BLUR_DISABLE_CLAMP + SamplePosition.x = clamp(SamplePosition.x, 0, ImageSize.x - 1); +#endif + c = BlurLoadInput(SamplePosition); + + // clamp to LDS bounds if we're on the last iteration of the loop + if (i == iNumLoops - 1) + { + // faster than 'if (LDSCoord.x < INPUT_CACHE_TILE_SIZE_X)', avoids a vmem sync at the cost of some ALU + LDSCoord.x = clamp(LDSCoord.x, -FfxInt32x2(FFX_BLUR_KERNEL_RANGE - 1, 0), (INPUT_CACHE_TILE_SIZE_X - 1) - FfxInt32x2(FFX_BLUR_KERNEL_RANGE - 1, 0)); + } + CacheInInputTile(LDSCoord, 0, c); + } + LDSBarrier(); + } +#endif // BLUR_ENABLE_INPUT_CACHE +// Fills the output cache with the horizontally-blurred image. +void PreFillOutputCache(in FfxInt32x2 gxy, in FfxInt32x2 lxy, in FfxInt32x2 WorkGroupID, FfxInt32x2 ImageSize) +{ +#if BLUR_DEBUG_PREFILL_OUTPUT_CACHE_WITH_COLOR + FfxFloat32x3 FillColor = FfxFloat32x3(0, 0, 0); // black border color + [unroll] + for (FfxInt32 iTile = 0; iTile < NUM_TILES_OUTPUT_CACHE; ++iTile) + { + CacheInOutputTile(lxy, iTile, FillColor); + } + LDSBarrier(); +#endif + + // load from VMEM the first NUM_PREFILL_TILES_OUTPUT_CACHE tiles + // while doing the horizontal blur, going top down +#if FFX_HALF + for (FfxInt16 j = FfxInt16(0); j < FfxInt16(NUM_PREFILL_TILES_OUTPUT_CACHE); ++j) +#else + for (FfxInt32 j = 0; j < NUM_PREFILL_TILES_OUTPUT_CACHE; ++j) +#endif + { + const FfxInt32x2 ImageCoordinate = gxy + FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * j); +#if FFX_HALF + FfxFloat16x3 c = HorizontalBlurFromTexture(ImageCoordinate, ImageSize); +#else + FfxFloat32x3 c = HorizontalBlurFromTexture(ImageCoordinate, ImageSize); +#endif + CacheInOutputTile(lxy, j, c); + } + +#if FFX_BLUR_DISPATCH_Y != 1 + // for any workgroup that doesn't start frop the top of the image, + // fill the cache from the tail, going upwards in the image space + if (WorkGroupID.y != 0) + { + +#if FFX_HALF + FfxFloat16x3 c = FfxFloat16x3(0, 0, 0); +#else + FfxFloat32x3 c = FfxFloat32x3(0, 0, 0); +#endif +#if FFX_HALF + for (FfxInt16 j = FfxInt16(1); j < FfxInt16(NUM_PREFILL_TILES_OUTPUT_CACHE+1 + (DIV_AND_ROUND_UP(FFX_BLUR_KERNEL_RANGE, FFX_BLUR_TILE_SIZE_Y))); ++j) +#else + for (FfxInt32 j = 1; j < NUM_PREFILL_TILES_OUTPUT_CACHE+1 + (DIV_AND_ROUND_UP(FFX_BLUR_KERNEL_RANGE, FFX_BLUR_TILE_SIZE_Y)); ++j) +#endif + { + const FfxInt32x2 ImageCoordinate = gxy - FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * j); + + #if BLUR_ENABLE_INPUT_CACHE + FillInputCache(lxy, ImageCoordinate, ImageSize); + c = HorizontalBlurFromCachedInput(lxy); + #else + c = HorizontalBlurFromTexture(ImageCoordinate, ImageSize); + #endif + +#if FFX_HALF + CacheInOutputTile(lxy, (FfxInt16(NUM_TILES_OUTPUT_CACHE) - j), c); +#else + CacheInOutputTile(lxy, (NUM_TILES_OUTPUT_CACHE - j), c); +#endif + } + } +#endif + + LDSBarrier(); // OutputCache Sync: Read -> Write ========================================= +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//============================================================================================================================== +// BLUR GAUSSIAN BLUR ALGORITHM +//============================================================================================================================== + +/// ffxBlur: The main idea of the algorithm is to utilize a number of tiles (8x8) that are cached on the groupshared memory +/// in a ring-buffer fashion to speed up texture lookups in a hand-optimized compute shader. +/// The tiles are defined by the FFX_BLUR_TILE_SIZE_X and FFX_BLUR_TILE_SIZE_Y defines, and are typically 8x8 pixels. +/// The image is horizontally blurred while being cached on the groupshared memory, +/// and when all the groupshared tiles are filled, a vertical blur pass is done on the groupshared memory +/// and the result is stored in the UAV as the final destination. +/// +/// The algorithm is as follows: +/// - Pre-fill LDS with 8x8 tiles, storing vertical tiles, containing horizontally blurred color +/// - Loop until the entire image is covered: +/// - Run a vertical blur pass on the LDS and output to final destination UAV +/// - Re-fill LDS with horizontally-blurred data +/// - Finish off the remaining last row/section of the image +/// +/// @param [in] GlobalThreadID The SV_DispatchThreadID.xy or gl_GlobalInvocationID.xy. +/// @param [in] WorkGroupLocalThreadID The SV_GroupThreadID.xy or gl_LocalInvocationID.xy. +/// @param [in] WorkGroupID The SV_GroupID.xy or gl_WorkGroupID.xy. +/// @param [in] ImageSize The two dimensional size of the input and output image. +/// +/// @ingroup FfxGPUBlur +void ffxBlur( + in FfxInt32x2 GlobalThreadID, + in FfxInt32x2 WorkGroupLocalThreadID, + in FfxInt32x2 WorkGroupID, + FfxInt32x2 ImageSize) +{ + // Each threadgroup processes a number of tiles of size FFX_BLUR_TILE_SIZE_Y * FFX_BLUR_TILE_SIZE_X + // This number depends on the image height and the vertical dimension (_Y) of the FFX_BLUR_TILE_SIZE + //const FfxUInt32 iTileCount = DIV_AND_ROUND_UP(ImageSize.y, FFX_BLUR_TILE_SIZE_Y); + const FfxUInt32 iTileCount = + DIV_AND_ROUND_UP( + ImageSize.y, + FFX_BLUR_TILE_SIZE_Y * FFX_BLUR_DISPATCH_Y); + + FfxInt32x2 gxy = FfxInt32x2( + WorkGroupID.x * FFX_BLUR_TILE_SIZE_X + WorkGroupLocalThreadID.x + , WorkGroupLocalThreadID.y + WorkGroupID.y * iTileCount * FFX_BLUR_TILE_SIZE_Y + ); + FfxInt32x2 lxy = WorkGroupLocalThreadID; + + if (gxy.x >= ImageSize.x) + return; + + //------------------------------------------------------------------------------------------------- + // STEP #1 + //------------------------------------------------------------------------------------------------- + // Pre-fill the output cache with a few tiles of horizontally blurred image. + // The tile count to pre-fill is a function of kernel width and TileSizeY. + PreFillOutputCache(gxy, lxy, WorkGroupID, ImageSize); // doesn't sync waves + + + //------------------------------------------------------------------------------------------------- + // STEP #2 + //------------------------------------------------------------------------------------------------- + // loop through the tiles and write out to UAV as we go from top to down + FfxInt32 iTileOutput = 0; + +#if FFX_HALF + FfxFloat16x3 c = FfxFloat16x3(0, 0, 0); +#else + FfxFloat32x3 c = FfxFloat32x3(0, 0, 0); +#endif + for (; iTileOutput < iTileCount - NUM_PREFILL_TILES_OUTPUT_CACHE; ++iTileOutput) + { + // index of next tile that we'll cache the output to + // It runs ahead of the tile we will be writing out to UAV by NUM_PREFILL_TILES_OUTPUT_CACHE tiles + FfxInt32 iNextTileOutputCache = iTileOutput + NUM_PREFILL_TILES_OUTPUT_CACHE; + const FfxInt32x2 HorizontalBlurInputCoord = gxy + FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iNextTileOutputCache); + + // run horizontal blur & cache the next output tile + #if BLUR_ENABLE_INPUT_CACHE + FillInputCache(lxy, HorizontalBlurInputCoord, ImageSize); + c = HorizontalBlurFromCachedInput(lxy); + #else + // Number of image_load instructions will scale with FFX_BLUR_OPTION_KERNEL_DIMENSION. + c = HorizontalBlurFromTexture(HorizontalBlurInputCoord, ImageSize); + #endif // BLUR_ENABLE_INPUT_CACHE + +#if FFX_HALF + CacheInOutputTile(lxy, FfxInt16(iNextTileOutputCache), c); +#else + CacheInOutputTile(lxy, iNextTileOutputCache, c); +#endif + + LDSBarrier(); // OutputCache Sync: Write -> Read ========================================= + + // Start writing out the pixel value which has its final value + // convolved from the pixels aready in the LDS section. + const FfxInt32x2 OutputCoord = gxy + FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iTileOutput); +#if FFX_HALF + c = VerticalBlurFromCachedOutput(lxy, WorkGroupID, FfxInt16x2(OutputCoord), FfxInt16x2(ImageSize)); +#else + c = VerticalBlurFromCachedOutput(lxy, WorkGroupID, OutputCoord, ImageSize); +#endif + BlurStoreOutput(OutputCoord, c); + LDSBarrier(); // OutputCache Sync: Read -> Write ========================================= + } + + + //------------------------------------------------------------------------------------------------- + // STEP #3 + //------------------------------------------------------------------------------------------------- + // fill in the remaining last tiles (= loop for NUM_PREFILL_TILES_OUTPUT_CACHE) + for (; iTileOutput < iTileCount; ++iTileOutput) + { + const FfxInt32x2 OutputCoord = gxy + FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iTileOutput); + if (iTileOutput >= iTileCount - NUM_PREFILL_TILES_OUTPUT_CACHE) + { + FfxInt32 iNextTileOutputCache = iTileOutput + NUM_PREFILL_TILES_OUTPUT_CACHE; + const FfxInt32x2 HorizontalBlurInputCoord = gxy + FfxInt32x2(0, FFX_BLUR_TILE_SIZE_Y * iNextTileOutputCache); + + // run horizontal blur & cache the next output tile +#if BLUR_ENABLE_INPUT_CACHE + FillInputCache(lxy, HorizontalBlurInputCoord, ImageSize); + c = HorizontalBlurFromCachedInput(lxy); +#else + // Number of image_load instructions will scale with FFX_BLUR_OPTION_KERNEL_DIMENSION. + c = HorizontalBlurFromTexture(HorizontalBlurInputCoord, ImageSize); +#endif // BLUR_ENABLE_INPUT_CACHE + +#if FFX_HALF + CacheInOutputTile(lxy, FfxInt16(iNextTileOutputCache), c); +#else + CacheInOutputTile(lxy, iNextTileOutputCache, c); +#endif + + LDSBarrier(); // OutputCache Sync: Write -> Read ========================================= + } +#if FFX_HALF + c = VerticalBlurFromCachedOutput(lxy, WorkGroupID, FfxInt16x2(OutputCoord), FfxInt16x2(ImageSize)); +#else + c = VerticalBlurFromCachedOutput(lxy, WorkGroupID, OutputCoord, ImageSize); +#endif + BlurStoreOutput(OutputCoord, c); + } +} + +#endif // !FFX_CPU +#endif // FFX_BLUR_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_blur.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_blur.h new file mode 100644 index 00000000..225fbe0f --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_blur.h @@ -0,0 +1,65 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +FFX_BLUR_KERNEL_TYPE BlurLoadKernelWeight(FfxInt32 iKernelIndex) +{ + return FfxBlurLoadKernelWeight(iKernelIndex); +} + +#if FFX_HALF + +void BlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat16x3 color) +{ + FfxBlurStoreOutput(outPxCoord, color); +} + +FfxFloat16x3 BlurLoadInput(FfxInt16x2 inPxCoord) +{ + return FfxBlurLoadInput(inPxCoord); +} + +#else // FFX_HALF + +void BlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat32x3 color) +{ + FfxBlurStoreOutput(outPxCoord, color); +} + +// DXIL generates load/sync/store blocks for each channel, ticket open: https://ontrack-internal.amd.com/browse/SWDEV-303837 +// this is 10x times slower!!! +//void Blur_StoreOutput(FfxInt32x2 outPxCoord, FfxFloat32x3 color) { texColorOutput[outPxCoord].rgb = color; } +FfxFloat32x3 BlurLoadInput(FfxInt32x2 inPxCoord) +{ + return FfxBlurLoadInput(inPxCoord); +} + +#endif // !FFX_HALF + +#include "blur/ffx_blur.h" + + +void ffxBlurPass(FfxInt32x2 DispatchThreadID, FfxInt32x2 LocalThreadId, FfxInt32x2 WorkGroupId) +{ + ffxBlur(DispatchThreadID, LocalThreadId, WorkGroupId, ImageSize()); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_callbacks_glsl.h new file mode 100644 index 00000000..3f8bcd9b --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_callbacks_glsl.h @@ -0,0 +1,216 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_blur_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #if defined(FFX_PREFER_WAVE64) + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#if defined(FFX_BLUR_BIND_CB_BLUR) + layout (set = 0, binding = FFX_BLUR_BIND_CB_BLUR, std140) uniform cbBLUR_t + { + FfxInt32x2 imageSize; + } cbBLUR; +#endif + +FfxInt32x2 ImageSize() +{ + return cbBLUR.imageSize; +} + +// SRVs +#if defined FFX_BLUR_BIND_SRV_INPUT_SRC + layout (set = 0, binding = FFX_BLUR_BIND_SRV_INPUT_SRC) uniform texture2D r_input_src; +#endif + +// UAV declarations +#if defined FFX_BLUR_BIND_UAV_OUTPUT + layout (set = 0, binding = FFX_BLUR_BIND_UAV_OUTPUT, rgba32f) uniform image2D rw_output; +#endif + +// FFX_BLUR_OPTION_KERNEL_DIMENSION to be defined by the client application +// App should define e.g the following for 5x5 blur: +// #define FFX_BLUR_OPTION_KERNEL_DIMENSION 5 +#ifndef FFX_BLUR_OPTION_KERNEL_DIMENSION +#error Please define FFX_BLUR_OPTION_KERNEL_DIMENSION +#endif + +// FFX_BLUR_KERNEL_RANGE is center + half width of the kernel +// +// consider a blur kernel 5x5 - '*' indicates the center of the kernel +// FFX_BLUR_OPTION_KERNEL_DIMENSION=5 +// |---------------| +// x x x x x +// x x x x x +// x x x* x x +// x x x x x +// x x x x x +// +// +// as separate 1D kernels +// +// x x x* x x +// |-------| +// FFX_BLUR_KERNEL_RANGE +// +#define FFX_BLUR_KERNEL_RANGE (((FFX_BLUR_OPTION_KERNEL_DIMENSION - 1) / 2) + 1) +#define FFX_BLUR_KERNEL_RANGE_MINUS1 (FFX_BLUR_KERNEL_RANGE - 1) + +// +// FFX-Blur Callback definitions +// +#if FFX_HALF +#define FFX_BLUR_KERNEL_TYPE FfxFloat16 +#else +#define FFX_BLUR_KERNEL_TYPE FfxFloat32 +#endif + +FFX_BLUR_KERNEL_TYPE FfxBlurLoadKernelWeight(FfxInt32 iKernelIndex) +{ +// GAUSSIAN BLUR 1D KERNELS +// +//---------------------------------------------------------------------------------------------------------------------------------- +//---------------------------------------------------------------------------------------------------------------------------------- +// Kernel Size: [3, 21]: odd numbers +// Kernels are pregenerated using three different sigma values. +// Larger sigmas are better for larger kernels. + const FFX_BLUR_KERNEL_TYPE kernel_weights[FFX_BLUR_KERNEL_RANGE] = +#if FFX_BLUR_OPTION_KERNEL_PERMUTATION == 0 +// Sigma: 1.6 +#if FFX_BLUR_KERNEL_RANGE == 2 + { FFX_BLUR_KERNEL_TYPE(0.3765770884), FFX_BLUR_KERNEL_TYPE(0.3117114558) }; +#elif FFX_BLUR_KERNEL_RANGE == 3 + { FFX_BLUR_KERNEL_TYPE(0.2782163289), FFX_BLUR_KERNEL_TYPE(0.230293397), FFX_BLUR_KERNEL_TYPE(0.1305984385) }; +#elif FFX_BLUR_KERNEL_RANGE == 4 + { FFX_BLUR_KERNEL_TYPE(0.2525903052), FFX_BLUR_KERNEL_TYPE(0.2090814714), FFX_BLUR_KERNEL_TYPE(0.1185692428), FFX_BLUR_KERNEL_TYPE(0.0460541333) }; +#elif FFX_BLUR_KERNEL_RANGE == 5 + { FFX_BLUR_KERNEL_TYPE(0.2465514351), FFX_BLUR_KERNEL_TYPE(0.2040828004), FFX_BLUR_KERNEL_TYPE(0.115734517), FFX_BLUR_KERNEL_TYPE(0.0449530818), FFX_BLUR_KERNEL_TYPE(0.0119538834) }; +#elif FFX_BLUR_KERNEL_RANGE == 6 + { FFX_BLUR_KERNEL_TYPE(0.245483563), FFX_BLUR_KERNEL_TYPE(0.2031988699), FFX_BLUR_KERNEL_TYPE(0.1152332436), FFX_BLUR_KERNEL_TYPE(0.0447583794), FFX_BLUR_KERNEL_TYPE(0.0119021083), FFX_BLUR_KERNEL_TYPE(0.0021656173) }; +#elif FFX_BLUR_KERNEL_RANGE == 7 + { FFX_BLUR_KERNEL_TYPE(0.2453513488), FFX_BLUR_KERNEL_TYPE(0.2030894296), FFX_BLUR_KERNEL_TYPE(0.1151711805), FFX_BLUR_KERNEL_TYPE(0.0447342732), FFX_BLUR_KERNEL_TYPE(0.011895698), FFX_BLUR_KERNEL_TYPE(0.0021644509), FFX_BLUR_KERNEL_TYPE(0.0002692935) }; +#elif FFX_BLUR_KERNEL_RANGE == 8 + { FFX_BLUR_KERNEL_TYPE(0.2453401155), FFX_BLUR_KERNEL_TYPE(0.2030801313), FFX_BLUR_KERNEL_TYPE(0.1151659074), FFX_BLUR_KERNEL_TYPE(0.044732225), FFX_BLUR_KERNEL_TYPE(0.0118951533), FFX_BLUR_KERNEL_TYPE(0.0021643518), FFX_BLUR_KERNEL_TYPE(0.0002692811), FFX_BLUR_KERNEL_TYPE(2.28922E-05) }; +#elif FFX_BLUR_KERNEL_RANGE == 9 + { FFX_BLUR_KERNEL_TYPE(0.2453394635), FFX_BLUR_KERNEL_TYPE(0.2030795916), FFX_BLUR_KERNEL_TYPE(0.1151656014), FFX_BLUR_KERNEL_TYPE(0.0447321061), FFX_BLUR_KERNEL_TYPE(0.0118951217), FFX_BLUR_KERNEL_TYPE(0.0021643461), FFX_BLUR_KERNEL_TYPE(0.0002692804), FFX_BLUR_KERNEL_TYPE(2.28922E-05), FFX_BLUR_KERNEL_TYPE(1.3287E-06) }; +#elif FFX_BLUR_KERNEL_RANGE == 10 + { FFX_BLUR_KERNEL_TYPE(0.2453394377), FFX_BLUR_KERNEL_TYPE(0.2030795703), FFX_BLUR_KERNEL_TYPE(0.1151655892), FFX_BLUR_KERNEL_TYPE(0.0447321014), FFX_BLUR_KERNEL_TYPE(0.0118951205), FFX_BLUR_KERNEL_TYPE(0.0021643458), FFX_BLUR_KERNEL_TYPE(0.0002692804), FFX_BLUR_KERNEL_TYPE(2.28922E-05), FFX_BLUR_KERNEL_TYPE(1.3287E-06), FFX_BLUR_KERNEL_TYPE(5.26E-08) }; +#elif FFX_BLUR_KERNEL_RANGE == 11 + { FFX_BLUR_KERNEL_TYPE(0.2453394371), FFX_BLUR_KERNEL_TYPE(0.2030795697), FFX_BLUR_KERNEL_TYPE(0.1151655889), FFX_BLUR_KERNEL_TYPE(0.0447321013), FFX_BLUR_KERNEL_TYPE(0.0118951204), FFX_BLUR_KERNEL_TYPE(0.0021643458), FFX_BLUR_KERNEL_TYPE(0.0002692804), FFX_BLUR_KERNEL_TYPE(2.28922E-05), FFX_BLUR_KERNEL_TYPE(1.3287E-06), FFX_BLUR_KERNEL_TYPE(5.26E-08), FFX_BLUR_KERNEL_TYPE(1.4E-09) }; +#endif +#elif FFX_BLUR_OPTION_KERNEL_PERMUTATION == 1 +// Sigma: 2.8 +#if FFX_BLUR_KERNEL_RANGE == 2 + { FFX_BLUR_KERNEL_TYPE(0.3474999743), FFX_BLUR_KERNEL_TYPE(0.3262500129) }; +#elif FFX_BLUR_KERNEL_RANGE == 3 + { FFX_BLUR_KERNEL_TYPE(0.2256541468), FFX_BLUR_KERNEL_TYPE(0.2118551763), FFX_BLUR_KERNEL_TYPE(0.1753177504) }; +#elif FFX_BLUR_KERNEL_RANGE == 4 + { FFX_BLUR_KERNEL_TYPE(0.1796953063), FFX_BLUR_KERNEL_TYPE(0.1687067636), FFX_BLUR_KERNEL_TYPE(0.1396108926), FFX_BLUR_KERNEL_TYPE(0.1018346906) }; +#elif FFX_BLUR_KERNEL_RANGE == 5 + { FFX_BLUR_KERNEL_TYPE(0.1588894947), FFX_BLUR_KERNEL_TYPE(0.1491732476), FFX_BLUR_KERNEL_TYPE(0.1234462081), FFX_BLUR_KERNEL_TYPE(0.0900438796), FFX_BLUR_KERNEL_TYPE(0.0578919173) }; +#elif FFX_BLUR_KERNEL_RANGE == 6 + { FFX_BLUR_KERNEL_TYPE(0.1491060676), FFX_BLUR_KERNEL_TYPE(0.1399880866), FFX_BLUR_KERNEL_TYPE(0.1158451582), FFX_BLUR_KERNEL_TYPE(0.0844995374), FFX_BLUR_KERNEL_TYPE(0.054327293), FFX_BLUR_KERNEL_TYPE(0.0307868909) }; +#elif FFX_BLUR_KERNEL_RANGE == 7 + { FFX_BLUR_KERNEL_TYPE(0.1446570603), FFX_BLUR_KERNEL_TYPE(0.1358111404), FFX_BLUR_KERNEL_TYPE(0.1123885856), FFX_BLUR_KERNEL_TYPE(0.0819782513), FFX_BLUR_KERNEL_TYPE(0.0527062824), FFX_BLUR_KERNEL_TYPE(0.0298682757), FFX_BLUR_KERNEL_TYPE(0.0149189344) }; +#elif FFX_BLUR_KERNEL_RANGE == 8 + { FFX_BLUR_KERNEL_TYPE(0.1427814521), FFX_BLUR_KERNEL_TYPE(0.1340502275), FFX_BLUR_KERNEL_TYPE(0.110931367), FFX_BLUR_KERNEL_TYPE(0.0809153299), FFX_BLUR_KERNEL_TYPE(0.0520228983), FFX_BLUR_KERNEL_TYPE(0.0294810068), FFX_BLUR_KERNEL_TYPE(0.0147254971), FFX_BLUR_KERNEL_TYPE(0.0064829474) }; +#elif FFX_BLUR_KERNEL_RANGE == 9 + { FFX_BLUR_KERNEL_TYPE(0.1420666821), FFX_BLUR_KERNEL_TYPE(0.1333791663), FFX_BLUR_KERNEL_TYPE(0.1103760399), FFX_BLUR_KERNEL_TYPE(0.0805102644), FFX_BLUR_KERNEL_TYPE(0.0517624694), FFX_BLUR_KERNEL_TYPE(0.0293334236), FFX_BLUR_KERNEL_TYPE(0.0146517806), FFX_BLUR_KERNEL_TYPE(0.0064504935), FFX_BLUR_KERNEL_TYPE(0.0025030212) }; +#elif FFX_BLUR_KERNEL_RANGE == 10 + { FFX_BLUR_KERNEL_TYPE(0.1418238658), FFX_BLUR_KERNEL_TYPE(0.1331511984), FFX_BLUR_KERNEL_TYPE(0.1101873883), FFX_BLUR_KERNEL_TYPE(0.0803726585), FFX_BLUR_KERNEL_TYPE(0.0516739985), FFX_BLUR_KERNEL_TYPE(0.0292832877), FFX_BLUR_KERNEL_TYPE(0.0146267382), FFX_BLUR_KERNEL_TYPE(0.0064394685), FFX_BLUR_KERNEL_TYPE(0.0024987432), FFX_BLUR_KERNEL_TYPE(0.0008545858) }; +#elif FFX_BLUR_KERNEL_RANGE == 11 + { FFX_BLUR_KERNEL_TYPE(0.1417508359), FFX_BLUR_KERNEL_TYPE(0.1330826344), FFX_BLUR_KERNEL_TYPE(0.1101306491), FFX_BLUR_KERNEL_TYPE(0.0803312719), FFX_BLUR_KERNEL_TYPE(0.0516473898), FFX_BLUR_KERNEL_TYPE(0.0292682088), FFX_BLUR_KERNEL_TYPE(0.0146192064), FFX_BLUR_KERNEL_TYPE(0.0064361526), FFX_BLUR_KERNEL_TYPE(0.0024974565), FFX_BLUR_KERNEL_TYPE(0.0008541457), FFX_BLUR_KERNEL_TYPE(0.0002574667) }; +#endif +#elif FFX_BLUR_OPTION_KERNEL_PERMUTATION == 2 +// Sigma: 4 +#if FFX_BLUR_KERNEL_RANGE == 2 + { FFX_BLUR_KERNEL_TYPE(0.3402771036), FFX_BLUR_KERNEL_TYPE(0.3298614482) }; +#elif FFX_BLUR_KERNEL_RANGE == 3 + { FFX_BLUR_KERNEL_TYPE(0.2125433723), FFX_BLUR_KERNEL_TYPE(0.2060375614), FFX_BLUR_KERNEL_TYPE(0.1876907525) }; +#elif FFX_BLUR_KERNEL_RANGE == 4 + { FFX_BLUR_KERNEL_TYPE(0.1608542243), FFX_BLUR_KERNEL_TYPE(0.1559305837), FFX_BLUR_KERNEL_TYPE(0.1420455978), FFX_BLUR_KERNEL_TYPE(0.1215967064) }; +#elif FFX_BLUR_KERNEL_RANGE == 5 + { FFX_BLUR_KERNEL_TYPE(0.1345347233), FFX_BLUR_KERNEL_TYPE(0.1304167051), FFX_BLUR_KERNEL_TYPE(0.1188036266), FFX_BLUR_KERNEL_TYPE(0.1017006505), FFX_BLUR_KERNEL_TYPE(0.0818116562) }; +#elif FFX_BLUR_KERNEL_RANGE == 6 + { FFX_BLUR_KERNEL_TYPE(0.1197258568), FFX_BLUR_KERNEL_TYPE(0.1160611281), FFX_BLUR_KERNEL_TYPE(0.1057263555), FFX_BLUR_KERNEL_TYPE(0.090505984), FFX_BLUR_KERNEL_TYPE(0.0728062644), FFX_BLUR_KERNEL_TYPE(0.0550373395) }; +#elif FFX_BLUR_KERNEL_RANGE == 7 + { FFX_BLUR_KERNEL_TYPE(0.1110429695), FFX_BLUR_KERNEL_TYPE(0.1076440182), FFX_BLUR_KERNEL_TYPE(0.0980587551), FFX_BLUR_KERNEL_TYPE(0.0839422118), FFX_BLUR_KERNEL_TYPE(0.0675261302), FFX_BLUR_KERNEL_TYPE(0.0510458624), FFX_BLUR_KERNEL_TYPE(0.0362615375) }; +#elif FFX_BLUR_KERNEL_RANGE == 8 + { FFX_BLUR_KERNEL_TYPE(0.1059153311), FFX_BLUR_KERNEL_TYPE(0.1026733334), FFX_BLUR_KERNEL_TYPE(0.0935306896), FFX_BLUR_KERNEL_TYPE(0.0800660068), FFX_BLUR_KERNEL_TYPE(0.0644079717), FFX_BLUR_KERNEL_TYPE(0.0486887143), FFX_BLUR_KERNEL_TYPE(0.0345870861), FFX_BLUR_KERNEL_TYPE(0.0230885324) }; +#elif FFX_BLUR_KERNEL_RANGE == 9 + { FFX_BLUR_KERNEL_TYPE(0.1029336421), FFX_BLUR_KERNEL_TYPE(0.0997829119), FFX_BLUR_KERNEL_TYPE(0.0908976484), FFX_BLUR_KERNEL_TYPE(0.0778120183), FFX_BLUR_KERNEL_TYPE(0.0625947824), FFX_BLUR_KERNEL_TYPE(0.0473180477), FFX_BLUR_KERNEL_TYPE(0.0336134033), FFX_BLUR_KERNEL_TYPE(0.0224385526), FFX_BLUR_KERNEL_TYPE(0.0140758142) }; +#elif FFX_BLUR_KERNEL_RANGE == 10 + { FFX_BLUR_KERNEL_TYPE(0.1012533395), FFX_BLUR_KERNEL_TYPE(0.0981540422), FFX_BLUR_KERNEL_TYPE(0.089413823), FFX_BLUR_KERNEL_TYPE(0.0765418045), FFX_BLUR_KERNEL_TYPE(0.0615729768), FFX_BLUR_KERNEL_TYPE(0.0465456216), FFX_BLUR_KERNEL_TYPE(0.0330646936), FFX_BLUR_KERNEL_TYPE(0.0220722627), FFX_BLUR_KERNEL_TYPE(0.0138460388), FFX_BLUR_KERNEL_TYPE(0.0081620671) }; +#elif FFX_BLUR_KERNEL_RANGE == 11 + { FFX_BLUR_KERNEL_TYPE(0.1003459368), FFX_BLUR_KERNEL_TYPE(0.0972744146), FFX_BLUR_KERNEL_TYPE(0.0886125226), FFX_BLUR_KERNEL_TYPE(0.0758558594), FFX_BLUR_KERNEL_TYPE(0.0610211779), FFX_BLUR_KERNEL_TYPE(0.0461284934), FFX_BLUR_KERNEL_TYPE(0.0327683775), FFX_BLUR_KERNEL_TYPE(0.0218744576), FFX_BLUR_KERNEL_TYPE(0.0137219546), FFX_BLUR_KERNEL_TYPE(0.008088921), FFX_BLUR_KERNEL_TYPE(0.0044808529) }; +#endif +#else +#error FFX_BLUR_OPTION_KERNEL_PERMUTATION is not a valid value. +#endif // FFX_BLUR_OPTION_KERNEL_PERMUTATIONs + + return kernel_weights[iKernelIndex]; +} + +#if FFX_HALF + +#if defined (FFX_BLUR_BIND_UAV_OUTPUT) +void FfxBlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat16x3 color) +{ + imageStore(rw_output, outPxCoord, FfxFloat16x4(color, 1)); +} +#endif // #if defined (FFX_BLUR_BIND_UAV_OUTPUT) + +#if defined (FFX_BLUR_BIND_SRV_INPUT_SRC) +FfxFloat16x3 FfxBlurLoadInput(FfxInt16x2 inPxCoord) +{ + return FfxFloat16x3(texelFetch(r_input_src, inPxCoord, 0).rgb); +} +#endif // #if defined FFX_BLUR_BIND_SRV_INPUT_SRC + +#else // FFX_HALF + +#if defined (FFX_BLUR_BIND_UAV_OUTPUT) +void FfxBlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat32x3 color) +{ + imageStore(rw_output, outPxCoord, FfxFloat32x4(color, 1)); +} +#endif // #if defined FFX_BLUR_BIND_UAV_OUTPUT + +// DXIL generates load/sync/store blocks for each channel, ticket open: https://ontrack-internal.amd.com/browse/SWDEV-303837 +// this is 10x times slower!!! +//void Blur_StoreOutput(FfxInt32x2 outPxCoord, FfxFloat32x3 color) { texColorOutput[outPxCoord].rgb = color; } +#if defined (FFX_BLUR_BIND_SRV_INPUT_SRC) +FfxFloat32x3 FfxBlurLoadInput(FfxInt32x2 inPxCoord) +{ + return texelFetch(r_input_src, inPxCoord, 0).rgb; +} +#endif // #if defined FFX_BLUR_BIND_SRV_INPUT_SRC + +#endif // !FFX_HALF + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_callbacks_hlsl.h new file mode 100644 index 00000000..f74c42ff --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_callbacks_hlsl.h @@ -0,0 +1,254 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_blur_resources.h" + +#if defined(FFX_GPU) + +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler + +#include "ffx_core.h" + +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(FFX_GPU) +#pragma warning(disable: 3205) // conversion from larger type to smaller +#endif // #if defined(FFX_GPU) + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_BLUR_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_BLUR_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_BLUR_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(FFX_BLUR_BIND_CB_BLUR) + cbuffer cbBLUR : FFX_BLUR_DECLARE_CB(FFX_BLUR_BIND_CB_BLUR) + { + FfxInt32x2 imageSize; + #define FFX_BLUR_CONSTANT_BUFFER_1_SIZE 2 // Number of 32-bit values. This must be kept in sync with the cbBLUR size. + }; +#else + #define imageSize 0 +#endif + +#define FFX_BLUR_ROOTSIG_STRINGIFY(p) FFX_BLUR_ROOTSIG_STR(p) +#define FFX_BLUR_ROOTSIG_STR(p) #p +#define FFX_BLUR_ROOTSIG [RootSignature("DescriptorTable(UAV(u0, numDescriptors = " FFX_BLUR_ROOTSIG_STRINGIFY(FFX_BLUR_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_BLUR_ROOTSIG_STRINGIFY(FFX_BLUR_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0)" )] + +#if defined(FFX_BLUR_EMBED_ROOTSIG) +#define FFX_BLUR_EMBED_ROOTSIG_CONTENT FFX_BLUR_ROOTSIG +#else +#define FFX_BLUR_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_BLUR_EMBED_ROOTSIG + +FfxInt32x2 ImageSize() +{ + return imageSize; +} + +// SRVs +#if defined FFX_BLUR_BIND_SRV_INPUT_SRC + #if FFX_HALF + Texture2D r_input_src : FFX_BLUR_DECLARE_SRV(FFX_BLUR_BIND_SRV_INPUT_SRC); + #else + Texture2D r_input_src : FFX_BLUR_DECLARE_SRV(FFX_BLUR_BIND_SRV_INPUT_SRC); + #endif // FFX_HALF +#endif + + // UAV declarations +#if defined FFX_BLUR_BIND_UAV_OUTPUT + #if FFX_HALF + RWTexture2D rw_output : FFX_BLUR_DECLARE_UAV(FFX_BLUR_BIND_UAV_OUTPUT); + #else + RWTexture2D rw_output : FFX_BLUR_DECLARE_UAV(FFX_BLUR_BIND_UAV_OUTPUT); + #endif // FFX_HALF +#endif + +// FFX_BLUR_OPTION_KERNEL_DIMENSION to be defined by the client application +// App should define e.g the following for 5x5 blur: +// #define FFX_BLUR_OPTION_KERNEL_DIMENSION 5 +#ifndef FFX_BLUR_OPTION_KERNEL_DIMENSION +#error Please define FFX_BLUR_OPTION_KERNEL_DIMENSION +#endif + +// FFX_BLUR_KERNEL_RANGE is center + half width of the kernel +// +// consider a blur kernel 5x5 - '*' indicates the center of the kernel +// FFX_BLUR_OPTION_KERNEL_DIMENSION=5 +// |---------------| +// x x x x x +// x x x x x +// x x x* x x +// x x x x x +// x x x x x +// +// +// as separate 1D kernels +// +// x x x* x x +// |-------| +// FFX_BLUR_KERNEL_RANGE +// +#define FFX_BLUR_KERNEL_RANGE (((FFX_BLUR_OPTION_KERNEL_DIMENSION - 1) / 2) + 1) +#define FFX_BLUR_KERNEL_RANGE_MINUS1 (FFX_BLUR_KERNEL_RANGE - 1) + +// +// FFX-Blur Callback definitions +// +#if FFX_HALF + #define FFX_BLUR_KERNEL_TYPE FfxFloat16 +#else + #define FFX_BLUR_KERNEL_TYPE FfxFloat32 +#endif + +inline FFX_BLUR_KERNEL_TYPE FfxBlurLoadKernelWeight(FfxInt32 iKernelIndex) +{ +// GAUSSIAN BLUR 1D KERNELS +// +//---------------------------------------------------------------------------------------------------------------------------------- +// Kernel Size: [3, 21]: odd numbers +// Kernels are pregenerated using three different sigma values. +// Larger sigmas are better for larger kernels. + const FFX_BLUR_KERNEL_TYPE kernel_weights[FFX_BLUR_KERNEL_RANGE] = +#if FFX_BLUR_OPTION_KERNEL_PERMUTATION == 0 +// Sigma: 1.6 +#if FFX_BLUR_KERNEL_RANGE == 2 + { 0.3765770884, 0.3117114558 }; +#elif FFX_BLUR_KERNEL_RANGE == 3 + { 0.2782163289, 0.230293397, 0.1305984385 }; +#elif FFX_BLUR_KERNEL_RANGE == 4 + { 0.2525903052, 0.2090814714, 0.1185692428, 0.0460541333 }; +#elif FFX_BLUR_KERNEL_RANGE == 5 + { 0.2465514351, 0.2040828004, 0.115734517, 0.0449530818, 0.0119538834 }; +#elif FFX_BLUR_KERNEL_RANGE == 6 + { 0.245483563, 0.2031988699, 0.1152332436, 0.0447583794, 0.0119021083, 0.0021656173 }; +#elif FFX_BLUR_KERNEL_RANGE == 7 + { 0.2453513488, 0.2030894296, 0.1151711805, 0.0447342732, 0.011895698, 0.0021644509, 0.0002692935 }; +#elif FFX_BLUR_KERNEL_RANGE == 8 + { 0.2453401155, 0.2030801313, 0.1151659074, 0.044732225, 0.0118951533, 0.0021643518, 0.0002692811, 2.28922E-05 }; +#elif FFX_BLUR_KERNEL_RANGE == 9 + { 0.2453394635, 0.2030795916, 0.1151656014, 0.0447321061, 0.0118951217, 0.0021643461, 0.0002692804, 2.28922E-05, 1.3287E-06 }; +#elif FFX_BLUR_KERNEL_RANGE == 10 + { 0.2453394377, 0.2030795703, 0.1151655892, 0.0447321014, 0.0118951205, 0.0021643458, 0.0002692804, 2.28922E-05, 1.3287E-06, 5.26E-08 }; +#elif FFX_BLUR_KERNEL_RANGE == 11 + { 0.2453394371, 0.2030795697, 0.1151655889, 0.0447321013, 0.0118951204, 0.0021643458, 0.0002692804, 2.28922E-05, 1.3287E-06, 5.26E-08, 1.4E-09 }; +#endif +#elif FFX_BLUR_OPTION_KERNEL_PERMUTATION == 1 +// Sigma: 2.8 +#if FFX_BLUR_KERNEL_RANGE == 2 + { 0.3474999743, 0.3262500129 }; +#elif FFX_BLUR_KERNEL_RANGE == 3 + { 0.2256541468, 0.2118551763, 0.1753177504 }; +#elif FFX_BLUR_KERNEL_RANGE == 4 + { 0.1796953063, 0.1687067636, 0.1396108926, 0.1018346906 }; +#elif FFX_BLUR_KERNEL_RANGE == 5 + { 0.1588894947, 0.1491732476, 0.1234462081, 0.0900438796, 0.0578919173 }; +#elif FFX_BLUR_KERNEL_RANGE == 6 + { 0.1491060676, 0.1399880866, 0.1158451582, 0.0844995374, 0.054327293, 0.0307868909 }; +#elif FFX_BLUR_KERNEL_RANGE == 7 + { 0.1446570603, 0.1358111404, 0.1123885856, 0.0819782513, 0.0527062824, 0.0298682757, 0.0149189344 }; +#elif FFX_BLUR_KERNEL_RANGE == 8 + { 0.1427814521, 0.1340502275, 0.110931367, 0.0809153299, 0.0520228983, 0.0294810068, 0.0147254971, 0.0064829474 }; +#elif FFX_BLUR_KERNEL_RANGE == 9 + { 0.1420666821, 0.1333791663, 0.1103760399, 0.0805102644, 0.0517624694, 0.0293334236, 0.0146517806, 0.0064504935, 0.0025030212 }; +#elif FFX_BLUR_KERNEL_RANGE == 10 + { 0.1418238658, 0.1331511984, 0.1101873883, 0.0803726585, 0.0516739985, 0.0292832877, 0.0146267382, 0.0064394685, 0.0024987432, 0.0008545858 }; +#elif FFX_BLUR_KERNEL_RANGE == 11 + { 0.1417508359, 0.1330826344, 0.1101306491, 0.0803312719, 0.0516473898, 0.0292682088, 0.0146192064, 0.0064361526, 0.0024974565, 0.0008541457, 0.0002574667 }; +#endif +#elif FFX_BLUR_OPTION_KERNEL_PERMUTATION == 2 +// Sigma: 4 +#if FFX_BLUR_KERNEL_RANGE == 2 + { 0.3402771036, 0.3298614482 }; +#elif FFX_BLUR_KERNEL_RANGE == 3 + { 0.2125433723, 0.2060375614, 0.1876907525 }; +#elif FFX_BLUR_KERNEL_RANGE == 4 + { 0.1608542243, 0.1559305837, 0.1420455978, 0.1215967064 }; +#elif FFX_BLUR_KERNEL_RANGE == 5 + { 0.1345347233, 0.1304167051, 0.1188036266, 0.1017006505, 0.0818116562 }; +#elif FFX_BLUR_KERNEL_RANGE == 6 + { 0.1197258568, 0.1160611281, 0.1057263555, 0.090505984, 0.0728062644, 0.0550373395 }; +#elif FFX_BLUR_KERNEL_RANGE == 7 + { 0.1110429695, 0.1076440182, 0.0980587551, 0.0839422118, 0.0675261302, 0.0510458624, 0.0362615375 }; +#elif FFX_BLUR_KERNEL_RANGE == 8 + { 0.1059153311, 0.1026733334, 0.0935306896, 0.0800660068, 0.0644079717, 0.0486887143, 0.0345870861, 0.0230885324 }; +#elif FFX_BLUR_KERNEL_RANGE == 9 + { 0.1029336421, 0.0997829119, 0.0908976484, 0.0778120183, 0.0625947824, 0.0473180477, 0.0336134033, 0.0224385526, 0.0140758142 }; +#elif FFX_BLUR_KERNEL_RANGE == 10 + { 0.1012533395, 0.0981540422, 0.089413823, 0.0765418045, 0.0615729768, 0.0465456216, 0.0330646936, 0.0220722627, 0.0138460388, 0.0081620671 }; +#elif FFX_BLUR_KERNEL_RANGE == 11 + { 0.1003459368, 0.0972744146, 0.0886125226, 0.0758558594, 0.0610211779, 0.0461284934, 0.0327683775, 0.0218744576, 0.0137219546, 0.008088921, 0.0044808529 }; +#endif +#else +#error FFX_BLUR_OPTION_KERNEL_PERMUTATION is not a valid value. +#endif // FFX_BLUR_OPTION_KERNEL_PERMUTATIONs + + return kernel_weights[iKernelIndex]; +} + +#if FFX_HALF + + #if defined (FFX_BLUR_BIND_UAV_OUTPUT) + void FfxBlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat16x3 color) + { + rw_output[outPxCoord] = FfxFloat16x4(color, 1); + } + #endif // #if defined (FFX_BLUR_BIND_UAV_OUTPUT) + + #if defined (FFX_BLUR_BIND_SRV_INPUT_SRC) + FfxFloat16x3 FfxBlurLoadInput(FfxInt16x2 inPxCoord) + { + return r_input_src[inPxCoord].rgb; + } + #endif // #if defined (FFX_BLUR_BIND_SRV_INPUT_SRC) + +#else // FFX_HALF + + #if defined (FFX_BLUR_BIND_UAV_OUTPUT) + void FfxBlurStoreOutput(FfxInt32x2 outPxCoord, FfxFloat32x3 color) + { + rw_output[outPxCoord] = FfxFloat32x4(color, 1); + } + #endif // #if defined (FFX_BLUR_BIND_UAV_OUTPUT) + + #if defined (FFX_BLUR_BIND_SRV_INPUT_SRC) + FfxFloat32x3 FfxBlurLoadInput(FfxInt32x2 inPxCoord) + { + return r_input_src[inPxCoord].rgb; + } + #endif // #if defined (FFX_BLUR_BIND_SRV_INPUT_SRC) + +#endif // !FFX_HALF + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_resources.h new file mode 100644 index 00000000..636de9b6 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/blur/ffx_blur_resources.h @@ -0,0 +1,39 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BLUR_RESOURCES_H +#define FFX_BLUR_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) + +#define FFX_BLUR_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_BLUR_RESOURCE_IDENTIFIER_INPUT_SRC 1 +#define FFX_BLUR_RESOURCE_IDENTIFIER_OUTPUT 2 + +#define FFX_BLUR_RESOURCE_IDENTIFIER_COUNT 3 + +// CBV resource definitions +#define FFX_BLUR_CONSTANTBUFFER_IDENTIFIER_BLUR 0 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif // FFX_BLUR_RESOURCES_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/CMakeCompileBrixelizerShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/CMakeCompileBrixelizerShaders.txt new file mode 100644 index 00000000..c361b207 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/CMakeCompileBrixelizerShaders.txt @@ -0,0 +1,74 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(BRIXELIZER_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(BRIXELIZER_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/brixelizer") + +if (NOT BRIXELIZER_SHADER_EXT) + set(BRIXELIZER_SHADER_EXT *) +endif() + +file(GLOB BRIXELIZER_SHADERS + "shaders/brixelizer/ffx_brixelizer_cascade_ops_build_tree_aabb_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_clear_brick_storage_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_clear_build_counters_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_clear_job_counter_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_clear_ref_counters_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_coarse_culling_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_compact_references_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_compress_brick_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_emit_sdf_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_free_cascade_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_initialize_cascade_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_invalidate_job_areas_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_mark_cascade_uninitialized_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_reset_cascade_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_scan_jobs_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_scan_references_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_scroll_cascade_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_cascade_ops_voxelize_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_clear_brick_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_clear_counters_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_collect_clear_bricks_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_collect_dirty_bricks_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_eikonal_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_merge_bricks_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_merge_cascades_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_prepare_clear_bricks_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_prepare_eikonal_args_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_context_ops_prepare_merge_bricks_args_pass.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_debug_draw_aabb_tree.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_debug_draw_instance_aabbs.${BRIXELIZER_SHADER_EXT}" + "shaders/brixelizer/ffx_brixelizer_debug_visualization_pass.${BRIXELIZER_SHADER_EXT}") + +# compile all the shaders +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${BRIXELIZER_BASE_ARGS}" "${BRIXELIZER_API_BASE_ARGS}" "" "${BRIXELIZER_INCLUDE_ARGS}" + "${BRIXELIZER_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" BRIXELIZER_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${BRIXELIZER_PERMUTATION_OUTPUTS}") \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_brick_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_brick_common.h new file mode 100644 index 00000000..ee1f6283 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_brick_common.h @@ -0,0 +1,117 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_BRICK_COMMON_H +#define FFX_BRIXELIZER_BRICK_COMMON_H + +#include "ffx_brixelizer_common.h" + +FfxUInt32 FfxBrixelizerBrickGetIndex(FfxUInt32 brick_id) +{ + return brick_id & FFX_BRIXELIZER_BRICK_ID_MASK; +} + +FfxUInt32x3 FfxBrixelizerWrapCoords(FfxInt32x3 clipmap_offset, FfxUInt32 wrap_mask, FfxUInt32x3 voxel_coord) +{ + return (voxel_coord + FfxUInt32x3(clipmap_offset)) & FfxUInt32x3(wrap_mask, wrap_mask, wrap_mask); +} + +FfxUInt32x3 FfxBrixelizerWrapCoords(FfxBrixelizerCascadeInfo cinfo, FfxUInt32x3 voxel_coord) +{ + return (voxel_coord + cinfo.clipmap_offset) & FfxUInt32x3(FFX_BRIXELIZER_CASCADE_WRAP_MASK, FFX_BRIXELIZER_CASCADE_WRAP_MASK, FFX_BRIXELIZER_CASCADE_WRAP_MASK); +} + +FfxUInt32 FfxBrixelizerLoadBrickIDUniform(FfxUInt32 voxel_flat_id, FfxUInt32 cascade_id) +{ + return LoadCascadeBrickMapArrayUniform(cascade_id, voxel_flat_id); +} + +FfxUInt32x3 FfxBrixelizerGetSDFAtlasOffset(FfxUInt32 brick_id) +{ + FfxUInt32 dim = 8; + FfxUInt32 offset = FfxBrixelizerBrickGetIndex(brick_id); + FfxUInt32 bperdim = FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE / dim; + FfxUInt32 xoffset = offset % bperdim; + FfxUInt32 yoffset = (offset / bperdim) % bperdim; + FfxUInt32 zoffset = (offset / bperdim / bperdim); + return FfxUInt32x3(xoffset, yoffset, zoffset) * dim; +} + +struct FfxBxAtlasBounds +{ + FfxUInt32 brick_dim; + FfxFloat32x3 uvw_min; + FfxFloat32x3 uvw_max; +}; + +FfxBxAtlasBounds FfxBrixelizerGetAtlasBounds(FfxUInt32 brick_id) +{ + FfxUInt32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxBxAtlasBounds bounds; + bounds.brick_dim = FfxUInt32(8); + bounds.uvw_min = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(0.5)) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + bounds.uvw_max = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(float(8.0 - 0.5))) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + return bounds; +} + +FfxFloat32 FfxBrixelizerSampleBrixelDistance(FfxUInt32 brick_id, FfxFloat32x3 uvw) +{ + FfxUInt32 brick_dim = FfxUInt32(8); + FfxFloat32 idim = FfxFloat32(1.0) / FfxFloat32(brick_dim); + FfxUInt32 texture_offset = FfxBrixelizerBrickGetIndex(brick_id); + + // Offset for 7x7x7 region + + FfxUInt32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxFloat32x3 uvw_min = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(0.5)) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + FfxFloat32x3 uvw_max = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(FfxFloat32(brick_dim - FfxFloat32(0.5)))) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + uvw = ffxLerp(uvw_min, uvw_max, uvw); + + return SampleSDFAtlas(uvw); +} + +FfxFloat32 FfxBrixelizerSampleBrixelDistance(FfxFloat32x3 uvw_min, FfxFloat32x3 uvw_max, FfxFloat32x3 uvw) +{ + uvw = ffxLerp(uvw_min, uvw_max, uvw); + return SampleSDFAtlas(uvw); +} + +FfxFloat32x3 FfxBrixelizerGetBrixelGrad(FfxFloat32x3 uvw_min, FfxFloat32x3 uvw_max, FfxFloat32x3 uvw) { + FfxFloat32 EPS = FfxFloat32(0.25) / (FfxFloat32(8.0) - FfxFloat32(1.0)); + + FfxFloat32x4 k = FfxFloat32x4(1.0, 1.0, 1.0, 0.0); + if (uvw.x > FfxFloat32(0.5)) k.x = -k.x; + if (uvw.y > FfxFloat32(0.5)) k.y = -k.y; + if (uvw.z > FfxFloat32(0.5)) k.z = -k.z; + FfxFloat32 fcenter = FfxBrixelizerSampleBrixelDistance(uvw_min, uvw_max, uvw); + FfxFloat32x3 grad = normalize( + k.xww * (FfxBrixelizerSampleBrixelDistance(uvw_min, uvw_max, uvw + k.xww * EPS) - fcenter) + + k.wyw * (FfxBrixelizerSampleBrixelDistance(uvw_min, uvw_max, uvw + k.wyw * EPS) - fcenter) + + k.wwz * (FfxBrixelizerSampleBrixelDistance(uvw_min, uvw_max, uvw + k.wwz * EPS) - fcenter) + ); + if (any(isnan(grad))) { + return normalize(uvw - FFX_BROADCAST_FLOAT32X3(0.5)); + } + return grad; +} + +#endif // FFX_BRIXELIZER_BRICK_COMMON_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_brick_common_private.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_brick_common_private.h new file mode 100644 index 00000000..7cc6e1f0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_brick_common_private.h @@ -0,0 +1,58 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_BRICK_COMMON_PRIVATE_H +#define FFX_BRIXELIZER_BRICK_COMMON_PRIVATE_H + +#include "ffx_brixelizer_common_private.h" +#include "ffx_brixelizer_brick_common.h" + +FfxUInt32 FfxBrixelizerVoxelGetIndex(FfxUInt32 voxel_id) +{ + return voxel_id & FFX_BRIXELIZER_VOXEL_ID_MASK; +} + +FfxUInt32 FfxBrixelizerGetVoxelCascade(FfxUInt32 voxel_id) +{ + return voxel_id >> FFX_BRIXELIZER_CASCADE_ID_SHIFT; +} + +FfxUInt32 WrapFlatCoords(FfxBrixelizerCascadeInfo CINFO, FfxUInt32 voxel_idx) +{ + return FfxBrixelizerFlattenPOT((FfxBrixelizerUnflattenPOT(voxel_idx, FFX_BRIXELIZER_CASCADE_DEGREE) + CINFO.clipmap_offset) & FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_WRAP_MASK), FFX_BRIXELIZER_CASCADE_DEGREE); +} + +FfxUInt32 FfxBrixelizerMakeBrickID(FfxUInt32 offset) +{ + return offset; +} + +FfxFloat32x3 FfxBrixelizerGetBrixelGrad(FfxUInt32 brick_id, FfxFloat32x3 uvw) +{ + FfxFloat32 EPS = FfxFloat32(0.1) / (FfxFloat32(8.0) - FfxFloat32(1.0)); + FfxUInt32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxFloat32x3 uvw_min = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(0.5)) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + FfxFloat32x3 uvw_max = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(float(8.0 - float(0.5)))) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + return FfxBrixelizerGetBrixelGrad(uvw_min, uvw_max, uvw); +} + +#endif // FFX_BRIXELIZER_BRICK_COMMON_PRIVATE_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_build_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_build_common.h new file mode 100644 index 00000000..31ee3559 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_build_common.h @@ -0,0 +1,39 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_BUILD_COMMON_H +#define FFX_BRIXELIZER_BUILD_COMMON_H + +#include "ffx_brixelizer_common_private.h" + +void FfxBrixelizerMarkBrickFree(FfxUInt32 brick_id) +{ + StoreBricksVoxelMap(FfxBrixelizerBrickGetIndex(brick_id), FFX_BRIXELIZER_INVALID_ID); +} + +FfxUInt32 FfxBrixelizerLoadBrickVoxelID(FfxUInt32 brick_id) +{ + return LoadBricksVoxelMap(FfxBrixelizerBrickGetIndex(brick_id)); +} +// FfxUInt32 FfxBrixelizerLoadBrickCascadeID(FfxUInt32 brick_id) { return LoadBricksVoxelMap(FfxBrixelizerBrickGetIndex(brick_id)) >> FFX_BRIXELIZER_CASCADE_ID_SHIFT; } + +#endif // FFX_BRIXELIZER_BUILD_COMMON_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_callbacks_glsl.h new file mode 100644 index 00000000..18ec5a2f --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_callbacks_glsl.h @@ -0,0 +1,1287 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_CALLBACKS_GLSL_H +#define FFX_BRIXELIZER_CALLBACKS_GLSL_H + +#include "ffx_brixelizer_resources.h" +#include "ffx_brixelizer_host_gpu_shared.h" +#include "ffx_brixelizer_host_gpu_shared_private.h" + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#define FFX_BRIXELIZER_SIZEOF_UINT 4 + +// CBVs + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO + layout (set = 0, binding = BRIXELIZER_BIND_CB_CASCADE_INFO, std140) uniform BrixelizerCascadeInfo_t + { + FfxBrixelizerCascadeInfo data; + } cbBrixelizerCascadeInfo; +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO + layout (set = 0, binding = BRIXELIZER_BIND_CB_CONTEXT_INFO, std140) uniform BrixelizerContextInfo_t + { + FfxBrixelizerContextInfo data; + } cbBrixelizerContextInfo; +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO + layout (set = 0, binding = BRIXELIZER_BIND_CB_BUILD_INFO, std140) uniform BrixelizerBuildInfo_t + { + FfxBrixelizerBuildInfo data; + } cbBrixelizerBuildInfo; +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO + layout (set = 0, binding = BRIXELIZER_BIND_CB_DEBUG_INFO, std140) uniform BrixelizerDebugInfo_t + { + FfxBrixelizerDebugInfo data; + } cbBrixelizerDebugInfo; +#endif + +// SRVs + +#if defined BRIXELIZER_BIND_SRV_DEBUG_INSTANCE_ID_BUFFER + layout (set = 0, binding = BRIXELIZER_BIND_SRV_DEBUG_INSTANCE_ID_BUFFER, std430) readonly buffer BrixelizerDebugInstanceID_t + { + FfxUInt32 data[]; + } r_debug_instance_id; +#endif + +#if defined BRIXELIZER_BIND_SRV_JOB_BUFFER + layout (set = 0, binding = BRIXELIZER_BIND_SRV_JOB_BUFFER, std430) readonly buffer BrixelizerJob_t + { + FfxBrixelizerBrixelizationJob data[]; + } r_job_buffer; +#endif + +#if defined BRIXELIZER_BIND_SRV_JOB_INDEX_BUFFER + layout (set = 0, binding = BRIXELIZER_BIND_SRV_JOB_INDEX_BUFFER, std430) readonly buffer BrixelizerJobIndex_t + { + FfxUInt32 data[]; + } r_job_index_buffer; +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_INFO_BUFFER + layout (set = 0, binding = BRIXELIZER_BIND_SRV_INSTANCE_INFO_BUFFER, std430) readonly buffer BrixelizerInstanceInfo_t + { + FfxBrixelizerInstanceInfo data[]; + } r_instance_info_buffer; +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_TRANSFORM_BUFFER + layout (set = 0, binding = BRIXELIZER_BIND_SRV_INSTANCE_TRANSFORM_BUFFER, std430) readonly buffer BrixelizerInstanceTransform_t + { + FfxFloat32x4 data[]; + } r_instance_transform_buffer; +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS + layout (set = 1, binding = BRIXELIZER_BIND_SRV_VERTEX_BUFFERS, std430) readonly buffer BrixelizerVertexBuffer_t + { + FfxUInt32 data[]; + } r_vertex_buffers[FFX_BRIXELIZER_STATIC_CONFIG_MAX_VERTEX_BUFFERS]; +#endif + +#if defined BRIXELIZER_BIND_SRV_SDF_ATLAS + layout (set = 0, binding = BRIXELIZER_BIND_SRV_SDF_ATLAS) uniform texture3D r_sdf_atlas; +#endif + +// UAVs + +#if defined BRIXELIZER_BIND_UAV_DEBUG_AABBS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_DEBUG_AABBS, std430) buffer BrixelizerDebugAABBs_t + { + FfxBrixelizerDebugAABB data[]; + } rw_debug_aabbs; +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE, std430) buffer BrixelizerCascadeAABBTree_t + { + FfxUInt32 data[]; + } rw_cascade_aabbtree; +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP, std430) buffer BrixelizerCascadeBrickMap_t + { + FfxUInt32 data[]; + } rw_cascade_brick_map; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS, std430) buffer BrixelizerScratchCounters_t + { + FfxUInt32 data[]; + } rw_scratch_counters; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP, std430) buffer BrixelizerScratchIndexSwap_t + { + FfxUInt32 data[]; + } rw_scratch_index_swap; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER, std430) buffer BrixelizerScratchVoxelAllocationFailCounter_t + { + FfxUInt32 data[]; + } rw_scratch_voxel_allocation_fail_counter; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE, std430) buffer BrixelizerScratchBricksStorage_t + { + FfxUInt32 data[]; + } rw_scratch_bricks_storage; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS, std430) buffer BrixelizerScratchBricksStorageOffsets_t + { + FfxUInt32 data[]; + } rw_scratch_bricks_storage_offsets; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST, std430) buffer BrixelizerScratchBricksCompressionList_t + { + FfxUInt32 data[]; + } rw_scratch_bricks_compression_list; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST, std430) buffer BrixelizerScratchBricksClearList_t + { + FfxUInt32 data[]; + } rw_scratch_bricks_clear_list; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS, std430) buffer BrixelizerScratchJobCounters_t + { + FfxUInt32 data[]; + } rw_scratch_job_counters; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN, std430) buffer BrixelizerScratchJobCountersScan_t + { + FfxUInt32 data[]; + } rw_scratch_job_counters_scan; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN, std430) buffer BrixelizerScratchJobGlobalCountersScan_t + { + FfxUInt32 data[]; + } rw_scratch_job_global_counters_scan; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES, std430) buffer BrixelizerScratchCR1References_t + { + FfxBrixelizerTriangleReference data[]; + } rw_scratch_cr1_references; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES, std430) buffer BrixelizerScratchCR1CompactedReferences_t + { + FfxUInt32 data[]; + } rw_scratch_cr1_compacted_references; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS, std430) buffer BrixelizerScratchCR1RefCounters_t + { + FfxUInt32 data[]; + } rw_scratch_cr1_ref_counters; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_INSTANCE_REF_COUNTERS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_INSTANCE_REF_COUNTERS, std430) buffer BrixelizerScratchCR1InstanceRefCounters_t + { + FfxUInt32 data[]; + } rw_scratch_cr1_instance_ref_counters; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN, std430) buffer BrixelizerScratchCR1RefCounterScan_t + { + FfxUInt32 data[]; + } rw_scratch_cr1_ref_counter_scan; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN, std430) buffer BrixelizerScratchCR1RefGlobalScan_t + { + FfxUInt32 data[]; + } rw_scratch_cr1_ref_global_scan; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN, std430) buffer BrixelizerScratchCR1StampScan_t + { + FfxUInt32 data[]; + } rw_scratch_cr1_stamp_scan; +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN, std430) buffer BrixelizerScratchCR1StampGlobalScan_t + { + FfxUInt32 data[]; + } rw_scratch_cr1_stamp_global_scan; +#endif + +#if defined BRIXELIZER_BIND_UAV_INDIRECT_ARGS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_INDIRECT_ARGS, std430) buffer BrixelizerIndirectArgs_t + { + FfxUInt32 data[]; + } rw_indirect_args_1; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP, std430) buffer BrixelizerContextBricksVoxelMap_t + { + FfxUInt32 data[]; + } rw_bctx_bricks_voxel_map; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB, std430) buffer BrixelizerContextBricksAABB_t + { + FfxUInt32 data[]; + } rw_bctx_bricks_aabb; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST, std430) buffer BrixelizerContextBricksFreeList_t + { + FfxUInt32 data[]; + } rw_bctx_bricks_free_list; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST, std430) buffer BrixelizerContextBricksClearList_t + { + FfxUInt32 data[]; + } rw_bctx_bricks_clear_list; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST, std430) buffer BrixelizerContextBricksEikonalList_t + { + FfxUInt32 data[]; + } rw_bctx_bricks_eikonal_list; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST, std430) buffer BrixelizerContextBricksMergeList_t + { + FfxUInt32 data[]; + } rw_bctx_bricks_merge_list; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS, std430) buffer BrixelizerContextBricksEikonalCounters_t + { + FfxUInt32 data[]; + } rw_bctx_bricks_eikonal_counters; +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS, std430) buffer BrixelizerContextCounters_t + { + FfxUInt32 data[]; + } rw_bctx_counters; +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS, std430) buffer BrixelizerCascadeBrickMaps_t + { + FfxUInt32 data[]; + } rw_cascade_brick_maps[24]; +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES + layout (set = 0, binding = BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES, std430) buffer BrixelizerCascadeAABBTrees_t + { + FfxUInt32 data[]; + } rw_cascade_aabbtrees[24]; +#endif + +#if defined BRIXELIZER_BIND_UAV_SDF_ATLAS + layout (set = 0, binding = BRIXELIZER_BIND_UAV_SDF_ATLAS, r8) uniform image3D rw_sdf_atlas; +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_OUTPUT + layout (set = 0, binding = BRIXELIZER_BIND_UAV_DEBUG_OUTPUT, rgba16f) uniform image2D rw_debug_output; +#endif + +layout (set = 0, binding = 1000) uniform sampler g_wrap_linear_sampler; + +FfxBrixelizerDebugAABB GetDebugAABB(FfxUInt32 idx); +void StoreDebugAABB(FfxUInt32 idx, FfxBrixelizerDebugAABB aabb); +FfxUInt32 GetDebugInstanceID(FfxUInt32 idx); +FfxBrixelizerCascadeInfo GetCascadeInfo(); +FfxUInt32x3 GetCascadeInfoClipmapOffset(); +FfxUInt32 GetCascadeInfoIndex(); +FfxFloat32x3 GetCascadeInfoGridMin(); +FfxFloat32x3 GetCascadeInfoGridMax(); +FfxFloat32 GetCascadeInfoVoxelSize(); +FfxInt32x3 GetCascadeInfoClipmapInvalidationOffset(); +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 idx); +FfxUInt32 GetContextInfoNumBricks(); +FfxUInt32x3 GetContextInfoCascadeClipmapOffset(FfxUInt32 cascade_index); +FfxBrixelizerBuildInfo GetBuildInfo(); +FfxUInt32 GetBuildInfoDoInitialization(); +FfxInt32 GetBuildInfoTreeIteration(); +FfxUInt32 GetBuildInfoNumJobs(); +FfxUInt32 GetDebugInfoMaxAABBs(); +FfxFloat32x4x4 GetDebugInfoInvView(); +FfxFloat32x4x4 GetDebugInfoInvProj(); +FfxFloat32 GetDebugInfoPreviewSDFSolveEpsilon(); +FfxUInt32 GetDebugInfoStartCascadeIndex(); +FfxUInt32 GetDebugInfoEndCascadeIndex(); +FfxFloat32 GetDebugInfoTMin(); +FfxFloat32 GetDebugInfoTMax(); +FfxUInt32 GetDebugInfoDebugState(); +FfxBrixelizerBrixelizationJob LoadBrixelizationJob(FfxUInt32 idx); +FfxUInt32 LoadJobIndex(FfxUInt32 idx); +FfxBrixelizerInstanceInfo LoadInstanceInfo(FfxUInt32 index); +FfxFloat32x3x4 LoadInstanceTransform(FfxUInt32 idx); +FfxUInt32 LoadVertexBufferUInt(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxUInt32x2 LoadVertexBufferUInt2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxUInt32x3 LoadVertexBufferUInt3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32x2 LoadVertexBufferFloat2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32x3 LoadVertexBufferFloat3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32x4 LoadVertexBufferFloat4(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw); +FfxUInt32 LoadCascadeBrickMap(FfxUInt32 elementIdx); +void StoreCascadeBrickMap(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +void StoreCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchCounter(FfxUInt32 counter); +void StoreScratchCounter(FfxUInt32 counter, FfxUInt32 value); +void IncrementScratchCounter(FfxUInt32 counter, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxUInt32x2 LoadScratchIndexSwapUInt2(FfxUInt32 elementIdx); +FfxFloat32x3 LoadScratchIndexSwapFloat3(FfxUInt32 elementIdx); +void StoreScratchIndexSwapUInt2(FfxUInt32 elementIdx, FfxUInt32x2 value); +void StoreScratchIndexSwapFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value); +void GetScratchIndexSwapDimensions(inout FfxUInt32 size); +FfxUInt32 LoadScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx); +void StoreScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksStorage(FfxUInt32 elementIdx); +void StoreScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value); +void GetScratchBricksStorageDimensions(inout FfxUInt32 size); +void MinScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksStorageOffsets(FfxUInt32 elementIdx); +void StoreScratchBricksStorageOffsets(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksCompressionList(FfxUInt32 elementIdx); +void StoreScratchBricksCompressionList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksClearList(FfxUInt32 elementIdx); +void StoreScratchBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchJobCounter(FfxUInt32 counterIdx); +void StoreScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value); +void IncrementScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value); +FfxUInt32 LoadScratchJobCountersScan(FfxUInt32 elementIdx); +void StoreScratchJobCountersScan(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadGlobalJobTriangleCounterScan(FfxUInt32 elementIdx); +void StoreGlobalJobTriangleCounterScan(FfxUInt32 elementIdx, FfxUInt32 scan); +FfxBrixelizerTriangleReference LoadScratchCR1Reference(FfxUInt32 elementIdx); +void StoreScratchCR1Reference(FfxUInt32 elementIdx, FfxBrixelizerTriangleReference ref); +void GetScratchMaxReferences(inout FfxUInt32 size); +FfxUInt32 LoadScratchCR1CompactedReferences(FfxUInt32 elementIdx); +void StoreScratchCR1CompactedReferences(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchCR1RefCounter(FfxUInt32 elementIdx); +void StoreScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value); +void IncrementScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxUInt32 LoadScratchCR1RefCounterScan(FfxUInt32 elementIdx); +void StoreScratchCR1RefCounterScan(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadVoxelReferenceGroupSum(FfxUInt32 elementIdx); +void StoreVoxelReferenceGroupSum(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchCR1StampScan(FfxUInt32 elementIdx); +void StoreScratchCR1StampScan(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadStampGroupSum(FfxUInt32 elementIdx); +void StoreStampGroupSum(FfxUInt32 elementIdx, FfxUInt32 value); +void StoreIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIdx); +void StoreBricksVoxelMap(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIdx); +void StoreBricksAABB(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksFreeList(FfxUInt32 elementIdx); +void StoreBricksFreeList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx); +void StoreBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksDirtyList(FfxUInt32 elementIdx); +void StoreBricksDirtyList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksMergeList(FfxUInt32 elementIdx); +void StoreBricksMergeList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksEikonalCounters(FfxUInt32 elementIdx); +void StoreBricksEikonalCounters(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx); +void StoreContextCounter(FfxUInt32 elementIdx, FfxUInt32 value); +void IncrementContextCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxFloat32x3 LoadCascadeAABBTreeFloat3(FfxUInt32 elementIdx); +FfxUInt32 LoadCascadeAABBTreeUInt(FfxUInt32 elementIdx); +void StoreCascadeAABBTreeUInt(FfxUInt32 elementIdx, FfxUInt32 value); +void StoreCascadeAABBTreeFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value); +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIdx); +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIdx); +FfxFloat32 LoadSDFAtlas(FfxUInt32x3 coord); +void StoreSDFAtlas(FfxUInt32x3 coord, FfxFloat32 value); +void StoreDebugOutput(FfxUInt32x2 coord, FfxFloat32x3 outputValue); +void GetDebugOutputDimensions(inout FfxUInt32 width, inout FfxUInt32 height); + +#if defined BRIXELIZER_BIND_UAV_DEBUG_AABBS +FfxBrixelizerDebugAABB GetDebugAABB(FfxUInt32 idx) +{ + return rw_debug_aabbs.data[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_AABBS +void StoreDebugAABB(FfxUInt32 idx, FfxBrixelizerDebugAABB aabb) +{ + rw_debug_aabbs.data[idx] = aabb; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_DEBUG_INSTANCE_ID_BUFFER +FfxUInt32 GetDebugInstanceID(FfxUInt32 idx) +{ + return r_debug_instance_id.data[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxBrixelizerCascadeInfo GetCascadeInfo() +{ + return cbBrixelizerCascadeInfo.data; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxUInt32x3 GetCascadeInfoClipmapOffset() +{ + return cbBrixelizerCascadeInfo.data.clipmap_offset; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxUInt32 GetCascadeInfoIndex() +{ + return cbBrixelizerCascadeInfo.data.index; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxFloat32x3 GetCascadeInfoGridMin() +{ + return cbBrixelizerCascadeInfo.data.grid_min; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxFloat32x3 GetCascadeInfoGridMax() +{ + return cbBrixelizerCascadeInfo.data.grid_max; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxFloat32 GetCascadeInfoVoxelSize() +{ + return cbBrixelizerCascadeInfo.data.voxel_size; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxInt32x3 GetCascadeInfoClipmapInvalidationOffset() +{ + return cbBrixelizerCascadeInfo.data.clipmap_invalidation_offset; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 idx) +{ + return cbBrixelizerContextInfo.data.cascades[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxUInt32 GetContextInfoNumBricks() +{ + return cbBrixelizerContextInfo.data.num_bricks; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxUInt32x3 GetContextInfoCascadeClipmapOffset(FfxUInt32 cascade_index) +{ + return cbBrixelizerContextInfo.data.cascades[cascade_index].clipmap_offset; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxBrixelizerBuildInfo GetBuildInfo() +{ + return cbBrixelizerBuildInfo.data; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxUInt32 GetBuildInfoDoInitialization() +{ + return cbBrixelizerBuildInfo.data.do_initialization; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxInt32 GetBuildInfoTreeIteration() +{ + return cbBrixelizerBuildInfo.data.tree_iteration; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxUInt32 GetBuildInfoNumJobs() +{ + return cbBrixelizerBuildInfo.data.num_jobs; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoMaxAABBs() +{ + return cbBrixelizerDebugInfo.data.max_aabbs; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32x4x4 GetDebugInfoInvView() +{ + return cbBrixelizerDebugInfo.data.inv_view; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32x4x4 GetDebugInfoInvProj() +{ + return cbBrixelizerDebugInfo.data.inv_proj; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32 GetDebugInfoPreviewSDFSolveEpsilon() +{ + return cbBrixelizerDebugInfo.data.preview_sdf_solve_eps; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoStartCascadeIndex() +{ + return cbBrixelizerDebugInfo.data.start_cascade_idx; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoEndCascadeIndex() +{ + return cbBrixelizerDebugInfo.data.end_cascade_idx; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32 GetDebugInfoTMin() +{ + return cbBrixelizerDebugInfo.data.t_min; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32 GetDebugInfoTMax() +{ + return cbBrixelizerDebugInfo.data.t_max; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoDebugState() +{ + return cbBrixelizerDebugInfo.data.debug_state; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_JOB_BUFFER +FfxBrixelizerBrixelizationJob LoadBrixelizationJob(FfxUInt32 idx) +{ + return r_job_buffer.data[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_JOB_INDEX_BUFFER +FfxUInt32 LoadJobIndex(FfxUInt32 idx) +{ + return r_job_index_buffer.data[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_INFO_BUFFER +FfxBrixelizerInstanceInfo LoadInstanceInfo(FfxUInt32 index) +{ + return r_instance_info_buffer.data[index]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_TRANSFORM_BUFFER +FfxFloat32x3x4 LoadInstanceTransform(FfxUInt32 idx) +{ + // Instance transforms as stored in rows, so load in the 3 rows for this matrix. + FfxFloat32x4 M0 = r_instance_transform_buffer.data[idx * FfxUInt32(3) + FfxUInt32(0)]; + FfxFloat32x4 M1 = r_instance_transform_buffer.data[idx * FfxUInt32(3) + FfxUInt32(1)]; + FfxFloat32x4 M2 = r_instance_transform_buffer.data[idx * FfxUInt32(3) + FfxUInt32(2)]; + + // A GLSL mat4x3 is constructed using 4xvec3 columns so we need to reshuffle the 3 rows that we loaded into 4 columns. + + return FfxFloat32x3x4(FfxFloat32x3(M0.x, M1.x, M2.x), + FfxFloat32x3(M0.y, M1.y, M2.y), + FfxFloat32x3(M0.z, M1.z, M2.z), + FfxFloat32x3(M0.w, M1.w, M2.w)); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxUInt32 LoadVertexBufferUInt(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxUInt32x2 LoadVertexBufferUInt2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxUInt32x2(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 0], + r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 1]); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxUInt32x3 LoadVertexBufferUInt3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxUInt32x3(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 0], + r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 1], + r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 2]); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxFloat32x2 LoadVertexBufferFloat2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxFloat32x2(uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 0]), + uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 1])); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxFloat32x3 LoadVertexBufferFloat3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxFloat32x3(uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 0]), + uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 1]), + uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxFloat32x4 LoadVertexBufferFloat4(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxFloat32x4(uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 0]), + uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 1]), + uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 2]), + uintBitsToFloat(r_vertex_buffers[nonuniformEXT(bufferIdx)].data[elementIdx + 3])); +} +#endif + +#if defined(BRIXELIZER_BIND_SRV_SDF_ATLAS) +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw) +{ + return textureLod(sampler3D(r_sdf_atlas, g_wrap_linear_sampler), uvw, FfxFloat32(0.0f)).r; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP +FfxUInt32 LoadCascadeBrickMap(FfxUInt32 elementIdx) +{ + return rw_cascade_brick_map.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP +void StoreCascadeBrickMap(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_cascade_brick_map.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return rw_cascade_brick_maps[bufferIdx].data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS +void StoreCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_cascade_brick_maps[bufferIdx].data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS +FfxUInt32 LoadScratchCounter(FfxUInt32 counter) +{ + return rw_scratch_counters.data[counter]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS +void StoreScratchCounter(FfxUInt32 counter, FfxUInt32 value) +{ + rw_scratch_counters.data[counter] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS +void IncrementScratchCounter(FfxUInt32 counter, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + originalValue = atomicAdd(rw_scratch_counters.data[counter], value); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +FfxUInt32x2 LoadScratchIndexSwapUInt2(FfxUInt32 elementIdx) +{ + return FfxUInt32x2(rw_scratch_index_swap.data[elementIdx + 0], + rw_scratch_index_swap.data[elementIdx + 1]); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +FfxFloat32x3 LoadScratchIndexSwapFloat3(FfxUInt32 elementIdx) +{ + return FfxFloat32x3(uintBitsToFloat(rw_scratch_index_swap.data[elementIdx + 0]), + uintBitsToFloat(rw_scratch_index_swap.data[elementIdx + 1]), + uintBitsToFloat(rw_scratch_index_swap.data[elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +void StoreScratchIndexSwapUInt2(FfxUInt32 elementIdx, FfxUInt32x2 value) +{ + rw_scratch_index_swap.data[elementIdx + 0] = value.x; + rw_scratch_index_swap.data[elementIdx + 1] = value.y; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +void StoreScratchIndexSwapFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value) +{ + rw_scratch_index_swap.data[elementIdx + 0] = floatBitsToUint(value.x); + rw_scratch_index_swap.data[elementIdx + 1] = floatBitsToUint(value.y); + rw_scratch_index_swap.data[elementIdx + 2] = floatBitsToUint(value.z); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +void GetScratchIndexSwapDimensions(inout FfxUInt32 size) +{ + FfxUInt32 numStructs = rw_scratch_index_swap.data.length(); + FfxUInt32 stride = 4; + size = numStructs * stride; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER +FfxUInt32 LoadScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx) +{ + return rw_scratch_voxel_allocation_fail_counter.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER +void StoreScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_voxel_allocation_fail_counter.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +FfxUInt32 LoadScratchBricksStorage(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_storage.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +void StoreScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_storage.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +void GetScratchBricksStorageDimensions(inout FfxUInt32 size) +{ + FfxUInt32 numStructs = rw_scratch_bricks_storage.data.length(); + FfxUInt32 stride = 4; + size = numStructs * stride; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +void MinScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value) +{ + atomicMin(rw_scratch_bricks_storage.data[elementIdx], value); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS +FfxUInt32 LoadScratchBricksStorageOffsets(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_storage_offsets.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS +void StoreScratchBricksStorageOffsets(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_storage_offsets.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST +FfxUInt32 LoadScratchBricksCompressionList(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_compression_list.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST +void StoreScratchBricksCompressionList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_compression_list.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST +FfxUInt32 LoadScratchBricksClearList(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_clear_list.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST +void StoreScratchBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_clear_list.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS +FfxUInt32 LoadScratchJobCounter(FfxUInt32 counterIdx) +{ + return rw_scratch_job_counters.data[counterIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS +void StoreScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value) +{ + rw_scratch_job_counters.data[counterIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS +void IncrementScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value) +{ + atomicAdd(rw_scratch_job_counters.data[counterIdx], value); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN +FfxUInt32 LoadScratchJobCountersScan(FfxUInt32 elementIdx) +{ + return rw_scratch_job_counters_scan.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN +void StoreScratchJobCountersScan(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_job_counters_scan.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN +FfxUInt32 LoadGlobalJobTriangleCounterScan(FfxUInt32 elementIdx) +{ + return rw_scratch_job_global_counters_scan.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN +void StoreGlobalJobTriangleCounterScan(FfxUInt32 elementIdx, FfxUInt32 scan) +{ + rw_scratch_job_global_counters_scan.data[elementIdx] = scan; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES +FfxBrixelizerTriangleReference LoadScratchCR1Reference(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_references.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES +void StoreScratchCR1Reference(FfxUInt32 elementIdx, FfxBrixelizerTriangleReference ref) +{ + rw_scratch_cr1_references.data[elementIdx] = ref; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES +void GetScratchMaxReferences(inout FfxUInt32 size) +{ + size = rw_scratch_cr1_references.data.length(); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES +FfxUInt32 LoadScratchCR1CompactedReferences(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_compacted_references.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES +void StoreScratchCR1CompactedReferences(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_compacted_references.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS +FfxUInt32 LoadScratchCR1RefCounter(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_ref_counters.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS +void StoreScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_ref_counters.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS +void IncrementScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + originalValue = atomicAdd(rw_scratch_cr1_ref_counters.data[elementIdx], value); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN +FfxUInt32 LoadScratchCR1RefCounterScan(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_ref_counter_scan.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN +void StoreScratchCR1RefCounterScan(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_ref_counter_scan.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN +FfxUInt32 LoadVoxelReferenceGroupSum(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_ref_global_scan.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN +void StoreVoxelReferenceGroupSum(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_ref_global_scan.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN +FfxUInt32 LoadScratchCR1StampScan(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_stamp_scan.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN +void StoreScratchCR1StampScan(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_stamp_scan.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN +FfxUInt32 LoadStampGroupSum(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_stamp_global_scan.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN +void StoreStampGroupSum(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_stamp_global_scan.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_INDIRECT_ARGS +void StoreIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_indirect_args_1.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_voxel_map.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP +void StoreBricksVoxelMap(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_voxel_map.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_aabb.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB +void StoreBricksAABB(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_aabb.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST +FfxUInt32 LoadBricksFreeList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_free_list.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST +void StoreBricksFreeList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_free_list.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_clear_list.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST +void StoreBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_clear_list.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST +FfxUInt32 LoadBricksDirtyList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_eikonal_list.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST +void StoreBricksDirtyList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_eikonal_list.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST +FfxUInt32 LoadBricksMergeList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_merge_list.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST +void StoreBricksMergeList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_merge_list.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS +FfxUInt32 LoadBricksEikonalCounters(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_eikonal_counters.data[elementIdx & FFX_BRIXELIZER_BRICK_ID_MASK]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS +void StoreBricksEikonalCounters(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_eikonal_counters.data[elementIdx & FFX_BRIXELIZER_BRICK_ID_MASK] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx) +{ + return rw_bctx_counters.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS +void StoreContextCounter(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_counters.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS +void IncrementContextCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + originalValue = atomicAdd(rw_bctx_counters.data[elementIdx], value); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +FfxFloat32x3 LoadCascadeAABBTreeFloat3(FfxUInt32 elementIdx) +{ + return FfxFloat32x3(uintBitsToFloat(rw_cascade_aabbtree.data[elementIdx + 0]), + uintBitsToFloat(rw_cascade_aabbtree.data[elementIdx + 1]), + uintBitsToFloat(rw_cascade_aabbtree.data[elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +FfxUInt32 LoadCascadeAABBTreeUInt(FfxUInt32 elementIdx) +{ + return rw_cascade_aabbtree.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +void StoreCascadeAABBTreeUInt(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_cascade_aabbtree.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +void StoreCascadeAABBTreeFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value) +{ + rw_cascade_aabbtree.data[elementIdx + 0] = floatBitsToUint(value.x); + rw_cascade_aabbtree.data[elementIdx + 1] = floatBitsToUint(value.y); + rw_cascade_aabbtree.data[elementIdx + 2] = floatBitsToUint(value.z); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIdx) +{ + return FfxFloat32x3(uintBitsToFloat(rw_cascade_aabbtrees[cascadeID].data[elementIdx + 0]), + uintBitsToFloat(rw_cascade_aabbtrees[cascadeID].data[elementIdx + 1]), + uintBitsToFloat(rw_cascade_aabbtrees[cascadeID].data[elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIdx) +{ + return rw_cascade_aabbtrees[cascadeID].data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SDF_ATLAS +FfxFloat32 LoadSDFAtlas(FfxUInt32x3 coord) +{ + return imageLoad(rw_sdf_atlas, FfxInt32x3(coord)).x; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SDF_ATLAS +void StoreSDFAtlas(FfxUInt32x3 coord, FfxFloat32 value) +{ + imageStore(rw_sdf_atlas, FfxInt32x3(coord), FfxFloat32x4(value, 0.0f, 0.0f, 0.0f)); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_OUTPUT +void StoreDebugOutput(FfxUInt32x2 coord, FfxFloat32x3 outputValue) +{ + imageStore(rw_debug_output, FfxInt32x2(coord), FfxFloat32x4(outputValue, 1.0f)); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_OUTPUT +void GetDebugOutputDimensions(inout FfxUInt32 width, inout FfxUInt32 height) +{ + FfxInt32x2 size = imageSize(rw_debug_output); + width = FfxUInt32(size.x); + height = FfxUInt32(size.y); +} +#endif + +#endif // #if defined(FFX_GPU) + +#endif // FFX_BRIXELIZER_CALLBACKS_GLSL_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_callbacks_hlsl.h new file mode 100644 index 00000000..91a4ccc4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_callbacks_hlsl.h @@ -0,0 +1,1188 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_CALLBACKS_HLSL_H +#define FFX_BRIXELIZER_CALLBACKS_HLSL_H + +#include "ffx_brixelizer_resources.h" +#include "ffx_brixelizer_host_gpu_shared.h" +#include "ffx_brixelizer_host_gpu_shared_private.h" + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#define FFX_BRIXELIZER_SIZEOF_UINT 4 + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_BRIXELIZER_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_BRIXELIZER_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_BRIXELIZER_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) +#define FFX_BRIXELIZER_DECLARE_STATIC_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex), space1) + +#define FFX_BRIXELIZER_ROOTSIG_STRINGIFY(p) FFX_BRIXELIZER_ROOTSIG_STR(p) +#define FFX_BRIXELIZER_ROOTSIG_STR(p) #p +#define FFX_BRIXELIZER_ROOTSIG [RootSignature("DescriptorTable(UAV(u0, numDescriptors = " FFX_BRIXELIZER_ROOTSIG_STRINGIFY(FFX_BRIXELIZER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_BRIXELIZER_ROOTSIG_STRINGIFY(FFX_BRIXELIZER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(Sampler(s0)), " \ + "CBV(b0), " \ + "CBV(b1), " \ + "CBV(b2), " \ + "CBV(b3)")] +#define FFX_BRIXELIZER_VOXELIZE_ROOTSIG [RootSignature("DescriptorTable(UAV(u0, numDescriptors = " FFX_BRIXELIZER_ROOTSIG_STRINGIFY(FFX_BRIXELIZER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_BRIXELIZER_ROOTSIG_STRINGIFY(FFX_BRIXELIZER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, space = 1, numDescriptors = unbounded)), " \ + "DescriptorTable(Sampler(s0)), " \ + "CBV(b0), " \ + "CBV(b1), " \ + "CBV(b2), " \ + "CBV(b3)")] + +#if defined(FFX_BRIXELIZER_EMBED_ROOTSIG) +#define FFX_BRIXELIZER_EMBED_ROOTSIG_CONTENT FFX_BRIXELIZER_ROOTSIG +#define FFX_BRIXELIZER_EMBED_VOXELIZE_ROOTSIG_CONTENT FFX_BRIXELIZER_VOXELIZE_ROOTSIG +#else +#define FFX_BRIXELIZER_EMBED_ROOTSIG_CONTENT +#define FFX_BRIXELIZER_EMBED_VOXELIZE_ROOTSIG_CONTENT +#endif // #if FFX_BRIXELIZER_EMBED_ROOTSIG + +// CBVs + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO + ConstantBuffer cbBrixelizerCascadeInfo : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_BIND_CB_CASCADE_INFO); +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO + ConstantBuffer cbBrixelizerContextInfo : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_BIND_CB_CONTEXT_INFO); +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO + ConstantBuffer cbBrixelizerBuildInfo : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_BIND_CB_BUILD_INFO); +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO + ConstantBuffer cbBrixelizerDebugInfo : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_BIND_CB_DEBUG_INFO); +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_AABBS + RWStructuredBuffer rw_debug_aabbs : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_DEBUG_AABBS); +#endif + +#if defined BRIXELIZER_BIND_SRV_DEBUG_INSTANCE_ID_BUFFER + StructuredBuffer r_debug_instance_id : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_DEBUG_INSTANCE_ID_BUFFER); +#endif + +// SRVs + +#if defined BRIXELIZER_BIND_SRV_JOB_BUFFER + StructuredBuffer r_job_buffer : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_JOB_BUFFER); +#endif + +#if defined BRIXELIZER_BIND_SRV_JOB_INDEX_BUFFER + StructuredBuffer r_job_index_buffer : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_JOB_INDEX_BUFFER); +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_INFO_BUFFER + StructuredBuffer r_instance_info_buffer : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_INSTANCE_INFO_BUFFER); +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_TRANSFORM_BUFFER + StructuredBuffer r_instance_transform_buffer : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_INSTANCE_TRANSFORM_BUFFER); +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS + StructuredBuffer r_vertex_buffers[FFX_BRIXELIZER_STATIC_CONFIG_MAX_VERTEX_BUFFERS] : FFX_BRIXELIZER_DECLARE_STATIC_SRV(BRIXELIZER_BIND_SRV_VERTEX_BUFFERS); +#endif + +#if defined BRIXELIZER_BIND_SRV_SDF_ATLAS + Texture3D r_sdf_atlas : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_SDF_ATLAS); +#endif + +// UAVs + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE + RWStructuredBuffer rw_cascade_aabbtree : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE); +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP + RWStructuredBuffer rw_cascade_brick_map : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS + RWStructuredBuffer rw_scratch_counters : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP + RWStructuredBuffer rw_scratch_index_swap : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER + RWStructuredBuffer rw_scratch_voxel_allocation_fail_counter : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE + RWStructuredBuffer rw_scratch_bricks_storage : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS + RWStructuredBuffer rw_scratch_bricks_storage_offsets : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST + RWStructuredBuffer rw_scratch_bricks_compression_list : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST + RWStructuredBuffer rw_scratch_bricks_clear_list : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS + RWStructuredBuffer rw_scratch_job_counters : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN + RWStructuredBuffer rw_scratch_job_counters_scan : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN + RWStructuredBuffer rw_scratch_job_global_counters_scan : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES + RWStructuredBuffer rw_scratch_cr1_references : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES + RWStructuredBuffer rw_scratch_cr1_compacted_references : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS + RWStructuredBuffer rw_scratch_cr1_ref_counters : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN + RWStructuredBuffer rw_scratch_cr1_ref_counter_scan : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN + RWStructuredBuffer rw_scratch_cr1_ref_global_scan : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN + RWStructuredBuffer rw_scratch_cr1_stamp_scan : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN); +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN + RWStructuredBuffer rw_scratch_cr1_stamp_global_scan : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN); +#endif + +#if defined BRIXELIZER_BIND_UAV_INDIRECT_ARGS + RWStructuredBuffer rw_indirect_args_1 : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_INDIRECT_ARGS); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP + RWStructuredBuffer rw_bctx_bricks_voxel_map : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB + RWStructuredBuffer rw_bctx_bricks_aabb : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST + RWStructuredBuffer rw_bctx_bricks_free_list : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST + RWStructuredBuffer rw_bctx_bricks_clear_list : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST + RWStructuredBuffer rw_bctx_bricks_eikonal_list : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST + RWStructuredBuffer rw_bctx_bricks_merge_list : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS + RWStructuredBuffer rw_bctx_bricks_eikonal_counters : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS); +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS + RWStructuredBuffer rw_bctx_counters : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS); +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS + RWStructuredBuffer rw_cascade_brick_maps[24] : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS); +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES + RWStructuredBuffer rw_cascade_aabbtrees[24] : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES); +#endif + +#if defined BRIXELIZER_BIND_UAV_SDF_ATLAS + RWTexture3D rw_sdf_atlas : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_SDF_ATLAS); +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_OUTPUT + RWTexture2D rw_debug_output : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_BIND_UAV_DEBUG_OUTPUT); +#endif + +SamplerState g_wrap_linear_sampler : register(s0); + +FfxBrixelizerDebugAABB GetDebugAABB(FfxUInt32 idx); +void StoreDebugAABB(FfxUInt32 idx, FfxBrixelizerDebugAABB aabb); +FfxUInt32 GetDebugInstanceID(FfxUInt32 idx); +FfxBrixelizerCascadeInfo GetCascadeInfo(); +FfxUInt32x3 GetCascadeInfoClipmapOffset(); +FfxUInt32 GetCascadeInfoIndex(); +FfxFloat32x3 GetCascadeInfoGridMin(); +FfxFloat32x3 GetCascadeInfoGridMax(); +FfxFloat32 GetCascadeInfoVoxelSize(); +FfxInt32x3 GetCascadeInfoClipmapInvalidationOffset(); +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 idx); +FfxUInt32 GetContextInfoNumBricks(); +FfxUInt32x3 GetContextInfoCascadeClipmapOffset(FfxUInt32 cascade_index); +FfxBrixelizerBuildInfo GetBuildInfo(); +FfxUInt32 GetBuildInfoDoInitialization(); +FfxInt32 GetBuildInfoTreeIteration(); +FfxUInt32 GetBuildInfoNumJobs(); +FfxUInt32 GetDebugInfoMaxAABBs(); +FfxFloat32x4x4 GetDebugInfoInvView(); +FfxFloat32x4x4 GetDebugInfoInvProj(); +FfxFloat32 GetDebugInfoPreviewSDFSolveEpsilon(); +FfxUInt32 GetDebugInfoStartCascadeIndex(); +FfxUInt32 GetDebugInfoEndCascadeIndex(); +FfxFloat32 GetDebugInfoTMin(); +FfxFloat32 GetDebugInfoTMax(); +FfxUInt32 GetDebugInfoDebugState(); +FfxBrixelizerBrixelizationJob LoadBrixelizationJob(FfxUInt32 idx); +FfxUInt32 LoadJobIndex(FfxUInt32 idx); +FfxBrixelizerInstanceInfo LoadInstanceInfo(FfxUInt32 index); +FfxFloat32x3x4 LoadInstanceTransform(FfxUInt32 idx); +FfxUInt32 LoadVertexBufferUInt(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxUInt32x2 LoadVertexBufferUInt2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxUInt32x3 LoadVertexBufferUInt3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32x2 LoadVertexBufferFloat2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32x3 LoadVertexBufferFloat3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32x4 LoadVertexBufferFloat4(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw); +FfxUInt32 LoadCascadeBrickMap(FfxUInt32 elementIdx); +void StoreCascadeBrickMap(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx); +void StoreCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchCounter(FfxUInt32 counter); +void StoreScratchCounter(FfxUInt32 counter, FfxUInt32 value); +void IncrementScratchCounter(FfxUInt32 counter, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxUInt32x2 LoadScratchIndexSwapUInt2(FfxUInt32 elementIdx); +FfxFloat32x3 LoadScratchIndexSwapFloat3(FfxUInt32 elementIdx); +void StoreScratchIndexSwapUInt2(FfxUInt32 elementIdx, FfxUInt32x2 value); +void StoreScratchIndexSwapFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value); +void GetScratchIndexSwapDimensions(inout FfxUInt32 size); +FfxUInt32 LoadScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx); +void StoreScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksStorage(FfxUInt32 elementIdx); +void StoreScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value); +void GetScratchBricksStorageDimensions(inout FfxUInt32 size); +void MinScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksStorageOffsets(FfxUInt32 elementIdx); +void StoreScratchBricksStorageOffsets(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksCompressionList(FfxUInt32 elementIdx); +void StoreScratchBricksCompressionList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchBricksClearList(FfxUInt32 elementIdx); +void StoreScratchBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchJobCounter(FfxUInt32 counterIdx); +void StoreScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value); +void IncrementScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value); +FfxUInt32 LoadScratchJobCountersScan(FfxUInt32 elementIdx); +void StoreScratchJobCountersScan(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadGlobalJobTriangleCounterScan(FfxUInt32 elementIdx); +void StoreGlobalJobTriangleCounterScan(FfxUInt32 elementIdx, FfxUInt32 scan); +FfxBrixelizerTriangleReference LoadScratchCR1Reference(FfxUInt32 elementIdx); +void StoreScratchCR1Reference(FfxUInt32 elementIdx, FfxBrixelizerTriangleReference ref); +void GetScratchMaxReferences(inout FfxUInt32 size); +FfxUInt32 LoadScratchCR1CompactedReferences(FfxUInt32 elementIdx); +void StoreScratchCR1CompactedReferences(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchCR1RefCounter(FfxUInt32 elementIdx); +void StoreScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value); +void IncrementScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxUInt32 LoadScratchCR1RefCounterScan(FfxUInt32 elementIdx); +void StoreScratchCR1RefCounterScan(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadVoxelReferenceGroupSum(FfxUInt32 elementIdx); +void StoreVoxelReferenceGroupSum(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadScratchCR1StampScan(FfxUInt32 elementIdx); +void StoreScratchCR1StampScan(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadStampGroupSum(FfxUInt32 elementIdx); +void StoreStampGroupSum(FfxUInt32 elementIdx, FfxUInt32 value); +void StoreIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIdx); +void StoreBricksVoxelMap(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIdx); +void StoreBricksAABB(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksFreeList(FfxUInt32 elementIdx); +void StoreBricksFreeList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx); +void StoreBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksDirtyList(FfxUInt32 elementIdx); +void StoreBricksDirtyList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksMergeList(FfxUInt32 elementIdx); +void StoreBricksMergeList(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadBricksEikonalCounters(FfxUInt32 elementIdx); +void StoreBricksEikonalCounters(FfxUInt32 elementIdx, FfxUInt32 value); +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx); +void StoreContextCounter(FfxUInt32 elementIdx, FfxUInt32 value); +void IncrementContextCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxFloat32x3 LoadCascadeAABBTreeFloat3(FfxUInt32 elementIdx); +FfxUInt32 LoadCascadeAABBTreeUInt(FfxUInt32 elementIdx); +void StoreCascadeAABBTreeUInt(FfxUInt32 elementIdx, FfxUInt32 value); +void StoreCascadeAABBTreeFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value); +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIdx); +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIdx); +FfxFloat32 LoadSDFAtlas(FfxUInt32x3 coord); +void StoreSDFAtlas(FfxUInt32x3 coord, FfxFloat32 value); +void StoreDebugOutput(FfxUInt32x2 coord, FfxFloat32x3 output); +void GetDebugOutputDimensions(inout FfxUInt32 width, inout FfxUInt32 height); + +#if defined BRIXELIZER_BIND_UAV_DEBUG_AABBS +FfxBrixelizerDebugAABB GetDebugAABB(FfxUInt32 idx) +{ + return rw_debug_aabbs[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_AABBS +void StoreDebugAABB(FfxUInt32 idx, FfxBrixelizerDebugAABB aabb) +{ + rw_debug_aabbs[idx] = aabb; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_DEBUG_INSTANCE_ID_BUFFER +FfxUInt32 GetDebugInstanceID(FfxUInt32 idx) +{ + return r_debug_instance_id[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxBrixelizerCascadeInfo GetCascadeInfo() +{ + return cbBrixelizerCascadeInfo; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxUInt32x3 GetCascadeInfoClipmapOffset() +{ + return cbBrixelizerCascadeInfo.clipmap_offset; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxUInt32 GetCascadeInfoIndex() +{ + return cbBrixelizerCascadeInfo.index; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxFloat32x3 GetCascadeInfoGridMin() +{ + return cbBrixelizerCascadeInfo.grid_min; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxFloat32x3 GetCascadeInfoGridMax() +{ + return cbBrixelizerCascadeInfo.grid_max; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxFloat32 GetCascadeInfoVoxelSize() +{ + return cbBrixelizerCascadeInfo.voxel_size; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CASCADE_INFO +FfxInt32x3 GetCascadeInfoClipmapInvalidationOffset() +{ + return cbBrixelizerCascadeInfo.clipmap_invalidation_offset; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 idx) +{ + return cbBrixelizerContextInfo.cascades[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxUInt32 GetContextInfoNumBricks() +{ + return cbBrixelizerContextInfo.num_bricks; +} +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxUInt32x3 GetContextInfoCascadeClipmapOffset(FfxUInt32 cascade_index) +{ + return cbBrixelizerContextInfo.cascades[cascade_index].clipmap_offset; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxBrixelizerBuildInfo GetBuildInfo() +{ + return cbBrixelizerBuildInfo; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxUInt32 GetBuildInfoDoInitialization() +{ + return cbBrixelizerBuildInfo.do_initialization; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxInt32 GetBuildInfoTreeIteration() +{ + return cbBrixelizerBuildInfo.tree_iteration; +} +#endif + +#if defined BRIXELIZER_BIND_CB_BUILD_INFO +FfxUInt32 GetBuildInfoNumJobs() +{ + return cbBrixelizerBuildInfo.num_jobs; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoMaxAABBs() +{ + return cbBrixelizerDebugInfo.max_aabbs; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32x4x4 GetDebugInfoInvView() +{ + return cbBrixelizerDebugInfo.inv_view; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32x4x4 GetDebugInfoInvProj() +{ + return cbBrixelizerDebugInfo.inv_proj; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32 GetDebugInfoPreviewSDFSolveEpsilon() +{ + return cbBrixelizerDebugInfo.preview_sdf_solve_eps; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoStartCascadeIndex() +{ + return cbBrixelizerDebugInfo.start_cascade_idx; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoEndCascadeIndex() +{ + return cbBrixelizerDebugInfo.end_cascade_idx; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32 GetDebugInfoTMin() +{ + return cbBrixelizerDebugInfo.t_min; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxFloat32 GetDebugInfoTMax() +{ + return cbBrixelizerDebugInfo.t_max; +} +#endif + +#if defined BRIXELIZER_BIND_CB_DEBUG_INFO +FfxUInt32 GetDebugInfoDebugState() +{ + return cbBrixelizerDebugInfo.debug_state; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_JOB_BUFFER +FfxBrixelizerBrixelizationJob LoadBrixelizationJob(FfxUInt32 idx) +{ + return r_job_buffer[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_JOB_INDEX_BUFFER +FfxUInt32 LoadJobIndex(FfxUInt32 idx) +{ + return r_job_index_buffer[idx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_INFO_BUFFER +FfxBrixelizerInstanceInfo LoadInstanceInfo(FfxUInt32 index) +{ + return r_instance_info_buffer[index]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_INSTANCE_TRANSFORM_BUFFER +FfxFloat32x3x4 LoadInstanceTransform(FfxUInt32 idx) +{ + FfxFloat32x4 M0 = r_instance_transform_buffer[idx * FfxUInt32(3) + FfxUInt32(0)]; + FfxFloat32x4 M1 = r_instance_transform_buffer[idx * FfxUInt32(3) + FfxUInt32(1)]; + FfxFloat32x4 M2 = r_instance_transform_buffer[idx * FfxUInt32(3) + FfxUInt32(2)]; + + return FfxFloat32x3x4(M0, M1, M2); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxUInt32 LoadVertexBufferUInt(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxUInt32x2 LoadVertexBufferUInt2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxUInt32x2(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 0], + r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 1]); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxUInt32x3 LoadVertexBufferUInt3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxUInt32x3(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 0], + r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 1], + r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 2]); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxFloat32x2 LoadVertexBufferFloat2(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxFloat32x2(asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 0]), + asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 1])); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxFloat32x3 LoadVertexBufferFloat3(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxFloat32x3(asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 0]), + asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 1]), + asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_VERTEX_BUFFERS +FfxFloat32x4 LoadVertexBufferFloat4(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return FfxFloat32x4(asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 0]), + asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 1]), + asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 2]), + asfloat(r_vertex_buffers[NonUniformResourceIndex(bufferIdx)][elementIdx + 3])); +} +#endif + +#if defined(BRIXELIZER_BIND_SRV_SDF_ATLAS) +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw) +{ + return r_sdf_atlas.SampleLevel(g_wrap_linear_sampler, uvw, FfxFloat32(0.0)); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP +FfxUInt32 LoadCascadeBrickMap(FfxUInt32 elementIdx) +{ + return rw_cascade_brick_map[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAP +void StoreCascadeBrickMap(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_cascade_brick_map[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx) +{ + return rw_cascade_brick_maps[bufferIdx][elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_BRICK_MAPS +void StoreCascadeBrickMapArrayUniform(FfxUInt32 bufferIdx, FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_cascade_brick_maps[bufferIdx][elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS +FfxUInt32 LoadScratchCounter(FfxUInt32 counter) +{ + return rw_scratch_counters[counter]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS +void StoreScratchCounter(FfxUInt32 counter, FfxUInt32 value) +{ + rw_scratch_counters[counter] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_COUNTERS +void IncrementScratchCounter(FfxUInt32 counter, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + InterlockedAdd(rw_scratch_counters[counter], value, originalValue); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +FfxUInt32x2 LoadScratchIndexSwapUInt2(FfxUInt32 elementIdx) +{ + return FfxUInt32x2(rw_scratch_index_swap[elementIdx + 0], + rw_scratch_index_swap[elementIdx + 1]); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +FfxFloat32x3 LoadScratchIndexSwapFloat3(FfxUInt32 elementIdx) +{ + return FfxFloat32x3(asfloat(rw_scratch_index_swap[elementIdx + 0]), + asfloat(rw_scratch_index_swap[elementIdx + 1]), + asfloat(rw_scratch_index_swap[elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +void StoreScratchIndexSwapUInt2(FfxUInt32 elementIdx, FfxUInt32x2 value) +{ + rw_scratch_index_swap[elementIdx + 0] = value.x; + rw_scratch_index_swap[elementIdx + 1] = value.y; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +void StoreScratchIndexSwapFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value) +{ + rw_scratch_index_swap[elementIdx + 0] = asuint(value.x); + rw_scratch_index_swap[elementIdx + 1] = asuint(value.y); + rw_scratch_index_swap[elementIdx + 2] = asuint(value.z); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_INDEX_SWAP +void GetScratchIndexSwapDimensions(inout FfxUInt32 size) +{ + FfxUInt32 numStructs = 0; + FfxUInt32 stride = 0; + rw_scratch_index_swap.GetDimensions(numStructs, stride); + size = numStructs * stride; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER +FfxUInt32 LoadScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx) +{ + return rw_scratch_voxel_allocation_fail_counter[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER +void StoreScratchVoxelAllocationFailCounter(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_voxel_allocation_fail_counter[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +FfxUInt32 LoadScratchBricksStorage(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_storage[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +void StoreScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_storage[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +void GetScratchBricksStorageDimensions(inout FfxUInt32 size) +{ + FfxUInt32 numStructs = 0; + FfxUInt32 stride = 0; + rw_scratch_bricks_storage.GetDimensions(numStructs, stride); + size = numStructs * stride; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE +void MinScratchBricksStorage(FfxUInt32 elementIdx, FfxUInt32 value) +{ + InterlockedMin(rw_scratch_bricks_storage[elementIdx], value); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS +FfxUInt32 LoadScratchBricksStorageOffsets(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_storage_offsets[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_STORAGE_OFFSETS +void StoreScratchBricksStorageOffsets(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_storage_offsets[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST +FfxUInt32 LoadScratchBricksCompressionList(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_compression_list[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_COMPRESSION_LIST +void StoreScratchBricksCompressionList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_compression_list[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST +FfxUInt32 LoadScratchBricksClearList(FfxUInt32 elementIdx) +{ + return rw_scratch_bricks_clear_list[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_BRICKS_CLEAR_LIST +void StoreScratchBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_bricks_clear_list[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS +FfxUInt32 LoadScratchJobCounter(FfxUInt32 counterIdx) +{ + return rw_scratch_job_counters[counterIdx]; +} +#endif + +void StoreScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value) +{ +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS + rw_scratch_job_counters[counterIdx] = value; +#endif +} + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS +void IncrementScratchJobCounter(FfxUInt32 counterIdx, FfxUInt32 value) +{ + InterlockedAdd(rw_scratch_job_counters[counterIdx], value); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN +FfxUInt32 LoadScratchJobCountersScan(FfxUInt32 elementIdx) +{ + return rw_scratch_job_counters_scan[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_COUNTERS_SCAN +void StoreScratchJobCountersScan(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_job_counters_scan[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN +FfxUInt32 LoadGlobalJobTriangleCounterScan(FfxUInt32 elementIdx) +{ + return rw_scratch_job_global_counters_scan[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN +void StoreGlobalJobTriangleCounterScan(FfxUInt32 elementIdx, FfxUInt32 scan) +{ + rw_scratch_job_global_counters_scan[elementIdx] = scan; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES +FfxBrixelizerTriangleReference LoadScratchCR1Reference(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_references[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES +void StoreScratchCR1Reference(FfxUInt32 elementIdx, FfxBrixelizerTriangleReference ref) +{ + rw_scratch_cr1_references[elementIdx] = ref; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REFERENCES +void GetScratchMaxReferences(inout FfxUInt32 size) +{ + FfxUInt32 numStructs = 0; + FfxUInt32 stride = 0; + rw_scratch_cr1_references.GetDimensions(numStructs, stride); + size = numStructs; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES +FfxUInt32 LoadScratchCR1CompactedReferences(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_compacted_references[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_COMPACTED_REFERENCES +void StoreScratchCR1CompactedReferences(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_compacted_references[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS +FfxUInt32 LoadScratchCR1RefCounter(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_ref_counters[elementIdx]; +} +#endif + +void StoreScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value) +{ +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS + rw_scratch_cr1_ref_counters[elementIdx] = value; +#endif +} + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTERS +void IncrementScratchCR1RefCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + InterlockedAdd(rw_scratch_cr1_ref_counters[elementIdx], value, originalValue); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN +FfxUInt32 LoadScratchCR1RefCounterScan(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_ref_counter_scan[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_COUNTER_SCAN +void StoreScratchCR1RefCounterScan(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_ref_counter_scan[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN +FfxUInt32 LoadVoxelReferenceGroupSum(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_ref_global_scan[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_REF_GLOBAL_SCAN +void StoreVoxelReferenceGroupSum(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_ref_global_scan[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN +FfxUInt32 LoadScratchCR1StampScan(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_stamp_scan[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_SCAN +void StoreScratchCR1StampScan(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_stamp_scan[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN +FfxUInt32 LoadStampGroupSum(FfxUInt32 elementIdx) +{ + return rw_scratch_cr1_stamp_global_scan[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SCRATCH_CR1_STAMP_GLOBAL_SCAN +void StoreStampGroupSum(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_scratch_cr1_stamp_global_scan[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_INDIRECT_ARGS +void StoreIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_indirect_args_1[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_voxel_map[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_VOXEL_MAP +void StoreBricksVoxelMap(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_voxel_map[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_aabb[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_AABB +void StoreBricksAABB(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_aabb[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST +FfxUInt32 LoadBricksFreeList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_free_list[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_FREE_LIST +void StoreBricksFreeList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_free_list[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_clear_list[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_CLEAR_LIST +void StoreBricksClearList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_clear_list[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST +FfxUInt32 LoadBricksDirtyList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_eikonal_list[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_LIST +void StoreBricksDirtyList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_eikonal_list[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST +FfxUInt32 LoadBricksMergeList(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_merge_list[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_MERGE_LIST +void StoreBricksMergeList(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_merge_list[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS +FfxUInt32 LoadBricksEikonalCounters(FfxUInt32 elementIdx) +{ + return rw_bctx_bricks_eikonal_counters[elementIdx & FFX_BRIXELIZER_BRICK_ID_MASK]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_BRICKS_EIKONAL_COUNTERS +void StoreBricksEikonalCounters(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_bricks_eikonal_counters[elementIdx & FFX_BRIXELIZER_BRICK_ID_MASK] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx) +{ + return rw_bctx_counters[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS +void StoreContextCounter(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_bctx_counters[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CONTEXT_COUNTERS +void IncrementContextCounter(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + InterlockedAdd(rw_bctx_counters[elementIdx], value, originalValue); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +FfxFloat32x3 LoadCascadeAABBTreeFloat3(FfxUInt32 elementIdx) +{ + return FfxFloat32x3(asfloat(rw_cascade_aabbtree[elementIdx + 0]), + asfloat(rw_cascade_aabbtree[elementIdx + 1]), + asfloat(rw_cascade_aabbtree[elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +FfxUInt32 LoadCascadeAABBTreeUInt(FfxUInt32 elementIdx) +{ + return rw_cascade_aabbtree[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +void StoreCascadeAABBTreeUInt(FfxUInt32 elementIdx, FfxUInt32 value) +{ + rw_cascade_aabbtree[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREE +void StoreCascadeAABBTreeFloat3(FfxUInt32 elementIdx, FfxFloat32x3 value) +{ + rw_cascade_aabbtree[elementIdx + 0] = asuint(value.x); + rw_cascade_aabbtree[elementIdx + 1] = asuint(value.y); + rw_cascade_aabbtree[elementIdx + 2] = asuint(value.z); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIdx) +{ + return FfxFloat32x3(asfloat(rw_cascade_aabbtrees[cascadeID][elementIdx + 0]), + asfloat(rw_cascade_aabbtrees[cascadeID][elementIdx + 1]), + asfloat(rw_cascade_aabbtrees[cascadeID][elementIdx + 2])); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_CASCADE_AABB_TREES +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIdx) +{ + return rw_cascade_aabbtrees[cascadeID][elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SDF_ATLAS +FfxFloat32 LoadSDFAtlas(FfxUInt32x3 coord) +{ + return rw_sdf_atlas[coord]; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_SDF_ATLAS +void StoreSDFAtlas(FfxUInt32x3 coord, FfxFloat32 value) +{ + rw_sdf_atlas[coord] = value; +} +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_OUTPUT +void StoreDebugOutput(FfxUInt32x2 coord, FfxFloat32x3 output) +{ + rw_debug_output[coord] = FfxFloat32x4(output, 1.0f); +} +#endif + +#if defined BRIXELIZER_BIND_UAV_DEBUG_OUTPUT +void GetDebugOutputDimensions(inout FfxUInt32 width, inout FfxUInt32 height) +{ + rw_debug_output.GetDimensions(width, height); +} +#endif + +#endif // #if defined(FFX_GPU) + +#endif // FFX_BRIXELIZER_CALLBACKS_HLSL_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_cascade_ops.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_cascade_ops.h new file mode 100644 index 00000000..40fdf8b1 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_cascade_ops.h @@ -0,0 +1,1477 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_CASCADE_OPS_H +#define FFX_BRIXELIZER_CASCADE_OPS_H + +#include "ffx_brixelizer_host_gpu_shared_private.h" +#include "ffx_brixelizer_brick_common_private.h" +#include "ffx_brixelizer_build_common.h" +#include "ffx_brixelizer_common_private.h" +#include "ffx_brixelizer_mesh_common.h" + +void FfxBrixelizerClearRefCounter(FfxUInt32 idx) +{ + StoreScratchCR1RefCounter(idx, FfxUInt32(0)); + StoreScratchVoxelAllocationFailCounter(idx, FfxUInt32(0)); +} + +// Search for n where a[n] <= offset and a[n+1] > offset +#define LOWER_BOUND(offset, total_count) \ + { \ + FfxUInt32 cursor = FfxUInt32(0); \ + FfxUInt32 size = total_count; \ + while (size > FfxUInt32(0)) { \ + FfxUInt32 size_half = size >> FfxUInt32(1); \ + FfxUInt32 mid = cursor + size_half; \ + if (LOWER_BOUND_LOAD(mid) > offset) \ + size = size_half; \ + else { \ + cursor = mid + FfxUInt32(1); \ + size = size - size_half - FfxUInt32(1); \ + } \ + } \ + \ + LOWER_BOUND_RESULT = max(cursor, FfxUInt32(1)) - FfxUInt32(1); \ + } + +FfxUInt32x3 WrapCoords(FfxUInt32x3 voxel_coord) +{ + return (voxel_coord + GetCascadeInfoClipmapOffset()) & FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_WRAP_MASK); +} + +FfxUInt32 WrapFlatCoords(FfxUInt32 voxel_idx) +{ + return FfxBrixelizerFlattenPOT((FfxBrixelizerUnflattenPOT(voxel_idx, FFX_BRIXELIZER_CASCADE_DEGREE) + GetCascadeInfoClipmapOffset()) & FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_WRAP_MASK), FFX_BRIXELIZER_CASCADE_DEGREE); +} + +void MarkFailed(FfxUInt32 flat_voxel_idx) +{ + StoreScratchVoxelAllocationFailCounter(flat_voxel_idx, FfxUInt32(1)); +} + +FfxBoolean IsBuildable(FfxUInt32 voxel_idx) +{ + return LoadCascadeBrickMap(WrapFlatCoords(voxel_idx)) == FFX_BRIXELIZER_UNINITIALIZED_ID; +} + +FfxBoolean CanBuildThisVoxel(FfxUInt32 flat_voxel_idx) +{ + if (!IsBuildable(flat_voxel_idx)) return false; + return true; +} + +void AddReferenceOrMarkVoxelFailed(FfxUInt32 voxel_idx, FfxUInt32 triangle_id) +{ + if (!CanBuildThisVoxel(voxel_idx)) { + return; + } + + FfxUInt32 local_ref_idx; + IncrementScratchCR1RefCounter(voxel_idx, FfxUInt32(1), local_ref_idx); + FfxBrixelizerTriangleReference ref; + ref.voxel_idx = voxel_idx; + ref.triangle_id = triangle_id; + ref.local_ref_idx = local_ref_idx; + FfxUInt32 coarse_ref_offset; + IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_REFERENCES, FfxUInt32(1), coarse_ref_offset); + FfxUInt32 max_references = LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_MAX_REFERENCES); + if (coarse_ref_offset < max_references) { + StoreScratchCR1Reference(coarse_ref_offset, ref); + } else { + MarkFailed(voxel_idx); + } +} + +FfxUInt32 GetReferenceOffset(FfxUInt32 voxel_idx) +{ + FfxUInt32 group_scan_id = voxel_idx / FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE; + FfxUInt32 group_scan_value = LoadVoxelReferenceGroupSum(group_scan_id); + FfxUInt32 local_scan_value = LoadScratchCR1RefCounterScan(voxel_idx); + return group_scan_value + local_scan_value; +} + +struct FfxBrixelizerCRItemPacked { + FfxUInt32 pack0; + FfxUInt32 pack1; +}; + +struct FfxBrixelizerCRItem { + FfxUInt32x3 bounds_min; + FfxUInt32x3 bounds_max; +}; + +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_voxelizer_items_ref_count[FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE]; +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE]; +FFX_GROUPSHARED FfxBrixelizerCRItemPacked gs_ffx_brixelizer_voxelizer_items[FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE]; +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_voxelizer_item_counter; +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_voxelizer_ref_counter; +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_voxelizer_ref_offset; +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_triangle_offset_global; +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_triangle_offset; +FFX_GROUPSHARED FfxBoolean gs_ffx_brixelizer_voxelizer_has_space; + +void FfxBrixelizerCRStoreItem(FfxInt32 index, FfxBrixelizerCRItem item) +{ + FfxUInt32 pack0 = ((item.bounds_min.x & FfxUInt32(0x3ff)) << FfxUInt32(0)) | + ((item.bounds_min.y & FfxUInt32(0x3ff)) << FfxUInt32(10)) | + ((item.bounds_min.z & FfxUInt32(0x3ff)) << FfxUInt32(20)); + FfxUInt32 pack1 = ((item.bounds_max.x & FfxUInt32(0x3ff)) << FfxUInt32(0)) | + ((item.bounds_max.y & FfxUInt32(0x3ff)) << FfxUInt32(10)) | + ((item.bounds_max.z & FfxUInt32(0x3ff)) << FfxUInt32(20)); + FfxBrixelizerCRItemPacked packed; + packed.pack0 = pack0; + packed.pack1 = pack1; + gs_ffx_brixelizer_voxelizer_items[index] = packed; +} + +FfxBrixelizerCRItem FfxBrixelizerCRLoadItem(FfxInt32 index) +{ + FfxBrixelizerCRItemPacked pack = gs_ffx_brixelizer_voxelizer_items[index]; + FfxBrixelizerCRItem item; + item.bounds_min.x = (pack.pack0 >> FfxUInt32(0)) & FfxUInt32(0x3ff); + item.bounds_min.y = (pack.pack0 >> FfxUInt32(10)) & FfxUInt32(0x3ff); + item.bounds_min.z = (pack.pack0 >> FfxUInt32(20)) & FfxUInt32(0x3ff); + item.bounds_max.x = (pack.pack1 >> FfxUInt32(0)) & FfxUInt32(0x3ff); + item.bounds_max.y = (pack.pack1 >> FfxUInt32(10)) & FfxUInt32(0x3ff); + item.bounds_max.z = (pack.pack1 >> FfxUInt32(20)) & FfxUInt32(0x3ff); + return item; +} + +struct FfxBrixelizerCRVoxelTriangleBounds { + FfxFloat32x3 bound_min; + FfxFloat32x3 bound_max; + FfxUInt32x3 ubound_min; + FfxUInt32x3 ubound_max; +}; + +FfxBrixelizerTriangle FetchTriangle(FfxBrixelizerBasicMeshInfo instance_info, FfxUInt32 instance_id, FfxUInt32 job_idx, FfxUInt32 triangle_index) +{ + FfxBrixelizerTrianglePos pos = FfxBrixelizerFetchTriangle(instance_info, instance_id, triangle_index); + + FfxBrixelizerTriangle tri; + tri.face3 = pos.face3; + tri.job_idx = job_idx; + tri.triangle_index = triangle_index; + tri.wp0 = FfxFloat32x3(pos.wp0 - GetCascadeInfoGridMin()); + tri.wp1 = FfxFloat32x3(pos.wp1 - GetCascadeInfoGridMin()); + tri.wp2 = FfxFloat32x3(pos.wp2 - GetCascadeInfoGridMin()); + + return tri; +} + +FfxBoolean GetTriangleBounds(FfxUInt32 instance_id, FfxUInt32 job_idx, FfxBrixelizerBasicMeshInfo instance_info, FfxUInt32 triangle_index, FFX_PARAMETER_OUT FfxBrixelizerTriangle tri, + FFX_PARAMETER_OUT FfxBrixelizerCRVoxelTriangleBounds tvbounds) +{ + FfxUInt32 job_num_triangles = instance_info.triangleCount; + if (triangle_index < job_num_triangles) { + tri = FetchTriangle(instance_info, instance_id, job_idx, triangle_index); + FfxFloat32 inflation_size = FfxFloat32(GetCascadeInfoVoxelSize() / FfxFloat32(7.0)); + tvbounds.bound_min = FfxFloat32x3(min(tri.wp0.x, min(tri.wp1.x, tri.wp2.x)), + min(tri.wp0.y, min(tri.wp1.y, tri.wp2.y)), + min(tri.wp0.z, min(tri.wp1.z, tri.wp2.z))); + tvbounds.bound_max = FfxFloat32x3(max(tri.wp0.x, max(tri.wp1.x, tri.wp2.x)), + max(tri.wp0.y, max(tri.wp1.y, tri.wp2.y)), + max(tri.wp0.z, max(tri.wp1.z, tri.wp2.z))); + + FfxFloat32x3 bounds_min; + + bounds_min.x = tvbounds.bound_min.x > FfxFloat32(0.0) ? tvbounds.bound_min.x : tvbounds.bound_min.x - FfxFloat32(1.0); + bounds_min.y = tvbounds.bound_min.y > FfxFloat32(0.0) ? tvbounds.bound_min.y : tvbounds.bound_min.y - FfxFloat32(1.0); + bounds_min.z = tvbounds.bound_min.z > FfxFloat32(0.0) ? tvbounds.bound_min.z : tvbounds.bound_min.z - FfxFloat32(1.0); + + tvbounds.ubound_min = min( + FFX_BROADCAST_INT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION - FfxUInt32(1)), + max( + FFX_BROADCAST_INT32X3(0), + FfxInt32x3((bounds_min - FFX_BROADCAST_FLOAT32X3(inflation_size)) / FfxFloat32(GetCascadeInfoVoxelSize())) + ) + ); + + FfxFloat32x3 bounds_max; + + bounds_max.x = tvbounds.bound_max.x > FfxFloat32(0.0) ? tvbounds.bound_max.x : tvbounds.bound_max.x - FfxFloat32(1.0); + bounds_max.y = tvbounds.bound_max.y > FfxFloat32(0.0) ? tvbounds.bound_max.y : tvbounds.bound_max.y - FfxFloat32(1.0); + bounds_max.z = tvbounds.bound_max.z > FfxFloat32(0.0) ? tvbounds.bound_max.z : tvbounds.bound_max.z - FfxFloat32(1.0); + + tvbounds.ubound_max = min( + FFX_BROADCAST_INT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION - FfxUInt32(1)), + max( + FFX_BROADCAST_INT32X3(0), + FfxInt32x3((bounds_max + FFX_BROADCAST_FLOAT32X3(inflation_size)) / FfxFloat32(GetCascadeInfoVoxelSize())) + ) + ) + + FFX_BROADCAST_INT32X3(1); + return all(FFX_LESS_THAN_EQUAL(tvbounds.bound_min, FfxFloat32x3(GetCascadeInfoGridMax() - GetCascadeInfoGridMin()) + FFX_BROADCAST_FLOAT32X3(inflation_size))) && + all(FFX_GREATER_THAN_EQUAL(tvbounds.bound_max, FFX_BROADCAST_FLOAT32X3(0.0) + FFX_BROADCAST_FLOAT32X3(-inflation_size))); + } + return false; +} + +void FfxBrixelizerStoreTriangleCenter(FfxUInt32 triangle_id_swap_offset, FfxBrixelizerTriangle tri) +{ + StoreScratchIndexSwapFloat3(triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT, (tri.wp0 + tri.wp1 + tri.wp2) / FfxFloat32(3.0)); +} + +FfxFloat32x3 FfxBrixelizerLoadTriangleCenter(FfxUInt32 triangle_id_swap_offset) +{ + return LoadScratchIndexSwapFloat3(triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT); +} + +struct FfxBrixelizerTrianglePartial { + FfxFloat32x3 wp0; + FfxFloat32x3 wp1; + FfxFloat32x3 wp2; +}; + +struct FfxBrixelizerTrianglePartialCompressed { + FfxUInt32x2 wp0xy; + FfxUInt32x2 ed0; + FfxUInt32x2 ed1; +}; + +// Compress to f32x3 v0 and f16x3 e0, e1 and store +void FfxBrixelizerStoreTrianglePartial(FfxUInt32 triangle_id_swap_offset, FfxBrixelizerTriangle tri) +{ + FfxBrixelizerTrianglePartialCompressed trip; + trip.wp0xy = ffxAsUInt32(tri.wp0.xy); + FfxFloat32x3 e0 = tri.wp1 - tri.wp0; + FfxFloat32x3 e1 = tri.wp2 - tri.wp0; + FfxFloat32x4 v0 = FfxFloat32x4(e0.xyz, e1.x); + trip.ed0 = ffxPackF32x2(v0); + trip.ed1.x = ffxPackF32(e1.yz); + trip.ed1.y = ffxAsUInt32(tri.wp0.z); + StoreScratchIndexSwapUInt2((triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT) + FfxUInt32(0), trip.wp0xy); + StoreScratchIndexSwapUInt2((triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT) + FfxUInt32(2), trip.ed0); + StoreScratchIndexSwapUInt2((triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT) + FfxUInt32(4), trip.ed1); +} + +void FfxBrixelizerLoadTrianglePartial(FfxUInt32 triangle_id_swap_offset, FFX_PARAMETER_OUT FfxBrixelizerTrianglePartial tri) +{ + FfxBrixelizerTrianglePartialCompressed tripc; + tripc.wp0xy = LoadScratchIndexSwapUInt2((triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT) + FfxUInt32(0)); + tripc.ed0 = LoadScratchIndexSwapUInt2((triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT) + FfxUInt32(2)); + tripc.ed1 = LoadScratchIndexSwapUInt2((triangle_id_swap_offset / FFX_BRIXELIZER_SIZEOF_UINT) + FfxUInt32(4)); + tri.wp0.xy = ffxAsFloat(tripc.wp0xy.xy); + tri.wp0.z = ffxAsFloat(tripc.ed1.y); + FfxFloat32x4 v0 = ffxUnpackF32x2(tripc.ed0); + FfxFloat32x2 v1 = ffxUnpackF32(tripc.ed1.x); + tri.wp1 = tri.wp0 + FfxFloat32x3(v0.xyz); + tri.wp2 = tri.wp0 + FfxFloat32x3(v0.w, v1.xy); +} + +// Integer scan +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_scan_buffer[FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE]; +FFX_GROUPSHARED FfxUInt32 gs_ffx_brixelizer_scan_group_id; +FfxUInt32 GroupScanExclusiveAdd(FfxUInt32 gid, FfxUInt32 group_size) +{ + FfxUInt32 sum = FfxUInt32(0); + for (FfxUInt32 stride = FfxUInt32(1); stride <= (group_size >> FfxUInt32(1)); stride <<= FfxUInt32(1)) { + if (gid < group_size / (FfxUInt32(2) * stride)) { + gs_ffx_brixelizer_scan_buffer[FfxUInt32(2) * (gid + FfxUInt32(1)) * stride - FfxUInt32(1)] += gs_ffx_brixelizer_scan_buffer[(FfxUInt32(2) * gid + FfxUInt32(1)) * stride - FfxUInt32(1)]; + } + FFX_GROUP_MEMORY_BARRIER; + } + + if (gid == FfxUInt32(0)) { + sum = gs_ffx_brixelizer_scan_buffer[group_size - FfxUInt32(1)]; + gs_ffx_brixelizer_scan_buffer[group_size - FfxUInt32(1)] = FfxUInt32(0); + } + FFX_GROUP_MEMORY_BARRIER; + + for (FfxUInt32 stride = (group_size >> FfxUInt32(1)); stride > FfxUInt32(0); stride >>= FfxUInt32(1)) { + if (gid < group_size / (FfxUInt32(2) * stride)) { + FfxUInt32 tmp = gs_ffx_brixelizer_scan_buffer[(FfxUInt32(2) * gid + FfxUInt32(1)) * stride - FfxUInt32(1)]; + gs_ffx_brixelizer_scan_buffer[(FfxUInt32(2) * gid + FfxUInt32(1)) * stride - FfxUInt32(1)] = gs_ffx_brixelizer_scan_buffer[FfxUInt32(2) * (gid + FfxUInt32(1)) * stride - FfxUInt32(1)]; + gs_ffx_brixelizer_scan_buffer[FfxUInt32(2) * (gid + FfxUInt32(1)) * stride - FfxUInt32(1)] = gs_ffx_brixelizer_scan_buffer[FfxUInt32(2) * (gid + FfxUInt32(1)) * stride - FfxUInt32(1)] + tmp; + } + FFX_GROUP_MEMORY_BARRIER; + } + + return sum; +} + +FfxUInt32 LoadJobTriangleCountScan(FfxUInt32 job_idx) +{ + return LoadScratchJobCountersScan(job_idx) + LoadGlobalJobTriangleCounterScan(job_idx / FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE); +} + +FfxUInt32 JobLowerBound(FfxUInt32 triangle_offset, FfxUInt32 total_job_count) +{ +#define LOWER_BOUND_LOAD(mid) LoadJobTriangleCountScan(mid) + + FfxUInt32 LOWER_BOUND_RESULT; + + LOWER_BOUND(triangle_offset, total_job_count); + +#undef LOWER_BOUND_LOAD + + return LOWER_BOUND_RESULT; +} + +FfxUInt32 JobLowerBoundBySubvoxel(FfxUInt32 subvoxel_offset, FfxUInt32 total_job_count) +{ +#define LOWER_BOUND_LOAD(mid) LoadJobIndex(mid) + + FfxUInt32 LOWER_BOUND_RESULT; + + LOWER_BOUND(subvoxel_offset, total_job_count); + +#undef LOWER_BOUND_LOAD + + return LOWER_BOUND_RESULT; +} + +// One group performs global scan for all the other groups +#define GROUP_SCAN(gid, total_group_count, group_size, LoadGlobal, StoreGlobal) \ + { \ + FFX_GROUP_MEMORY_BARRIER; \ + if (gid == FfxUInt32(0)) gs_ffx_brixelizer_scan_group_id = FfxUInt32(0); \ + FFX_GROUP_MEMORY_BARRIER; \ + for (FfxUInt32 cursor = FfxUInt32(0); cursor < total_group_count; cursor += group_size) { \ + FFX_GROUP_MEMORY_BARRIER; \ + if (gid + cursor < total_group_count) \ + gs_ffx_brixelizer_scan_buffer[gid] = LoadGlobal(gid + cursor); \ + else \ + gs_ffx_brixelizer_scan_buffer[gid] = FfxUInt32(0); \ + FFX_GROUP_MEMORY_BARRIER; \ + FfxUInt32 sum = GroupScanExclusiveAdd(gid, group_size); \ + \ + if (gid + cursor < total_group_count) StoreGlobal(gid + cursor, gs_ffx_brixelizer_scan_buffer[gid] + gs_ffx_brixelizer_scan_group_id); \ + \ + FFX_GROUP_MEMORY_BARRIER; \ + \ + if (gid == FfxUInt32(0)) gs_ffx_brixelizer_scan_group_id += sum; \ + } \ + } + +// Used for group scan macros +FfxUInt32 StampLowerBound(FfxUInt32 item_id) +{ +#define LOWER_BOUND_LOAD(mid) LoadScratchCR1StampScan(mid) + + FfxUInt32 LOWER_BOUND_RESULT; + + LOWER_BOUND(item_id, FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION); + +#undef LOWER_BOUND_LOAD + + return LOWER_BOUND_RESULT; +} + +void AddBrickToCompressionList(FfxUInt32 brick_id) +{ + FfxUInt32 offset; + IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_COMPRESSION_BRICKS, FfxUInt32(1), offset); + StoreScratchBricksCompressionList(offset, brick_id); +} + +FfxUInt32 AllocateBrick() +{ + FfxUInt32 brick_idx; + IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_NUM_BRICKS_ALLOCATED, FfxUInt32(1), brick_idx); + if (brick_idx > GetBuildInfo().max_bricks_per_bake) { + return FFX_BRIXELIZER_INVALID_ID; + } + + FfxUInt32 val; + IncrementContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_BRICK_COUNT, FfxUInt32(1), val); + if (val >= LoadContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_FREE_BRICKS)) return FFX_BRIXELIZER_INVALID_ID; + FfxUInt32 brick_id = LoadBricksFreeList(val); + return brick_id; +} + +void MapBrickToVoxel(FfxUInt32 brick_id, FfxUInt32 voxel_id) +{ + voxel_id |= (GetCascadeInfoIndex()) << FFX_BRIXELIZER_CASCADE_ID_SHIFT; + StoreBricksVoxelMap(FfxBrixelizerBrickGetIndex(brick_id), voxel_id); +} + +FfxUInt32 BrickGetStorageOffset(FfxUInt32 brick_id) +{ + return LoadScratchBricksStorageOffsets(FfxBrixelizerBrickGetIndex(brick_id)); +} + +FfxUInt32 AllocateStorage(FfxUInt32 brick_id) +{ + FfxUInt32 dim = FfxUInt32(8); + FfxUInt32 size = dim * dim * dim * FfxUInt32(4); + FfxUInt32 offset; + IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_STORAGE_OFFSET, size, offset); + if (offset + size > LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_STORAGE_SIZE)) { + StoreScratchBricksStorageOffsets(FfxBrixelizerBrickGetIndex(brick_id), FFX_BRIXELIZER_INVALID_ALLOCATION); + return FFX_BRIXELIZER_INVALID_ALLOCATION; + } + StoreScratchBricksStorageOffsets(FfxBrixelizerBrickGetIndex(brick_id), offset); + return offset; +} + +void AppendClearBrick(FfxUInt32 brick_id) +{ + FfxUInt32 offset; + IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_CLEAR_BRICKS, 1, offset); + StoreScratchBricksClearList(offset, brick_id); +} + +// Utilities for 32 scratch space for atomics to work +FfxFloat32 LoadBrixelData32(FfxUInt32 brick_id, FfxInt32x3 coord) +{ + FfxInt32 brick_dim = FfxInt32(8); + if (any(FFX_GREATER_THAN_EQUAL(coord, FFX_BROADCAST_INT32X3(brick_dim))) || any(FFX_LESS_THAN(coord, FFX_BROADCAST_INT32X3(0)))) return FfxFloat32(1.0); + + const FfxUInt32 brick_size = brick_dim * brick_dim * brick_dim * FFX_BRIXELIZER_SIZEOF_UINT; + FfxUInt32 offset = FfxBrixelizerFlattenPOT(coord, 3); + offset += BrickGetStorageOffset(brick_id) / FFX_BRIXELIZER_SIZEOF_UINT; + FfxUInt32 uval = LoadScratchBricksStorage(offset); + return FfxBrixelizerUnpackDistance(uval); +} + +void BrickInterlockedMin32(FfxUInt32 brick_id, FfxInt32x3 coord, FfxUInt32 uval) +{ + FfxInt32 brick_dim = 8; + if (any(FFX_GREATER_THAN_EQUAL(coord, FFX_BROADCAST_INT32X3(brick_dim))) || any(FFX_LESS_THAN(coord, FFX_BROADCAST_INT32X3(0)))) return; + + const FfxUInt32 brick_size = brick_dim * brick_dim * brick_dim * FFX_BRIXELIZER_SIZEOF_UINT; + FfxUInt32 offset = FfxBrixelizerFlattenPOT(coord, 3) * FFX_BRIXELIZER_SIZEOF_UINT; + offset += BrickGetStorageOffset(brick_id); + MinScratchBricksStorage(offset / FFX_BRIXELIZER_SIZEOF_UINT, uval); +} + +void BrickInterlockedMin32(FfxUInt32 brick_id, FfxInt32x3 coord, FfxFloat32 fval) +{ + BrickInterlockedMin32(brick_id, coord, FfxBrixelizerPackDistance(fval)); +} + +void ClearBrixelData32(FfxUInt32 brick_id, FfxInt32x3 coord) +{ + FfxInt32 brick_dim = 8; + if (any(FFX_GREATER_THAN_EQUAL(coord, FFX_BROADCAST_INT32X3(brick_dim))) || any(FFX_LESS_THAN(coord, FFX_BROADCAST_INT32X3(0)))) return; + + FfxUInt32 offset = FfxBrixelizerFlattenPOT(coord, 3) * FFX_BRIXELIZER_SIZEOF_UINT; + offset += BrickGetStorageOffset(brick_id); + StoreScratchBricksStorage(offset / FFX_BRIXELIZER_SIZEOF_UINT, FfxBrixelizerPackDistance(FfxFloat32(1.0))); +} + +void InitializeIndirectArgs(FfxUInt32 subvoxel_count) +{ + { + FfxUInt32 tier_cnt = LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_CLEAR_BRICKS); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_CLEAR_BRICKS_32 + 0, tier_cnt * 8); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_CLEAR_BRICKS_32 + 1, 1); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_CLEAR_BRICKS_32 + 2, 1); + } + { + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_EMIT_SDF_32 + 0, subvoxel_count); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_EMIT_SDF_32 + 1, 1); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_EMIT_SDF_32 + 2, 1); + } + { + FfxUInt32 tier_cnt = LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_COMPRESSION_BRICKS); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_COMPRESS_32 + 0, tier_cnt); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_COMPRESS_32 + 1, 1); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_COMPRESS_32 + 2, 1); + } + { + FfxUInt32 total_cell_count = FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION; + FfxUInt32 total_references = min(LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_REFERENCES), LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_MAX_REFERENCES)); + FfxUInt32 total_thread_count = max(total_cell_count, total_references); + + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_COMPACT_REFERENCES_32 + 0, (total_thread_count + FFX_BRIXELIZER_STATIC_CONFIG_COMPACT_REFERENCES_GROUP_SIZE - 1) / FFX_BRIXELIZER_STATIC_CONFIG_COMPACT_REFERENCES_GROUP_SIZE); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_COMPACT_REFERENCES_32 + 1, 1); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_COMPACT_REFERENCES_32 + 2, 1); + } +} + +void InitializeJobIndirectArgs(FfxUInt32 num_triangles) +{ + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_VOXELIZE_32 + 0, (num_triangles + FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE - 1) / FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_VOXELIZE_32 + 1, 1); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_VOXELIZE_32 + 2, 1); +} + +void FfxBrixelizerClearBuildCounters() +{ + for (FfxUInt32 i = FfxUInt32(0); i < FFX_BRIXELIZER_NUM_SCRATCH_COUNTERS; i++) { + StoreScratchCounter(i, FfxUInt32(0)); + } + FfxUInt32 storage_size; + GetScratchBricksStorageDimensions(storage_size); + StoreScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_STORAGE_SIZE, storage_size); + GetScratchIndexSwapDimensions(storage_size); + StoreScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_MAX_TRIANGLES, storage_size); + GetScratchMaxReferences(storage_size); + StoreScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_MAX_REFERENCES, storage_size); + for (FfxUInt32 i = 0; i < FFX_BROADCAST_UINT32(FFX_BRIXELIZER_NUM_INDIRECT_OFFSETS) * FFX_BROADCAST_UINT32(FFX_BRIXELIZER_STATIC_CONFIG_INDIRECT_DISPATCH_STRIDE32); i++) { + StoreIndirectArgs(i, FfxUInt32(0)); + } +} + +void FfxBrixelizerResetCascade(FfxUInt32 tid) +{ + if (tid < FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION) { + FfxUInt32 brick_id = LoadCascadeBrickMap(tid); + if (FfxBrixelizerIsValidID(brick_id)) { + FfxBrixelizerMarkBrickFree(brick_id); + } + StoreCascadeBrickMap(tid, FFX_BRIXELIZER_UNINITIALIZED_ID); + } +} + +void FfxBrixelizerInitializeCascade(FfxUInt32 tid) +{ + if (tid < FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION) { + FfxUInt32 brick_id = LoadCascadeBrickMap(tid); + if (brick_id == FFX_BRIXELIZER_UNINITIALIZED_ID) { + StoreCascadeBrickMap(tid, FFX_BRIXELIZER_INVALID_ID); + } + } +} + +void FfxBrixelizerMarkCascadeUninitialized(FfxUInt32 tid) +{ + if (tid < FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION) { + StoreCascadeBrickMap(tid, FFX_BRIXELIZER_UNINITIALIZED_ID); + } +} + +void FfxBrixelizerFreeCascade(FfxUInt32 tid) +{ + if (tid < FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION) { + FfxUInt32 brick_id = LoadCascadeBrickMap(tid); + if (FfxBrixelizerIsValidID(brick_id)) { + FfxBrixelizerMarkBrickFree(brick_id); + } + StoreCascadeBrickMap(tid, FFX_BRIXELIZER_UNINITIALIZED_ID); + } +} + +void FfxBrixelizerScrollCascade(FfxUInt32 tid) +{ + if (all(FFX_LESS_THAN(FfxBrixelizerUnflattenPOT(tid, FFX_BRIXELIZER_CASCADE_DEGREE), FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION)))) { + FfxInt32x3 voxel_coord = to_int3(FfxBrixelizerUnflattenPOT(tid, FFX_BRIXELIZER_CASCADE_DEGREE)); +#ifdef FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMap(WrapFlatCoords(voxel_idx)); + StoreCascadeBrickMap(WrapFlatCoords(voxel_idx), FFX_BRIXELIZER_UNINITIALIZED_ID); +#else // !FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + + // Scrolling clipmap update + if (any(FFX_LESS_THAN(voxel_coord, -GetCascadeInfoClipmapInvalidationOffset())) || any(FFX_GREATER_THAN_EQUAL(voxel_coord, FFX_BROADCAST_INT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION) - GetCascadeInfoClipmapInvalidationOffset()))) { + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMap(WrapFlatCoords(voxel_idx)); + if (FfxBrixelizerIsValidID(brick_id)) { + FfxBrixelizerMarkBrickFree(brick_id); + } + StoreCascadeBrickMap(WrapFlatCoords(voxel_idx), FFX_BRIXELIZER_UNINITIALIZED_ID); + } + +#endif // !FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + } +} + +void FfxBrixelizerClearRefCounters(FfxUInt32 tid) +{ + FfxUInt32x3 voxel_coord = FfxBrixelizerUnflattenPOT(tid, FFX_BRIXELIZER_CASCADE_DEGREE); + if (all(FFX_LESS_THAN(voxel_coord, FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION)))) { + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxBrixelizerClearRefCounter(voxel_idx); + } +} + +void FfxBrixelizerClearJobCounter(FfxUInt32 tid) +{ + if (tid < GetBuildInfoNumJobs()) StoreScratchJobCounter(tid, FfxUInt32(0)); +} + +void FfxBrixelizerInvalidateJobAreas(FfxUInt32 gtid, FfxUInt32 group_id) +{ + + FfxUInt32 thread_subvoxel_offset = group_id * FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE + gtid; + FfxUInt32 job_idx = JobLowerBoundBySubvoxel(thread_subvoxel_offset, GetBuildInfoNumJobs()); + + if (job_idx < GetBuildInfoNumJobs()) { + FfxBrixelizerBrixelizationJob job = LoadBrixelizationJob(job_idx); + FfxUInt32 subvoxel_id = thread_subvoxel_offset - LoadJobIndex(job_idx); + FfxInt32x3 dim = FfxInt32x3(job.aabbMax - job.aabbMin); + + ffxassert(all(job.aabbMax > FFX_BROADCAST_UINT32X3(0))); + ffxassert(all(job.aabbMin >= FFX_BROADCAST_UINT32X3(0))); + ffxassert(all(job.aabbMin < FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + ffxassert(all(job.aabbMax > job.aabbMin)); + ffxassert(all(job.aabbMax <= FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + + if (FFX_HAS_FLAG(job.flags, FFX_BRIXELIZER_JOB_FLAG_INVALIDATE)) { + if (subvoxel_id < dim.x * dim.y * dim.z) { + FfxUInt32x3 subvoxel_coord = FfxBrixelizerUnflatten(subvoxel_id, dim); + FfxUInt32x3 global_voxel_coord = subvoxel_coord + job.aabbMin; + ffxassert(all(global_voxel_coord >= FFX_BROADCAST_UINT32X3(0)) && all(global_voxel_coord < FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + FfxUInt32 brick_id = LoadCascadeBrickMap(WrapFlatCoords(FfxBrixelizerFlattenPOT(global_voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE))); + if (brick_id != FFX_BRIXELIZER_UNINITIALIZED_ID) { + FfxBrixelizerMarkBrickFree(brick_id); + StoreCascadeBrickMap(WrapFlatCoords(FfxBrixelizerFlattenPOT(global_voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE)), FFX_BRIXELIZER_UNINITIALIZED_ID); + } + } + } else { + } + } +} + +void FfxBrixelizerCoarseCulling(FfxUInt32 gtid, FfxUInt32 group_id) +{ + FfxUInt32 thread_subvoxel_offset = group_id * FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE + gtid; + FfxUInt32 job_idx = JobLowerBoundBySubvoxel(thread_subvoxel_offset, GetBuildInfoNumJobs()); + + FfxBoolean needs_rebuild = false; + + if (job_idx < GetBuildInfoNumJobs()) { + FfxBrixelizerBrixelizationJob job = LoadBrixelizationJob(job_idx); + FfxUInt32 subvoxel_id = thread_subvoxel_offset - LoadJobIndex(job_idx); + FfxInt32x3 dim = FfxInt32x3(job.aabbMax - job.aabbMin); + + ffxassert(all(job.aabbMax > FFX_BROADCAST_UINT32X3(0))); + ffxassert(all(job.aabbMin >= FFX_BROADCAST_UINT32X3(0))); + ffxassert(all(job.aabbMin < FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + ffxassert(all(job.aabbMax > job.aabbMin)); + ffxassert(all(job.aabbMax <= FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + if (FFX_HAS_FLAG(job.flags, FFX_BRIXELIZER_JOB_FLAG_INVALIDATE)) { + } else { + if (subvoxel_id < dim.x * dim.y * dim.z) { + FfxUInt32x3 subvoxel_coord = FfxBrixelizerUnflatten(subvoxel_id, dim); + FfxUInt32x3 global_voxel_coord = subvoxel_coord + job.aabbMin; + ffxassert(all(global_voxel_coord >= FFX_BROADCAST_UINT32X3(0)) && all(global_voxel_coord < FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(global_voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxBoolean this_needs_rebuild = CanBuildThisVoxel(voxel_idx); +#ifdef FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + this_needs_rebuild = true; +#else // !FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + +#endif // !FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + + needs_rebuild = this_needs_rebuild; + } + } + } + if (needs_rebuild) { + IncrementScratchJobCounter(job_idx, 1); + } +} + +void FfxBrixelizerScanJobs(FfxUInt32 job_idx, FfxUInt32 gtid, FfxUInt32 group_id) +{ + FfxBoolean is_touched = job_idx < GetBuildInfoNumJobs() && LoadScratchJobCounter(job_idx) > 0; + FfxBrixelizerBrixelizationJob job = LoadBrixelizationJob(job_idx); + FfxBrixelizerInstanceInfo instance_info = LoadInstanceInfo(job.instanceIdx); + + ffxassert((job.flags & FFX_BRIXELIZER_JOB_FLAG_INVALIDATE) == 0); + // Scan triangle counts so that later we can map thread_id -> job_idx + { + gs_ffx_brixelizer_scan_buffer[gtid] = is_touched ? instance_info.triangleCount : 0; + FFX_GROUP_MEMORY_BARRIER; + FfxUInt32 sum = GroupScanExclusiveAdd(gtid, FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE); + if (job_idx < GetBuildInfoNumJobs()) StoreScratchJobCountersScan(job_idx, gs_ffx_brixelizer_scan_buffer[gtid]); + + if (gtid == 0) // The first thread stores the sum + StoreGlobalJobTriangleCounterScan(group_id, sum); + } + if (gtid == 0) IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_GROUP_INDEX, 1, gs_ffx_brixelizer_scan_group_id); + + FfxUInt32 total_group_count = (GetBuildInfoNumJobs() + FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE - 1) / FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE; + + FFX_GROUP_MEMORY_BARRIER; // Wait for gs_ffx_brixelizer_scan_group_id + if (total_group_count - 1 == gs_ffx_brixelizer_scan_group_id) { // the last group does the rest of the scans + + GROUP_SCAN(gtid, + total_group_count, + FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE, + LoadGlobalJobTriangleCounterScan, + StoreGlobalJobTriangleCounterScan); + + if (gtid == 0) { + StoreScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_GROUP_INDEX, FfxUInt32(0)); + InitializeJobIndirectArgs(gs_ffx_brixelizer_scan_group_id); + } + } +} + +void FfxBrixelizerVoxelize(FfxUInt32 gtid, FfxUInt32 group_id) +{ + if (gtid == 0) { + gs_ffx_brixelizer_voxelizer_item_counter = 0; + gs_ffx_brixelizer_voxelizer_ref_counter = 0; + gs_ffx_brixelizer_voxelizer_ref_offset = 0; + gs_ffx_brixelizer_triangle_offset_global = 0; + gs_ffx_brixelizer_triangle_offset = 0; + } + FFX_GROUP_MEMORY_BARRIER; // Wait for initialization + + FfxUInt32 thread_triangle_offset = group_id * FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE + gtid; + FfxUInt32 job_idx = JobLowerBound(thread_triangle_offset, GetBuildInfoNumJobs()); + FfxBoolean is_touched = job_idx < GetBuildInfoNumJobs() && LoadScratchJobCounter(job_idx) > 0; + FfxUInt32 triangle_index = thread_triangle_offset - LoadJobTriangleCountScan(job_idx); + FfxBrixelizerTriangle tri; + FfxBrixelizerCRVoxelTriangleBounds tvbounds; + FfxBoolean collides = false; + if (is_touched) { + FfxBrixelizerBrixelizationJob job = LoadBrixelizationJob(job_idx); + FfxBrixelizerInstanceInfo instance_info = LoadInstanceInfo(job.instanceIdx); + if (triangle_index < instance_info.triangleCount) { + collides = GetTriangleBounds(job.instanceIdx, job_idx, ffxBrixelizerInstanceInfoGetMeshInfo(instance_info), triangle_index, /* out */ tri, + /* out */ tvbounds); + } + } + + ffxassert(!collides || all(tvbounds.ubound_max <= FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + ffxassert(!collides || all(tvbounds.ubound_min < FFX_BROADCAST_UINT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION))); + + FfxUInt32 item_offset; + + if (collides) { + FFX_ATOMIC_ADD_RETURN(gs_ffx_brixelizer_voxelizer_item_counter, 1, item_offset); + + FfxBrixelizerCRItem item; + item.bounds_min = tvbounds.ubound_min; + item.bounds_max = tvbounds.ubound_max; + + FfxBrixelizerCRStoreItem(FfxInt32(item_offset), item); + + FfxUInt32x3 dim = tvbounds.ubound_max - tvbounds.ubound_min; + +#if defined(FFX_BRIXELIZER_VOXELIZER_2D) + FfxUInt32 num_refs = dim.x * dim.z; +#else // !defined(FFX_BRIXELIZER_VOXELIZER_2D) + FfxUInt32 num_refs = dim.x * dim.y * dim.z; +#endif // !defined(FFX_BRIXELIZER_VOXELIZER_2D) + FFX_ATOMIC_ADD(gs_ffx_brixelizer_voxelizer_ref_counter, num_refs); + gs_ffx_brixelizer_voxelizer_items_ref_count[item_offset] = num_refs; + gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_offset] = 0; + } + + FFX_GROUP_MEMORY_BARRIER; // Wait for gs_ffx_brixelizer_voxelizer_ref_counter + + if (gs_ffx_brixelizer_voxelizer_item_counter == FfxUInt32(0)) return; // scalar + +#if defined(FFX_BRIXELIZER_VOXELIZER_CHECK_BRICKS) + { + FfxUInt32 item_id = FfxUInt32(0); + FfxUInt32 ref_scan = FfxUInt32(0); + for (FfxUInt32 ref_id = gtid; ref_id < gs_ffx_brixelizer_voxelizer_ref_counter; ref_id += FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE) { + while (ref_id >= gs_ffx_brixelizer_voxelizer_items_ref_count[item_id] + ref_scan) { + ref_scan += gs_ffx_brixelizer_voxelizer_items_ref_count[item_id]; + item_id++; + } + if (ref_id >= gs_ffx_brixelizer_voxelizer_ref_counter) break; + FfxUInt32 local_ref_id = ref_id - ref_scan; + FfxBrixelizerCRItem item = FfxBrixelizerCRLoadItem(item_id); + FfxUInt32x3 dim = item.bounds_max - item.bounds_min; + +# if defined(FFX_BRIXELIZER_VOXELIZER_2D) + FfxUInt32x2 local_voxel_coord = FfxBrixelizerUnflatten(local_ref_id, dim.xz); + + for (FfxUInt32 y = FfxUInt32(0); y < dim.y; y++) { + FfxUInt32x3 global_voxel_coord = FfxUInt32x3(local_voxel_coord.x, y, local_voxel_coord.y) + item.bounds_min; + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(global_voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + if (CanBuildThisVoxel(voxel_idx)) { + FFX_ATOMIC_OR(gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_id], FfxUInt32(1)); + } + } +# else // !defined(FFX_BRIXELIZER_VOXELIZER_2D) + FfxUInt32x3 local_voxel_coord = FfxBrixelizerUnflatten(local_ref_id, dim); + FfxUInt32x3 global_voxel_coord = local_voxel_coord + item.bounds_min; + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(global_voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + if (CanBuildThisVoxel(voxel_idx)) { + FFX_ATOMIC_OR(gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_id], FfxUInt32(1)); + } +# endif // !defined(FFX_BRIXELIZER_VOXELIZER_2D) + } + } + +#endif // defined(FFX_BRIXELIZER_VOXELIZER_CHECK_BRICKS) + + FFX_GROUP_MEMORY_BARRIER; + + const FfxUInt32 MAX_STORAGE = LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_MAX_TRIANGLES); + + FfxFloat32x3 bounds = tvbounds.bound_max - tvbounds.bound_min; + FfxFloat32 aabb_max_dim = ffxMax3(bounds.x, bounds.y, bounds.z); + FfxFloat32 voxel_size_ratio = aabb_max_dim / GetCascadeInfoVoxelSize(); + FfxBoolean small_triangle = voxel_size_ratio < FfxFloat32(1.0e-1); // 1/10th of a brick is small enough for the point approximation + + FfxUInt32 triangle_size = FfxUInt32(0); + if (small_triangle) + triangle_size = FfxUInt32(12); + else + triangle_size = FfxUInt32(24); + +#if defined(FFX_BRIXELIZER_VOXELIZER_CHECK_BRICKS) + FfxUInt32 hit_cnt = gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_offset]; +#else // ! defined(FFX_BRIXELIZER_VOXELIZER_CHECK_BRICKS) + FfxUInt32 hit_cnt = 1; +#endif // ! defined(FFX_BRIXELIZER_VOXELIZER_CHECK_BRICKS) + FfxUInt32 local_triangle_swap_offset; + + if (collides && hit_cnt != FfxUInt32(0)) FFX_ATOMIC_ADD_RETURN(gs_ffx_brixelizer_triangle_offset, triangle_size, local_triangle_swap_offset); + + FFX_GROUP_MEMORY_BARRIER; + + if (gtid == FfxUInt32(0)) { + IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_TRIANGLES, /* in */ gs_ffx_brixelizer_triangle_offset, + /* out */ gs_ffx_brixelizer_triangle_offset_global); + // Check that there's enough swap space for the triangles + gs_ffx_brixelizer_voxelizer_has_space = gs_ffx_brixelizer_triangle_offset_global + gs_ffx_brixelizer_triangle_offset <= MAX_STORAGE; + } + + FFX_GROUP_MEMORY_BARRIER; + + // Swap only triangles that have enough resources to get voxelized + if (collides && gs_ffx_brixelizer_voxelizer_has_space) { + if (hit_cnt != FfxUInt32(0)) { + FfxUInt32 triangle_id_swap_offset = local_triangle_swap_offset + gs_ffx_brixelizer_triangle_offset_global; + if (small_triangle) { + FfxBrixelizerStoreTriangleCenter(triangle_id_swap_offset, tri); + triangle_id_swap_offset |= FFX_BRIXELIZER_TRIANGLE_SMALL_FLAG; + } else + FfxBrixelizerStoreTrianglePartial(triangle_id_swap_offset, tri); + gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_offset] = triangle_id_swap_offset; + } else { + gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_offset] = FfxUInt32(-1); + } + } + + FFX_GROUP_MEMORY_BARRIER; + + { + FfxUInt32 item_id = FfxUInt32(0); + FfxUInt32 ref_scan = FfxUInt32(0); + for (FfxUInt32 ref_id = gtid; ref_id < gs_ffx_brixelizer_voxelizer_ref_counter; ref_id += FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE) { + while (ref_id >= gs_ffx_brixelizer_voxelizer_items_ref_count[item_id] + ref_scan) { + ref_scan += gs_ffx_brixelizer_voxelizer_items_ref_count[item_id]; + item_id++; + } + if (ref_id >= gs_ffx_brixelizer_voxelizer_ref_counter) break; + if (gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_id] == FfxUInt32(-1)) continue; // Skip if culled + + FfxUInt32 local_ref_id = ref_id - ref_scan; + FfxBrixelizerCRItem item = FfxBrixelizerCRLoadItem(FfxInt32(item_id)); + FfxUInt32x3 dim = item.bounds_max - item.bounds_min; + FfxUInt32 num_cells = dim.x * dim.y * dim.z; + +#if defined(FFX_BRIXELIZER_VOXELIZER_2D) + FfxUInt32x2 local_voxel_coord = FfxBrixelizerUnflatten(local_ref_id, dim.xz); + + // Only cull if the number of cells is more than N + FfxBoolean check_range = !FfxBrixelizerTriangleIsSmall(gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_id]) && num_cells > FfxUInt32(1); + FfxBrixelizerTrianglePartial tri; + FfxFloat32x3 e0; + FfxFloat32x3 e1; + FfxFloat32x3 e2; + FfxFloat32x3 gn; + if (check_range) { + FfxBrixelizerLoadTrianglePartial(FfxBrixelizerTriangleIDGetOffset(gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_id]), /* out */ tri); + e0 = tri.wp1.xyz - tri.wp0.xyz; + e1 = tri.wp2.xyz - tri.wp1.xyz; + e2 = tri.wp0.xyz - tri.wp2.xyz; + gn = normalize(cross(e2, e0)); + } + for (FfxUInt32 y = FfxUInt32(0); y < dim.y; y++) { + FfxUInt32x3 global_voxel_coord = FfxUInt32x3(local_voxel_coord.x, y, local_voxel_coord.y) + item.bounds_min; + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(global_voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + if (check_range) { + FfxFloat32x3 voxel_offset = GetCascadeInfoVoxelSize() * (FfxFloat32x3(global_voxel_coord) + FFX_BROADCAST_FLOAT32X3(0.5)); + FfxFloat32 dist = abs(dot(gn, (voxel_offset - tri.wp0))); + if (dist > GetCascadeInfoVoxelSize() * FfxFloat32(2.0)) continue; + dist = CalculateDistanceToTriangle(voxel_offset, tri.wp0, tri.wp1, tri.wp2); + if (dist > GetCascadeInfoVoxelSize() * FfxFloat32(2.0)) continue; + } + if (!gs_ffx_brixelizer_voxelizer_has_space) { + MarkFailed(voxel_idx); + } else { + AddReferenceOrMarkVoxelFailed(voxel_idx, gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_id]); + } + } +#else // !defined(FFX_BRIXELIZER_VOXELIZER_2D) + FfxUInt32x3 local_voxel_coord = FfxBrixelizerUnflatten(local_ref_id, dim); + FfxUInt32x3 global_voxel_coord = local_voxel_coord + item.bounds_min; + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(global_voxel_coord, FFX_BRIXELIZER_CASCADE_DEGREE); + if (!gs_ffx_brixelizer_voxelizer_has_space) { + MarkFailed(voxel_idx); + } else { + AddReferenceOrMarkVoxelFailed(voxel_idx, gs_ffx_brixelizer_voxelizer_items_triangle_id_swap_offsets[item_id]); + } +#endif // !defined(FFX_BRIXELIZER_VOXELIZER_2D) + } + } +} + +void FfxBrixelizerScanReferences(FfxUInt32 voxel_flat_id, FfxUInt32 gtid, FfxUInt32 group_id) +{ + FfxUInt32 total_cell_count = (FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION); + FfxUInt32 total_group_count = (total_cell_count + FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE - FfxUInt32(1)) / FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE; + FfxUInt32 ref_count = voxel_flat_id < total_cell_count ? LoadScratchCR1RefCounter(voxel_flat_id) : FfxUInt32(0); + + FfxUInt32 failed_at_voxelizer = LoadScratchVoxelAllocationFailCounter(voxel_flat_id); + + if (failed_at_voxelizer != FfxUInt32(0)) { + ref_count = FfxUInt32(0); + FfxBrixelizerClearRefCounter(voxel_flat_id); + } + + FfxUInt32 brick_id = LoadCascadeBrickMap(WrapFlatCoords(voxel_flat_id)); + + // Brick allocation/deallocation logic + if (ref_count > 0) { + if (brick_id == FFX_BRIXELIZER_UNINITIALIZED_ID) { // Allocate a new brick + brick_id = AllocateBrick(); + if (FfxBrixelizerIsInvalidID(brick_id)) { + ref_count = FfxUInt32(0); + FfxBrixelizerClearRefCounter(voxel_flat_id); + StoreCascadeBrickMap(WrapFlatCoords(voxel_flat_id), FFX_BRIXELIZER_UNINITIALIZED_ID); + } else { + ffxassert(FfxBrixelizerIsValidID(brick_id)); + FfxUInt32 storage_alloc_offset = AllocateStorage(brick_id); + if (storage_alloc_offset == FFX_BRIXELIZER_INVALID_ALLOCATION) { + ref_count = FfxUInt32(0); + FfxBrixelizerClearRefCounter(voxel_flat_id); + FfxBrixelizerMarkBrickFree(brick_id); + StoreCascadeBrickMap(WrapFlatCoords(voxel_flat_id), FFX_BRIXELIZER_UNINITIALIZED_ID); + brick_id = FFX_BRIXELIZER_INVALID_ID; + } else { + AppendClearBrick(brick_id); + AddBrickToCompressionList(brick_id); + StoreCascadeBrickMap(WrapFlatCoords(voxel_flat_id), brick_id); + } + } + } else { // Already have an assigned brick + ref_count = FfxUInt32(0); // No need to rebuild + FfxBrixelizerClearRefCounter(voxel_flat_id); + } + } else { + if (failed_at_voxelizer == FfxUInt32(0) && // Restart next frame + brick_id == FFX_BRIXELIZER_UNINITIALIZED_ID) { + brick_id = FFX_BRIXELIZER_INVALID_ID; + StoreCascadeBrickMap(WrapFlatCoords(voxel_flat_id), FFX_BRIXELIZER_INVALID_ID); + FfxBrixelizerClearRefCounter(voxel_flat_id); + } + } + + if (FfxBrixelizerIsValidID(brick_id) && brick_id != FFX_BRIXELIZER_UNINITIALIZED_ID) { + MapBrickToVoxel(brick_id, voxel_flat_id); // Update mapping + } + + //////////////////////////////////////////////////// + { + // Scan the ref counts for sorting + gs_ffx_brixelizer_scan_buffer[gtid] = ref_count; + FFX_GROUP_MEMORY_BARRIER; + FfxUInt32 ref_sum = GroupScanExclusiveAdd(gtid, FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE); + StoreScratchCR1RefCounterScan(voxel_flat_id, gs_ffx_brixelizer_scan_buffer[gtid]); + + if (gtid == FfxUInt32(0)) // The first thread stores the sum + StoreVoxelReferenceGroupSum(group_id, ref_sum); + } + //////////////////////////////////////////////////// + { + // Scan the stamp counts for work distribution + FfxUInt32 stamp_count = FfxUInt32(0); + if ((ref_count > 0) && FfxBrixelizerIsValidID(brick_id)) { + stamp_count = ((ref_count + FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_REFS_PER_GROUP - FfxUInt32(1)) / FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_REFS_PER_GROUP); + } + gs_ffx_brixelizer_scan_buffer[gtid] = stamp_count; + FFX_GROUP_MEMORY_BARRIER; + FfxUInt32 stamp_sum = GroupScanExclusiveAdd(gtid, FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE); + StoreScratchCR1StampScan(voxel_flat_id, gs_ffx_brixelizer_scan_buffer[gtid]); + if (gtid == FfxUInt32(0)) // The first thread stores the sum + StoreStampGroupSum(group_id, stamp_sum); + } + + if (gtid == FfxUInt32(0)) IncrementScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_GROUP_INDEX, FfxUInt32(1), gs_ffx_brixelizer_scan_group_id); + + FFX_GROUP_MEMORY_BARRIER; // Wait for gs_ffx_brixelizer_scan_group_id + if (total_group_count - FfxUInt32(1) == gs_ffx_brixelizer_scan_group_id) { // the last group does the rest of the scans + + GROUP_SCAN(gtid, + total_group_count, + FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE, + LoadVoxelReferenceGroupSum, + StoreVoxelReferenceGroupSum); + + GROUP_SCAN(gtid, + total_group_count, + FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE, + LoadStampGroupSum, + StoreStampGroupSum); + + if (gtid == FfxUInt32(0)) { + StoreScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_GROUP_INDEX, FfxUInt32(0)); + InitializeIndirectArgs(gs_ffx_brixelizer_scan_group_id); + } + } +} + +void FfxBrixelizerCompactReferences(FfxUInt32 tid) +{ + FfxUInt32 total_cell_count = (FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION); + FfxUInt32 total_group_count = (total_cell_count + FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE - FfxUInt32(1)) / FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE; + + FfxUInt32 total_references = min(LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_REFERENCES), LoadScratchCounter(FFX_BRIXELIZER_SCRATCH_COUNTER_MAX_REFERENCES)); + if (tid < total_references) { + FfxBrixelizerTriangleReference ref = LoadScratchCR1Reference(tid); + FfxUInt32 voxel_id = ref.voxel_idx; + FfxUInt32 ref_count = LoadScratchCR1RefCounter(voxel_id); + if (ref_count > 0) { + ffxassert(ref.local_ref_idx < ref_count); + FfxUInt32 offset = GetReferenceOffset(voxel_id) + ref.local_ref_idx; + StoreScratchCR1CompactedReferences(offset, ref.triangle_id); + } + } + + if (tid < total_cell_count) { + FfxUInt32 group_scan_id = tid / FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE; + FfxUInt32 group_scan_value = LoadStampGroupSum(group_scan_id); + FfxUInt32 local_scan_value = LoadScratchCR1StampScan(tid); + FfxUInt32 stamp_offset = group_scan_value + local_scan_value; + StoreScratchCR1StampScan(tid, stamp_offset); + } +} + +void FfxBrixelizerEmitSDF(FfxUInt32 ref_id_offset, FfxUInt32 global_stamp_id) +{ + FfxUInt32 voxel_id = StampLowerBound(global_stamp_id); + FfxUInt32 brick_id = LoadCascadeBrickMap(WrapFlatCoords(voxel_id)); + FfxUInt32 ref_count = LoadScratchCR1RefCounter(voxel_id); + + if (FfxBrixelizerIsInvalidID(brick_id) || ref_count == FfxUInt32(0)) return; + + FfxUInt32 refbatch_count = (ref_count + FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_REFS_PER_GROUP - 1) / FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_REFS_PER_GROUP; + FfxUInt32 global_stamp_offset = LoadScratchCR1StampScan(voxel_id); + FfxUInt32 voxel_stamp_id = global_stamp_id - global_stamp_offset; + FfxUInt32 refbatch_id = voxel_stamp_id % refbatch_count; + FfxUInt32 voxel_ref_offset = GetReferenceOffset(voxel_id); + FfxUInt32 refbatch_item_offset = refbatch_id * FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_REFS_PER_GROUP; + FfxUInt32 start_ref_id = voxel_ref_offset + refbatch_item_offset; + FfxUInt32 end_ref_id = voxel_ref_offset + min(refbatch_item_offset + FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_REFS_PER_GROUP, ref_count); + + FfxUInt32x3 stamp_min = FfxUInt32x3(0, 0, 0); + FfxUInt32x3 stamp_max = stamp_min + FFX_BROADCAST_UINT32X3(8); + + const FfxFloat32 brick_width = FfxFloat32(8.0); + FfxUInt32x3 voxel_coord = FfxBrixelizerUnflattenPOT(voxel_id, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxFloat32 brixel_size = FfxFloat32(GetCascadeInfoVoxelSize() / (brick_width - FfxFloat32(FfxFloat32(1.0)))); + FfxFloat32 half_brixel_size = FfxFloat32(brixel_size / FfxFloat32(FfxFloat32(2.0))); + FfxFloat32x3 brick_min = to_float3(voxel_coord) * FfxFloat32(GetCascadeInfoVoxelSize()) - FFX_BROADCAST_FLOAT32X3(FfxFloat32(half_brixel_size)); + FfxFloat32x3 brick_max = brick_min + FFX_BROADCAST_FLOAT32X3(brixel_size * brick_width); + FfxFloat32 clamped_dist = ffxAsFloat(FfxUInt32(-1)); + for (FfxUInt32 ref_id = start_ref_id + ref_id_offset; ref_id < end_ref_id; ref_id += FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_GROUP_SIZE) { + FfxUInt32 triangle_id = LoadScratchCR1CompactedReferences(ref_id); + + if (FfxBrixelizerTriangleIsSmall(triangle_id)) { + FfxFloat32x3 center = FfxBrixelizerLoadTriangleCenter(FfxBrixelizerTriangleIDGetOffset(triangle_id)); + FfxFloat32x3 COORD = (center - brick_min) / (brixel_size); + FfxFloat32x3 VOXEL = clamp(floor(COORD), FFX_BROADCAST_FLOAT32X3(0.0), FFX_BROADCAST_FLOAT32X3(7.0)); + FfxFloat32x3 p = VOXEL + FFX_BROADCAST_FLOAT32X3(FfxFloat32(0.5)); + FfxFloat32 dist = dot2(p - COORD) * FfxFloat32(0.25) * FfxFloat32(0.25); + clamped_dist = FfxFloat32(1.0) * clamp(dist, FfxFloat32(0.0), FfxFloat32(1.0)); + BrickInterlockedMin32(brick_id, FfxInt32x3(VOXEL), clamped_dist); + } else { + + FfxBrixelizerTrianglePartial tri; + FfxBrixelizerLoadTrianglePartial(FfxBrixelizerTriangleIDGetOffset(triangle_id), /* out */ tri); + + FfxFloat32x3 TRIANGLE_VERTEX_0 = (tri.wp0 - brick_min) / (brixel_size); + FfxFloat32x3 TRIANGLE_VERTEX_1 = (tri.wp1 - brick_min) / (brixel_size); + FfxFloat32x3 TRIANGLE_VERTEX_2 = (tri.wp2 - brick_min) / (brixel_size); + const FfxFloat32 TRIANGLE_OFFSET = FfxFloat32(FfxFloat32(0.0)); + FfxFloat32x3 TRIANGLE_MIN = min(TRIANGLE_VERTEX_0, min(TRIANGLE_VERTEX_1, TRIANGLE_VERTEX_2)); + FfxFloat32x3 TRIANGLE_MAX = max(TRIANGLE_VERTEX_0, max(TRIANGLE_VERTEX_1, TRIANGLE_VERTEX_2)); + FfxFloat32x3 TRIANGLE_AABB_MIN; + FfxFloat32x3 TRIANGLE_AABB_MAX; + + TRIANGLE_AABB_MIN.x = (floor(TRIANGLE_MIN.x < FfxFloat32(0.0) ? TRIANGLE_MIN.x - FfxFloat32(1.0) : TRIANGLE_MIN.x)) - TRIANGLE_OFFSET; + TRIANGLE_AABB_MIN.y = (floor(TRIANGLE_MIN.y < FfxFloat32(0.0) ? TRIANGLE_MIN.y - FfxFloat32(1.0) : TRIANGLE_MIN.y)) - TRIANGLE_OFFSET; + TRIANGLE_AABB_MIN.z = (floor(TRIANGLE_MIN.z < FfxFloat32(0.0) ? TRIANGLE_MIN.z - FfxFloat32(1.0) : TRIANGLE_MIN.z)) - TRIANGLE_OFFSET; + + TRIANGLE_AABB_MAX.x = (floor(TRIANGLE_MAX.x < FfxFloat32(0.0) ? TRIANGLE_MAX.x - FfxFloat32(1.0) : TRIANGLE_MAX.x)) + (FfxFloat32(1.0) + TRIANGLE_OFFSET); + TRIANGLE_AABB_MAX.y = (floor(TRIANGLE_MAX.y < FfxFloat32(0.0) ? TRIANGLE_MAX.y - FfxFloat32(1.0) : TRIANGLE_MAX.y)) + (FfxFloat32(1.0) + TRIANGLE_OFFSET); + TRIANGLE_AABB_MAX.z = (floor(TRIANGLE_MAX.z < FfxFloat32(0.0) ? TRIANGLE_MAX.z - FfxFloat32(1.0) : TRIANGLE_MAX.z)) + (FfxFloat32(1.0) + TRIANGLE_OFFSET); + + TRIANGLE_AABB_MIN = max(TRIANGLE_AABB_MIN, FfxFloat32x3(stamp_min)); + TRIANGLE_AABB_MAX = min(TRIANGLE_AABB_MAX, FfxFloat32x3(stamp_max)); + + if (all(FFX_EQUAL(TRIANGLE_AABB_MIN, TRIANGLE_AABB_MAX))) continue; + + FfxFloat32x3 a = TRIANGLE_VERTEX_0; + FfxFloat32x3 b = TRIANGLE_VERTEX_1; + FfxFloat32x3 c = TRIANGLE_VERTEX_2; + FfxFloat32x3 ba = TRIANGLE_VERTEX_1 - TRIANGLE_VERTEX_0; + FfxFloat32x3 ac = TRIANGLE_VERTEX_0 - TRIANGLE_VERTEX_2; + FfxFloat32x3 cb = TRIANGLE_VERTEX_2 - TRIANGLE_VERTEX_1; + FfxFloat32x3 nor = cross(ba, ac); + FfxFloat32x3 cross_ba_nor = cross(ba, nor); + FfxFloat32x3 cross_cb_nor = cross(cb, nor); + FfxFloat32x3 cross_ac_nor = cross(ac, nor); + FfxFloat32 dot2_ba = dot2(ba); + FfxFloat32 dot2_cb = dot2(cb); + FfxFloat32 dot2_ac = dot2(ac); + FfxFloat32 dot2_nor = dot2(nor); + +#define FFX_BRIXELIZER_TRIANGLE_VOXELIZER_THIN_LAYER + +#define FFX_BRIXELIZER_TRIANGLE_VOXELIZER_BODY \ + { \ + FfxFloat32x3 p = VOXEL + FFX_BROADCAST_FLOAT32X3(FfxFloat32(0.5)); \ + FfxFloat32 dist = CalculateDistanceToTriangleSquared(ba, p - a, c - b, p - b, ac, p - c, nor, cross_ba_nor, cross_cb_nor, cross_ac_nor, dot2_ba, dot2_cb, dot2_ac, dot2_nor) * \ + FfxFloat32(0.25) * FfxFloat32(0.25); \ + clamped_dist = FfxFloat32(1.0) * clamp(dist, FfxFloat32(0.0), FfxFloat32(1.0)); \ + BrickInterlockedMin32(brick_id, FfxInt32x3(VOXEL), clamped_dist); \ + } + + // for FFX_BRIXELIZER_TRIANGLE_VOXELIZER_THIN_LAYER: + // Basically a simple 2D loop over 2D AABB of a triangle selected by VX_CRD_2 and VX_CRD_0 + // Then 1D loop for the depth layer of that triangle for VX_CRD_1 + // Sensitive to the selection of the major axis + // else: + // Iterates 3D AABB of a triangle + + // Macros allow to change the major plane easily + // For thin layer there's a major plane for the outer 2D iteration and then the one axis left for 1D iteration + #if !defined(VX_CRD_0) + # define VX_CRD_0 x + #endif // !defined(VX_CRD_0) + + #if !defined(VX_CRD_1) + # define VX_CRD_1 y + #endif // !defined(VX_CRD_1) + + #if !defined(VX_CRD_2) + # define VX_CRD_2 z + #endif // !defined(VX_CRD_2) + + { // Everything is in grid space + + // 3 2d edge normals with offsets for edge functions for 3 projections xy, yz, xz + brixelizerreal3 de_xy; + brixelizerreal3x2 ne_xy; + brixelizerreal3 de_xz; + brixelizerreal3x2 ne_xz; + brixelizerreal3 de_yz; + brixelizerreal3x2 ne_yz; + + brixelizerreal3 gn; // triangle plane normal + + // Need to offset the edge functions by the grid alignment + FfxBrixelizerGet2DEdges( // + /* out */ de_xy, // + /* out */ ne_xy, // + /* out */ de_xz, // + /* out */ ne_xz, // + /* out */ de_yz, // + /* out */ ne_yz, // + /* out */ gn, // + brixelizerreal3(TRIANGLE_VERTEX_0), // + brixelizerreal3(TRIANGLE_VERTEX_1), // + brixelizerreal3(TRIANGLE_VERTEX_2), // + TRIANGLE_OFFSET, // + false + ); + + brixelizerreal3 VOXEL; + + // Some duplication but with the other ordering, only one is used though + brixelizerreal3 de_yx = de_xy; + brixelizerreal3x2 ne_yx = ne_xy; + brixelizerreal3 de_zx = de_xz; + brixelizerreal3x2 ne_zx = ne_xz; + brixelizerreal3 de_zy = de_yz; + brixelizerreal3x2 ne_zy = ne_yz; + + #define _CONCAT(a, b) a##b + #define CONCAT(a, b) _CONCAT(a, b) + #define VX_CRD_02 CONCAT(VX_CRD_0, VX_CRD_2) + #define VX_CRD_01 CONCAT(VX_CRD_0, VX_CRD_1) + #define VX_CRD_12 CONCAT(VX_CRD_1, VX_CRD_2) + #define VX_DE_01 CONCAT(de_, VX_CRD_01) + #define VX_DE_02 CONCAT(de_, VX_CRD_02) + #define VX_DE_12 CONCAT(de_, VX_CRD_12) + #define VX_NE_02 CONCAT(ne_, VX_CRD_02) + #define VX_NE_01 CONCAT(ne_, VX_CRD_01) + #define VX_NE_12 CONCAT(ne_, VX_CRD_12) + + // Just one row of the voxelizer along the 1st + #if defined(FFX_BRIXELIZER_TRIANGLE_VOXELIZER_ONE_ROW) + + // gn = normalize(cross(e2, e0)); + if (gn.VX_CRD_1 < brixelizerreal(0.0)) { + gn = -gn; // make normal point in +z direction + } + brixelizerreal ny_inv = brixelizerreal(brixelizerreal(1.0) / max(gn.VX_CRD_1, brixelizerreal(1.0e-4))); + brixelizerreal d_tri = -dot(gn, brixelizerreal3(TRIANGLE_VERTEX_0)); + // 2 plane equation offsets with grid alignment + brixelizerreal d_tri_proj_min = -FfxBrixelizerOffsetByMax(d_tri, gn.VX_CRD_01, TRIANGLE_OFFSET) * ny_inv; + brixelizerreal d_tri_proj_max = -FfxBrixelizerOffsetByMin(d_tri, gn.VX_CRD_01, TRIANGLE_OFFSET) * ny_inv; + + VOXEL.VX_CRD_2 = TRIANGLE_AABB_MIN.VX_CRD_2; + { + VOXEL.VX_CRD_0 = TRIANGLE_AABB_MIN.VX_CRD_0; + { + if (FfxBrixelizerEvalEdge(VOXEL.VX_CRD_02, VX_DE_02, VX_NE_02)) // 2D triangle test + { + // Now figure out the 3rd coordinate range [min, max] + // By doing range analysis on the evaluation of the plane equation on the 4 corners of the row + brixelizerreal y00 = -((VOXEL.VX_CRD_0 + brixelizerreal(0.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(0.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal y01 = -((VOXEL.VX_CRD_0 + brixelizerreal(0.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(1.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal y10 = -((VOXEL.VX_CRD_0 + brixelizerreal(1.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(0.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal y11 = -((VOXEL.VX_CRD_0 + brixelizerreal(1.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(1.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal min_y = floor(min(y00, min(y01, min(y10, y11))) - d_tri * ny_inv); + min_y = max(TRIANGLE_AABB_MIN.VX_CRD_1, min_y); + brixelizerreal max_y = floor(max(y00, max(y01, max(y10, y11))) - d_tri * ny_inv) + brixelizerreal(1.0); + max_y = min(TRIANGLE_AABB_MAX.VX_CRD_1, max_y); + + // brixelizerreal min_y = floor(min(y00, min(y01, min(y10, y11 + d_tri_proj_min))) + d_tri_proj_min); + // min_y = max(TRIANGLE_AABB_MIN.VX_CRD_1, min_y); + // brixelizerreal max_y = floor(max(y00, max(y01, max(y10, y11))) + d_tri_proj_max) + brixelizerreal(1.0); + // max_y = min(TRIANGLE_AABB_MAX.VX_CRD_1, max_y); + + for (VOXEL.VX_CRD_1 = min_y; VOXEL.VX_CRD_1 < max_y; VOXEL.VX_CRD_1 += brixelizerreal(1.0)) { + // for (VOXEL.VX_CRD_1 = TRIANGLE_AABB_MIN.VX_CRD_1; VOXEL.VX_CRD_1 < TRIANGLE_AABB_MAX.VX_CRD_1; VOXEL.VX_CRD_1 += brixelizerreal(1.0)) { + // if (FfxBrixelizerEvalEdge(VOXEL.VX_CRD_01, VX_DE_01, VX_NE_01) && // the rest of the 2D triangle tests + // FfxBrixelizerEvalEdge(VOXEL.VX_CRD_12, VX_DE_12, VX_NE_12)) // + { FFX_BRIXELIZER_TRIANGLE_VOXELIZER_BODY; } + } + } + } + } + + // Outer loop iterates on the 2d bounding box + #elif defined(FFX_BRIXELIZER_TRIANGLE_VOXELIZER_THIN_LAYER) + // gn = normalize(cross(e2, e0)); + if (gn.VX_CRD_1 < brixelizerreal(0.0)) { + gn = -gn; // make normal point in +z direction + } + brixelizerreal ny_inv = brixelizerreal(brixelizerreal(1.0) / max(gn.VX_CRD_1, brixelizerreal(1.0e-4))); + brixelizerreal d_tri = -dot(gn, brixelizerreal3(TRIANGLE_VERTEX_0)); + brixelizerreal d_tri_proj_min = -FfxBrixelizerOffsetByMax(d_tri, gn.VX_CRD_01, TRIANGLE_OFFSET) * ny_inv; + brixelizerreal d_tri_proj_max = -FfxBrixelizerOffsetByMin(d_tri, gn.VX_CRD_01, TRIANGLE_OFFSET) * ny_inv; + // For thin layer we iterate N^2 and project a point on two planes to find the lower/upper bound for the 3rd inner loop + for (VOXEL.VX_CRD_2 = TRIANGLE_AABB_MIN.VX_CRD_2; VOXEL.VX_CRD_2 < TRIANGLE_AABB_MAX.VX_CRD_2; VOXEL.VX_CRD_2 += brixelizerreal(1.0)) { + for (VOXEL.VX_CRD_0 = TRIANGLE_AABB_MIN.VX_CRD_0; VOXEL.VX_CRD_0 < TRIANGLE_AABB_MAX.VX_CRD_0; VOXEL.VX_CRD_0 += brixelizerreal(1.0)) { + if (FfxBrixelizerEvalEdge(VOXEL.VX_CRD_02, VX_DE_02, VX_NE_02)) // 2D triangle test + { + // Now figure out the 3rd coordinate range [min, max] + // By doing range analysis on the evaluation of 4 corners of the grid + brixelizerreal y00 = -((VOXEL.VX_CRD_0 + brixelizerreal(0.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(0.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal y01 = -((VOXEL.VX_CRD_0 + brixelizerreal(0.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(1.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal y10 = -((VOXEL.VX_CRD_0 + brixelizerreal(1.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(0.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal y11 = -((VOXEL.VX_CRD_0 + brixelizerreal(1.0)) * gn.VX_CRD_0 + (VOXEL.VX_CRD_2 + brixelizerreal(1.0)) * gn.VX_CRD_2) * ny_inv; + brixelizerreal min_y = floor(min(y00 + d_tri_proj_min, min(y01 + d_tri_proj_min, min(y10 + d_tri_proj_min, y11 + d_tri_proj_min)))); + min_y = max(TRIANGLE_AABB_MIN.VX_CRD_1, min_y); + brixelizerreal max_y = floor(max(y00 + d_tri_proj_max, max(y01 + d_tri_proj_max, max(y10 + d_tri_proj_max, y11 + d_tri_proj_max)))) + brixelizerreal(1.0); + max_y = min(TRIANGLE_AABB_MAX.VX_CRD_1, max_y); + + for (VOXEL.VX_CRD_1 = min_y; VOXEL.VX_CRD_1 < max_y; VOXEL.VX_CRD_1 += brixelizerreal(1.0)) { + if (FfxBrixelizerEvalEdge(VOXEL.VX_CRD_01, VX_DE_01, VX_NE_01) && // the rest of the 2D triangle tests + FfxBrixelizerEvalEdge(VOXEL.VX_CRD_12, VX_DE_12, VX_NE_12)) // + { + FFX_BRIXELIZER_TRIANGLE_VOXELIZER_BODY; + } + } + } + } + } + #else // !FFX_BRIXELIZER_TRIANGLE_VOXELIZER_THIN_LAYER + // For thick layer we iterate N^3 + for (VOXEL.VX_CRD_2 = TRIANGLE_AABB_MIN.VX_CRD_2; VOXEL.VX_CRD_2 < TRIANGLE_AABB_MAX.VX_CRD_2; VOXEL.VX_CRD_2 += brixelizerreal(1.0)) { + for (VOXEL.VX_CRD_0 = TRIANGLE_AABB_MIN.VX_CRD_0; VOXEL.VX_CRD_0 < TRIANGLE_AABB_MAX.VX_CRD_0; VOXEL.VX_CRD_0 += brixelizerreal(1.0)) { + if (FfxBrixelizerEvalEdge(VOXEL.VX_CRD_02, VX_DE_02, VX_NE_02)) // + { + for (VOXEL.VX_CRD_1 = TRIANGLE_AABB_MIN.VX_CRD_1; VOXEL.VX_CRD_1 < TRIANGLE_AABB_MAX.VX_CRD_1; VOXEL.VX_CRD_1 += brixelizerreal(1.0)) { + if (FfxBrixelizerEvalEdge(VOXEL.VX_CRD_01, VX_DE_01, VX_NE_01) && // + FfxBrixelizerEvalEdge(VOXEL.VX_CRD_12, VX_DE_12, VX_NE_12)) // + { + FFX_BRIXELIZER_TRIANGLE_VOXELIZER_BODY; + } + } + } + } + } + #endif + } + +#undef FFX_BRIXELIZER_TRIANGLE_VOXELIZER_BODY + +#undef FFX_BRIXELIZER_TRIANGLE_VOXELIZER_THIN_LAYER + } + } +} + +FFX_GROUPSHARED FfxUInt32x3 lds_aabb_tree_min; +FFX_GROUPSHARED FfxUInt32x3 lds_aabb_tree_max; +// Build AABB tree for 64^3 for 4^3 stamp +void FfxBrixelizerBuildTreeAABB(FfxUInt32x3 gid, FfxUInt32x3 group_id) +{ + FfxUInt32 layer_idx = GetBuildInfoTreeIteration(); + + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X3(0)))) { + lds_aabb_tree_min = FFX_BROADCAST_UINT32X3(FfxUInt32(-1)); + lds_aabb_tree_max = FFX_BROADCAST_UINT32X3(FfxUInt32(0)); + } + + FFX_GROUP_MEMORY_BARRIER; + + if (layer_idx == FfxUInt32(0)) { // bottom level 16^16^16 of 4^4^4 + FfxUInt32x3 child_coord = gid.xyz; + FfxUInt32x3 node_offset = group_id.xyz * FfxUInt32(4); + FfxUInt32x3 voxel_coord = node_offset + child_coord; + FfxUInt32 brick_id = LoadCascadeBrickMap(FfxBrixelizerFlattenPOT(WrapCoords(voxel_coord), FFX_BRIXELIZER_CASCADE_DEGREE)); + FfxBoolean full_or_unitialized = brick_id != FFX_BRIXELIZER_INVALID_ID; // It's a valid brick or an uninitialized one + if (full_or_unitialized) { + FfxUInt32 brick_aabb_pack = 0x3FE00; + if (brick_id != FFX_BRIXELIZER_UNINITIALIZED_ID) { + brick_aabb_pack = LoadBricksAABB(FfxBrixelizerBrickGetIndex(brick_id)); + } + FfxUInt32x3 brick_aabb_umin = FfxBrixelizerUnflattenPOT(brick_aabb_pack & ((FfxUInt32(1) << FfxUInt32(9)) - FfxUInt32(1)), FfxUInt32(3)); + FfxUInt32x3 brick_aabb_umax = FfxBrixelizerUnflattenPOT((brick_aabb_pack >> FfxUInt32(9)) & ((FfxUInt32(1) << FfxUInt32(9)) - FfxUInt32(1)), FfxUInt32(3)); + FFX_ATOMIC_MIN(lds_aabb_tree_min.x, child_coord.x * FfxUInt32(8) + brick_aabb_umin.x); + FFX_ATOMIC_MIN(lds_aabb_tree_min.y, child_coord.y * FfxUInt32(8) + brick_aabb_umin.y); + FFX_ATOMIC_MIN(lds_aabb_tree_min.z, child_coord.z * FfxUInt32(8) + brick_aabb_umin.z); + FFX_ATOMIC_MAX(lds_aabb_tree_max.x, child_coord.x * FfxUInt32(8) + brick_aabb_umax.x); + FFX_ATOMIC_MAX(lds_aabb_tree_max.y, child_coord.y * FfxUInt32(8) + brick_aabb_umax.y); + FFX_ATOMIC_MAX(lds_aabb_tree_max.z, child_coord.z * FfxUInt32(8) + brick_aabb_umax.z); + } + FFX_GROUP_MEMORY_BARRIER; + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X3(0)))) { + FfxUInt32 flat_stamp_idx = FfxBrixelizerFlattenPOT(group_id.xyz, FfxUInt32(4)); + FfxUInt32 min_pack = FfxBrixelizerFlattenPOT(lds_aabb_tree_min.xyz & FfxUInt32(0x1f), FfxUInt32(5)); + FfxUInt32 max_pack = FfxBrixelizerFlattenPOT(lds_aabb_tree_max.xyz & FfxUInt32(0x1f), FfxUInt32(5)); + StoreCascadeAABBTreeUInt(flat_stamp_idx, min_pack | (max_pack << FfxUInt32(16))); + } + } else if (layer_idx == FfxUInt32(1)) { // mid level 4^4^4 of 4^4^4 + FfxUInt32x3 child_coord = gid.xyz * FfxUInt32(4) + group_id.xyz * FfxUInt32(16); + FfxUInt32 child_idx = FfxBrixelizerFlattenPOT(child_coord / FfxUInt32(4), FfxUInt32(4)); + FfxUInt32 bottom_aabb_node = LoadCascadeAABBTreeUInt(child_idx); + FfxUInt32x3 aabb_min = FfxBrixelizerUnflattenPOT(bottom_aabb_node & FfxUInt32(0x7fff), FfxUInt32(5)); + FfxUInt32x3 aabb_max = FfxBrixelizerUnflattenPOT((bottom_aabb_node >> FfxUInt32(16)) & FfxUInt32(0x7fff), FfxUInt32(5)); + if (bottom_aabb_node != FFX_BRIXELIZER_INVALID_BOTTOM_AABB_NODE) { + FFX_ATOMIC_MIN(lds_aabb_tree_min.x, child_coord.x * FfxUInt32(8) + aabb_min.x); + FFX_ATOMIC_MIN(lds_aabb_tree_min.y, child_coord.y * FfxUInt32(8) + aabb_min.y); + FFX_ATOMIC_MIN(lds_aabb_tree_min.z, child_coord.z * FfxUInt32(8) + aabb_min.z); + FFX_ATOMIC_MAX(lds_aabb_tree_max.x, child_coord.x * FfxUInt32(8) + aabb_max.x); + FFX_ATOMIC_MAX(lds_aabb_tree_max.y, child_coord.y * FfxUInt32(8) + aabb_max.y); + FFX_ATOMIC_MAX(lds_aabb_tree_max.z, child_coord.z * FfxUInt32(8) + aabb_max.z); + } + FFX_GROUP_MEMORY_BARRIER; + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X3(0)))) { + if (lds_aabb_tree_min.x == FfxUInt32(-1)) { // TODO(Dihara): Check this!!!!! + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + 6 * FfxBrixelizerFlattenPOT(group_id, 2) + 0, FfxFloat32x3(0.0, 0.0, 0.0)); + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + 6 * FfxBrixelizerFlattenPOT(group_id, 2) + 3, FfxFloat32x3(0.0, 0.0, 0.0)); + } else { + FfxFloat32x3 world_aabb_min = FfxFloat32x3(lds_aabb_tree_min.xyz) * GetCascadeInfoVoxelSize() / FfxFloat32(8.0) + GetCascadeInfoGridMin(); + FfxFloat32x3 world_aabb_max = FfxFloat32x3(lds_aabb_tree_max.xyz + FFX_BROADCAST_UINT32X3(1)) * GetCascadeInfoVoxelSize() / FfxFloat32(8.0) + GetCascadeInfoGridMin(); + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + 3 * (2 * FfxBrixelizerFlattenPOT(group_id, 2) + FfxUInt32(0)), FfxFloat32x3(world_aabb_min)); + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + 3 * (2 * FfxBrixelizerFlattenPOT(group_id, 2) + FfxUInt32(1)), FfxFloat32x3(world_aabb_max)); + } + } + } else if (layer_idx == FfxUInt32(2)) { // toP level 4^4^4 + FfxUInt32x3 child_coord = gid.xyz; + FfxUInt32 child_idx = FfxBrixelizerFlattenPOT(child_coord, FfxUInt32(2)); + FfxFloat32x3 stamp_aabb_min = LoadCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + (FfxUInt32(2) * child_idx + FfxUInt32(0)) * 3); + FfxFloat32x3 stamp_aabb_max = LoadCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + (FfxUInt32(2) * child_idx + FfxUInt32(1)) * 3); + FfxUInt32x3 voxel_aabb_min = FfxUInt32x3(max(FFX_BROADCAST_FLOAT32X3(0.0), stamp_aabb_min - GetCascadeInfoGridMin()) / (GetCascadeInfoVoxelSize() / FfxFloat32(8.0))); + FfxUInt32x3 voxel_aabb_max = FfxUInt32x3(max(FFX_BROADCAST_FLOAT32X3(0.0), stamp_aabb_max - GetCascadeInfoGridMin()) / (GetCascadeInfoVoxelSize() / FfxFloat32(8.0))); + if (ffxAsUInt32(stamp_aabb_min.x) != ffxAsUInt32(stamp_aabb_max.x)) { + FFX_ATOMIC_MIN(lds_aabb_tree_min.x, voxel_aabb_min.x); + FFX_ATOMIC_MIN(lds_aabb_tree_min.y, voxel_aabb_min.y); + FFX_ATOMIC_MIN(lds_aabb_tree_min.z, voxel_aabb_min.z); + FFX_ATOMIC_MAX(lds_aabb_tree_max.x, voxel_aabb_max.x); + FFX_ATOMIC_MAX(lds_aabb_tree_max.y, voxel_aabb_max.y); + FFX_ATOMIC_MAX(lds_aabb_tree_max.z, voxel_aabb_max.z); + } + FFX_GROUP_MEMORY_BARRIER; + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X3(0)))) { + if (lds_aabb_tree_min.x == FfxUInt32(-1)) { // TODO(Dihara): Check this!!!!! + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + FfxUInt32(4 * 4 * 4) * 6 + 0, FfxFloat32x3(0.0, 0.0, 0.0)); + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + FfxUInt32(4 * 4 * 4) * 6 + 3, FfxFloat32x3(0.0, 0.0, 0.0)); + } else { + FfxFloat32x3 world_aabb_min = FfxFloat32x3(lds_aabb_tree_min.xyz) * GetCascadeInfoVoxelSize() / FfxFloat32(8.0) + GetCascadeInfoGridMin(); + FfxFloat32x3 world_aabb_max = FfxFloat32x3(lds_aabb_tree_max.xyz) * GetCascadeInfoVoxelSize() / FfxFloat32(8.0) + GetCascadeInfoGridMin(); + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + 3 * FfxUInt32(2 * 4 * 4 * 4 + 0), world_aabb_min); + StoreCascadeAABBTreeFloat3(FfxUInt32(16 * 16 * 16) + 3 * FfxUInt32(2 * 4 * 4 * 4 + 1), world_aabb_max); + } + } + } +} + +void FfxBrixelizerClearBrickStorage(FfxUInt32 gtid, FfxUInt32 group_id) +{ + FfxUInt32 brick_offset = group_id >> FfxUInt32(3); + FfxUInt32 stamp_id = group_id & FfxUInt32(7); + FfxUInt32 brick_id = LoadScratchBricksClearList(brick_offset); + FfxUInt32 brick_dim = FfxUInt32(8); + FfxUInt32x3 local_coord = FfxBrixelizerUnflattenPOT(gtid, FfxUInt32(2)) + FfxBrixelizerUnflattenPOT(stamp_id, FfxUInt32(1)) * FfxUInt32(4); + + ClearBrixelData32(brick_id, FfxInt32x3(local_coord)); +} + +FFX_GROUPSHARED FfxUInt32x3 lds_brick_aabb_min; +FFX_GROUPSHARED FfxUInt32x3 lds_brick_aabb_max; +void FfxBrixelizerCompressBrick(FfxUInt32 gtid, FfxUInt32 brick_map_offset) +{ + FfxUInt32 brick_id = LoadScratchBricksCompressionList(brick_map_offset); + FfxUInt32 voxel_id = FfxBrixelizerLoadBrickVoxelID(brick_id); + FfxUInt32 voxel_idx = FfxBrixelizerVoxelGetIndex(voxel_id); + FfxUInt32 cascade_id = FfxBrixelizerGetVoxelCascade(voxel_id); + + if (gtid == 0) { + lds_brick_aabb_max = FFX_BROADCAST_UINT32X3(0); + lds_brick_aabb_min = FFX_BROADCAST_UINT32X3(0xffffffffu); + } + FfxUInt32x3 local_coord = FfxBrixelizerUnflattenPOT(gtid, FfxUInt32(3)); + FfxFloat32 val = LoadBrixelData32(brick_id, FfxInt32x3(local_coord)); + + FFX_GROUP_MEMORY_BARRIER; + if (val < FfxFloat32(1.0 / 8.0)) { + FFX_ATOMIC_MAX(lds_brick_aabb_max.x, local_coord.x); + FFX_ATOMIC_MAX(lds_brick_aabb_max.y, local_coord.y); + FFX_ATOMIC_MAX(lds_brick_aabb_max.z, local_coord.z); + FFX_ATOMIC_MIN(lds_brick_aabb_min.x, local_coord.x); + FFX_ATOMIC_MIN(lds_brick_aabb_min.y, local_coord.y); + FFX_ATOMIC_MIN(lds_brick_aabb_min.z, local_coord.z); + } + FFX_GROUP_MEMORY_BARRIER; + if (gtid == FfxUInt32(0)) { + if (lds_brick_aabb_min.x == FfxUInt32(0xffffffff)) { // free brick + FfxBrixelizerMarkBrickFree(brick_id); + StoreCascadeBrickMap(WrapFlatCoords(voxel_idx), FFX_BRIXELIZER_INVALID_ID); + } else { + FfxUInt32 pack0 = FfxBrixelizerFlattenPOT(min(FFX_BROADCAST_UINT32X3(7), lds_brick_aabb_min), FfxUInt32(3)); + FfxUInt32 pack1 = FfxBrixelizerFlattenPOT(min(FFX_BROADCAST_UINT32X3(7), lds_brick_aabb_max), FfxUInt32(3)); + StoreBricksAABB(FfxBrixelizerBrickGetIndex(brick_id), pack0 | (pack1 << FfxUInt32(9))); + } + } + + if (lds_brick_aabb_min.x != 0xffffffffu) { + if (abs(val) > FfxFloat32(0.9999)) return; + val = (FfxBrixelizerGetSign(val) * sqrt(abs(val)) * FfxFloat32(4.0)) / FfxFloat32(8 - 1); + ffxassert(val >= -FfxFloat32(1.0) && val <= FfxFloat32(1.0)); + StoreSDFAtlas(FfxBrixelizerGetSDFAtlasOffset(brick_id) + local_coord, clamp(val, FfxFloat32(0.0), FfxFloat32(1.0))); + } +} + +#endif // ifndef FFX_BRIXELIZER_CASCADE_OPS_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_common.h new file mode 100644 index 00000000..1be68537 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_common.h @@ -0,0 +1,103 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_COMMON_H +#define FFX_BRIXELIZER_COMMON_H + +#include "../ffx_core.h" +#include "ffx_brixelizer_host_gpu_shared.h" + +#define ffxassert(x) + +FfxBoolean FfxBrixelizerIsValidID(FfxUInt32 id) +{ + return (id & FFX_BRIXELIZER_INVALID_ID) != FFX_BRIXELIZER_INVALID_ID; +} + +FfxBoolean FfxBrixelizerIntersectAABB(FfxFloat32x3 ray_origin, FfxFloat32x3 ray_invdir, FfxFloat32x3 box_min, FfxFloat32x3 box_max, FFX_PARAMETER_OUT FfxFloat32 hit_min, FFX_PARAMETER_OUT FfxFloat32 hit_max) +{ + FfxFloat32x3 tbot = ray_invdir * (box_min - ray_origin); + FfxFloat32x3 ttop = ray_invdir * (box_max - ray_origin); + FfxFloat32x3 tmin = min(ttop, tbot); + FfxFloat32x3 tmax = max(ttop, tbot); + FfxFloat32x2 t = max(tmin.xx, tmin.yz); + FfxFloat32 t0 = max(t.x, t.y); + t = min(tmax.xx, tmax.yz); + FfxFloat32 t1 = min(t.x, t.y); + hit_min = max(t0, FfxFloat32(0.0)); + hit_max = max(t1, FfxFloat32(0.0)); + return hit_max > hit_min; +} + +FfxUInt32 FfxBrixelizerFlattenPOT(FfxUInt32x3 voxel_coord, FfxUInt32 degree) +{ + return voxel_coord.x | (voxel_coord.y << degree) | (voxel_coord.z << (2 * degree)); +} + +FfxUInt32x3 FfxBrixelizerUnflattenPOT(FfxUInt32 flat_bx_coord, FfxUInt32 degree) +{ + return FfxUInt32x3(flat_bx_coord & ((FfxUInt32(1) << degree) - 1), (flat_bx_coord >> degree) & ((FfxUInt32(1) << degree) - 1), flat_bx_coord >> (2 * degree)); +} + +FfxUInt32 FfxBrixelizerPackUnsigned8Bits(FfxFloat32 a) +{ + return FfxUInt32(ffxSaturate(a) * FfxFloat32(255.0)) & 0xffu; +} + +FfxFloat32 FfxBrixelizerUnpackUnsigned8Bits(FfxUInt32 uval) +{ + return FfxFloat32(uval & 0xff) / FfxFloat32(255.0); +} + +FfxUInt32 PackUVWC(FfxFloat32x4 uvwc) +{ + FfxUInt32 pack = // + (FfxBrixelizerPackUnsigned8Bits(uvwc.x) << 0) // + | (FfxBrixelizerPackUnsigned8Bits(uvwc.y) << 8) // + | (FfxBrixelizerPackUnsigned8Bits(uvwc.z) << 16) // + | (FfxBrixelizerPackUnsigned8Bits(uvwc.w) << 24); // + return pack; +} + +FfxFloat32x2 FfxBrixelizerOctahedronToUV(FfxFloat32x3 N) +{ + N.xy = FfxFloat32x2(N.xy) / dot(FFX_BROADCAST_FLOAT32X3(1.0), abs(N)); + FfxFloat32x2 k; + k.x = N.x >= float(0.0) ? float(1.0) : -float(1.0); + k.y = N.y >= float(0.0) ? float(1.0) : -float(1.0); + if (N.z <= float(0.0)) N.xy = (float(1.0) - abs(FfxFloat32x2(N.yx))) * k; + return N.xy * float(0.5) + float(0.5); +} + +FfxFloat32x3 FfxBrixelizerUVToOctahedron(FfxFloat32x2 UV) +{ + UV = float(2.0) * (UV - float(0.5)); + FfxFloat32x3 N = FfxFloat32x3(UV, float(1.0) - abs(UV.x) - abs(UV.y)); + float t = max(-N.z, float(0.0)); + FfxFloat32x2 k; + k.x = N.x >= float(0.0) ? -t : t; + k.y = N.y >= float(0.0) ? -t : t; + N.xy += k; + return normalize(N); +} + +#endif // FFX_BRIXELIZER_COMMON_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_common_private.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_common_private.h new file mode 100644 index 00000000..22fc4156 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_common_private.h @@ -0,0 +1,243 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_COMMON_PRIVATE_H +#define FFX_BRIXELIZER_COMMON_PRIVATE_H + +#include "ffx_brixelizer_common.h" +#include "ffx_brixelizer_host_gpu_shared_private.h" + +FfxInt32x3 to_int3(FfxUInt32x3 a) { return FfxInt32x3(FfxInt32(a.x), FfxInt32(a.y), FfxInt32(a.z)); } +FfxFloat32x3 to_float3(FfxUInt32x3 a) { return FfxFloat32x3(FfxFloat32(a.x), FfxFloat32(a.y), FfxFloat32(a.z)); } +FfxFloat32x3 to_float3(FfxInt32x3 a) { return FfxFloat32x3(FfxFloat32(a.x), FfxFloat32(a.y), FfxFloat32(a.z)); } + +FfxUInt32 FfxBrixelizerPackDistance(FfxFloat32 distance) +{ + FfxUInt32 uval = ffxAsUInt32(distance); + FfxUInt32 sign_bit = uval >> FfxUInt32(31); + return (uval << 1) | sign_bit; +} + +FfxFloat32 FfxBrixelizerUnpackDistance(FfxUInt32 uval) +{ + FfxUInt32 sign_bit = (uval & 1); + return ffxAsFloat((uval >> FfxUInt32(1)) | (sign_bit << FfxUInt32(31))); +} + +// Returns the minimal absolute value with its sign unchanged +FfxFloat32 FfxBrixelizerUnsignedMin(FfxFloat32 a, FfxFloat32 b) { return abs(a) < abs(b) ? a : b; } +// sign without zero +FfxFloat32 FfxBrixelizerGetSign(FfxFloat32 v) { return v < FfxFloat32(0.0) ? -FfxFloat32(1.0) : FfxFloat32(1.0); } + +FfxFloat32 dot2(FfxFloat32x3 v) { return dot(v, v); } +FfxFloat32 dot2(FfxFloat32x2 v) { return dot(v, v); } + +// https://www.shadertoy.com/view/4sXXRN +// The MIT License +// Copyright © 2014 Inigo Quilez +// 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. +// +// It computes the distance to a triangle. +// +// See here: http://iquilezles.org/www/articles/triangledistance/triangledistance.htm +// +// In case a mesh was rendered, only one square root would be needed for the +// whole mesh. In this example the triangle is given a thckness of 0.01 units +// for display purposes. Like the square root, this thickness should be added +// only once for the whole mesh too. +FfxFloat32 CalculateDistanceToTriangle(FfxFloat32x3 p, FfxFloat32x3 a, FfxFloat32x3 b, FfxFloat32x3 c) { + FfxFloat32x3 ba = b - a; + FfxFloat32x3 pa = p - a; + FfxFloat32x3 cb = c - b; + FfxFloat32x3 pb = p - b; + FfxFloat32x3 ac = a - c; + FfxFloat32x3 pc = p - c; + FfxFloat32x3 nor = cross(ba, ac); + + return sqrt( // + (sign(dot(cross(ba, nor), pa)) + // + sign(dot(cross(cb, nor), pb)) + // + sign(dot(cross(ac, nor), pc)) < // + FfxFloat32(2.0)) // + ? // + min(min( // + dot2(ba * ffxSaturate(dot(ba, pa) / dot2(ba)) - pa), // + dot2(cb * ffxSaturate(dot(cb, pb) / dot2(cb)) - pb)), // + dot2(ac * ffxSaturate(dot(ac, pc) / dot2(ac)) - pc)) // + : // + dot(nor, pa) * dot(nor, pa) / dot2(nor) // + ); // +} + +FfxFloat32 CalculateDistanceToTriangleSquared(FfxFloat32x3 ba, // + FfxFloat32x3 pa, // + FfxFloat32x3 cb, // + FfxFloat32x3 pb, // + FfxFloat32x3 ac, // + FfxFloat32x3 pc, // + FfxFloat32x3 nor, // + FfxFloat32x3 cross_ba_nor, // + FfxFloat32x3 cross_cb_nor, // + FfxFloat32x3 cross_ac_nor, // + FfxFloat32 dot2_ba, // + FfxFloat32 dot2_cb, // + FfxFloat32 dot2_ac, // + FfxFloat32 dot2_nor // +) { + return // + ( // + (sign(dot(cross_ba_nor, pa)) + // + sign(dot(cross_cb_nor, pb)) + // + sign(dot(cross_ac_nor, pc)) < // + FfxFloat32(2.0)) // + ? // + min(min( // + dot2(ba * ffxSaturate(dot(ba, pa) / dot2_ba) - pa), // + dot2(cb * ffxSaturate(dot(cb, pb) / dot2_cb) - pb)), // + dot2(ac * ffxSaturate(dot(ac, pc) / dot2_ac) - pc)) // + : // + dot(nor, pa) * dot(nor, pa) / dot2_nor // + ); // +} + +#define brixelizerreal FfxFloat32 +#define brixelizerreal2 FfxFloat32x2 +#define brixelizerreal3 FfxFloat32x3 +#define brixelizerreal4 FfxFloat32x4 + +#ifdef FFX_HLSL +# define brixelizerreal3x2 float3x2 +#else +# define brixelizerreal3x2 mat3x2 +#endif + +brixelizerreal3 to_brixelizerreal3(FfxUInt32x3 a) { return brixelizerreal3(brixelizerreal(a.x), brixelizerreal(a.y), brixelizerreal(a.z)); } + +// Offsets the plane equation for the nearest grid point +brixelizerreal FfxBrixelizerOffsetByMax(brixelizerreal de, brixelizerreal2 ne, brixelizerreal offset) +{ + de += max(FfxFloat32(0.0), ne.x) + abs(ne.x * offset); + de += max(FfxFloat32(0.0), ne.y) + abs(ne.y * offset); + return de; +} + +// Offsets the plane equation for the next grid point +brixelizerreal FfxBrixelizerOffsetByMin(brixelizerreal de, brixelizerreal2 ne, brixelizerreal offset) +{ + de += min(FfxFloat32(0.0), ne.x) - abs(ne.x * offset); + de += min(FfxFloat32(0.0), ne.y) - abs(ne.x * offset); + return de; +} + +void FfxBrixelizerGet2DEdge(FFX_PARAMETER_OUT brixelizerreal2 ne, + FFX_PARAMETER_OUT brixelizerreal de, + brixelizerreal orientation, + brixelizerreal edge_x, + brixelizerreal edge_y, + brixelizerreal vertex_x, + brixelizerreal vertex_y, + brixelizerreal offset) +{ + ne = brixelizerreal2(-orientation * edge_y, orientation * edge_x); + de = -(ne.x * vertex_x + ne.y * vertex_y); + de = FfxBrixelizerOffsetByMax(de, ne, offset); +} + +void FfxBrixelizerGet2DEdges( + FFX_PARAMETER_OUT brixelizerreal3 de_xy, + FFX_PARAMETER_OUT brixelizerreal3x2 ne_xy, + FFX_PARAMETER_OUT brixelizerreal3 de_xz, + FFX_PARAMETER_OUT brixelizerreal3x2 ne_xz, + FFX_PARAMETER_OUT brixelizerreal3 de_yz, + FFX_PARAMETER_OUT brixelizerreal3x2 ne_yz, + FFX_PARAMETER_OUT brixelizerreal3 gn, + brixelizerreal3 TRIANGLE_VERTEX_0, + brixelizerreal3 TRIANGLE_VERTEX_1, + brixelizerreal3 TRIANGLE_VERTEX_2, + brixelizerreal offset, + bool invert) +{ + brixelizerreal3 e0 = TRIANGLE_VERTEX_1.xyz - TRIANGLE_VERTEX_0.xyz; + brixelizerreal3 e1 = TRIANGLE_VERTEX_2.xyz - TRIANGLE_VERTEX_1.xyz; + brixelizerreal3 e2 = TRIANGLE_VERTEX_0.xyz - TRIANGLE_VERTEX_2.xyz; + if (invert) { + e0 = -e0; + e1 = -e1; + e2 = -e2; + } + + gn = normalize(cross(e2, e0)); + + brixelizerreal orientation_xy = brixelizerreal(gn.z < FfxFloat32(0.0) ? -FfxFloat32(1.0) : FfxFloat32(1.0)); + FfxBrixelizerGet2DEdge(/* out */ ne_xy[0], /* out */ de_xy[0], orientation_xy, e0.x, e0.y, TRIANGLE_VERTEX_0.x, TRIANGLE_VERTEX_0.y, offset); + FfxBrixelizerGet2DEdge(/* out */ ne_xy[1], /* out */ de_xy[1], orientation_xy, e1.x, e1.y, TRIANGLE_VERTEX_1.x, TRIANGLE_VERTEX_1.y, offset); + FfxBrixelizerGet2DEdge(/* out */ ne_xy[2], /* out */ de_xy[2], orientation_xy, e2.x, e2.y, TRIANGLE_VERTEX_2.x, TRIANGLE_VERTEX_2.y, offset); + brixelizerreal orientation_xz = brixelizerreal(gn.y > FfxFloat32(0.0) ? -FfxFloat32(1.0) : FfxFloat32(1.0)); + FfxBrixelizerGet2DEdge(/* out */ ne_xz[0], /* out */ de_xz[0], orientation_xz, e0.x, e0.z, TRIANGLE_VERTEX_0.x, TRIANGLE_VERTEX_0.z, offset); + FfxBrixelizerGet2DEdge(/* out */ ne_xz[1], /* out */ de_xz[1], orientation_xz, e1.x, e1.z, TRIANGLE_VERTEX_1.x, TRIANGLE_VERTEX_1.z, offset); + FfxBrixelizerGet2DEdge(/* out */ ne_xz[2], /* out */ de_xz[2], orientation_xz, e2.x, e2.z, TRIANGLE_VERTEX_2.x, TRIANGLE_VERTEX_2.z, offset); + brixelizerreal orientation_yz = brixelizerreal(gn.x < FfxFloat32(0.0) ? -FfxFloat32(1.0) : FfxFloat32(1.0)); + FfxBrixelizerGet2DEdge(/* out */ ne_yz[0], /* out */ de_yz[0], orientation_yz, e0.y, e0.z, TRIANGLE_VERTEX_0.y, TRIANGLE_VERTEX_0.z, offset); + FfxBrixelizerGet2DEdge(/* out */ ne_yz[1], /* out */ de_yz[1], orientation_yz, e1.y, e1.z, TRIANGLE_VERTEX_1.y, TRIANGLE_VERTEX_1.z, offset); + FfxBrixelizerGet2DEdge(/* out */ ne_yz[2], /* out */ de_yz[2], orientation_yz, e2.y, e2.z, TRIANGLE_VERTEX_2.y, TRIANGLE_VERTEX_2.z, offset); +} + +bool FfxBrixelizerEvalEdge(brixelizerreal2 vertex, brixelizerreal3 de, brixelizerreal3x2 ne) +{ + return (ne[0].x * vertex.x + ne[0].y * vertex.y + de[0] >= brixelizerreal(FfxFloat32(0.0))) && + (ne[1].x * vertex.x + ne[1].y * vertex.y + de[1] >= brixelizerreal(FfxFloat32(0.0))) && + (ne[2].x * vertex.x + ne[2].y * vertex.y + de[2] >= brixelizerreal(FfxFloat32(0.0))); +} + +// We need those non-POT versions around for culling +FfxUInt32x3 FfxBrixelizerUnflatten(FfxUInt32 flat_bx_coord, FfxUInt32x3 dim) +{ + return FfxUInt32x3(flat_bx_coord % dim.x, (flat_bx_coord / dim.x) % dim.y, flat_bx_coord / (dim.x * dim.y)); +} + +FfxUInt32x2 FfxBrixelizerUnflatten(FfxUInt32 flat_bx_coord, FfxUInt32x2 dim) +{ + return FfxUInt32x2(flat_bx_coord % dim.x, (flat_bx_coord / dim.x) % dim.y); +} + +FfxUInt32 FfxBrixelizerFlatten(FfxUInt32x3 voxel_coord, FfxUInt32x3 dim) +{ + return voxel_coord.x + voxel_coord.y * dim.x + voxel_coord.z * dim.x * dim.y; +} + +#endif // FFX_BRIXELIZER_COMMON_PRIVATE_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_context_ops.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_context_ops.h new file mode 100644 index 00000000..9298d451 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_context_ops.h @@ -0,0 +1,306 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_CONTEXT_OPS_H +#define FFX_BRIXELIZER_CONTEXT_OPS_H + +#include "ffx_brixelizer_host_gpu_shared_private.h" +#include "ffx_brixelizer_brick_common_private.h" +#include "ffx_brixelizer_build_common.h" +#include "ffx_brixelizer_common_private.h" + +void FfxBrixelizerAppendClearBrick(FfxUInt32 brick_id) +{ + FfxUInt32 offset; + IncrementContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_CLEAR_BRICKS, FfxUInt32(1), offset); + StoreBricksClearList(offset, brick_id); +} + +void FfxBrixelizerAppendDirtyBrick(FfxUInt32 brick_id) +{ + FfxUInt32 offset; + IncrementContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_DIRTY_BRICKS, FfxUInt32(1), offset); + StoreBricksDirtyList(offset, brick_id); +} + +void FfxBrixelizerClearCounters() +{ + for (FfxUInt32 i = 0; i < FFX_BRIXELIZER_NUM_CONTEXT_COUNTERS; i++) { + StoreContextCounter(i, FfxUInt32(0)); + } +} + +void FfxBrixelizerAddBrickToFreeList(FfxUInt32 brick_id) +{ + FfxUInt32 offset; + IncrementContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_FREE_BRICKS, FfxUInt32(1), offset); + StoreBricksFreeList(offset, brick_id); +} + +FfxFloat32 FfxBrixelizerLoadBrixelDist(FfxUInt32 brick_id, FfxInt32x3 coord) +{ + if (any(FFX_GREATER_THAN(coord, FFX_BROADCAST_INT32X3(7))) || any(FFX_LESS_THAN(coord, FFX_BROADCAST_INT32X3(0)))) return FfxFloat32(1.0); + return LoadSDFAtlas(FfxBrixelizerGetSDFAtlasOffset(brick_id) + coord); +} + +void FfxBrixelizerStoreBrixelDist(FfxUInt32 brick_id, FfxUInt32x3 coord, FfxFloat32 dist) +{ + StoreSDFAtlas(FfxBrixelizerGetSDFAtlasOffset(brick_id) + coord, clamp(dist, FfxFloat32(0.0), FfxFloat32(1.0))); +} + +void FfxBrixelizerClearBrick(FfxUInt32 brick_id, FfxUInt32x3 voxel_coord) +{ + FfxBrixelizerStoreBrixelDist(brick_id, voxel_coord, FfxFloat32(1.0)); +} + +FfxFloat32 FfxBrixelizerEikonalMin(FfxFloat32 a, FfxFloat32 b) +{ + return FfxBrixelizerUnsignedMin(a, b); +} + +// Eikonal solver, enforce |gradient|==d +// Generic form for n dimensions: +// U = 1/n * (sum(U_i) + sqrt(sum(U_i) * sum(U_i) - n * (sum(U_i * U_i) - D))) +// when sqrt is non real then fall back to min of lower dimensions +FfxFloat32 FfxBrixelizerEikonal1D(FfxFloat32 x, FfxFloat32 y, FfxFloat32 z, FfxFloat32 d) +{ + FfxFloat32 xyz = FfxBrixelizerEikonalMin(x, FfxBrixelizerEikonalMin(y, z)); + return (xyz + d * FfxBrixelizerGetSign(xyz)); +} + +FfxFloat32 FfxBrixelizerEikonal2D(FfxFloat32 x, FfxFloat32 y, FfxFloat32 d) +{ + const FfxFloat32 k = FfxFloat32(1.0) / FfxFloat32(2.0); + FfxFloat32 xy = x + y; + FfxFloat32 v = xy * xy - FfxFloat32(2.0) * (x * x + y * y - d * d); + if (v < FfxFloat32(0.0)) return FfxFloat32(1.0); + return k * (xy + sqrt(v) * FfxBrixelizerGetSign(xy)); +} + +FfxFloat32 FfxBrixelizerEikonal3D(FfxFloat32 x, FfxFloat32 y, FfxFloat32 z, FfxFloat32 d) +{ + const FfxFloat32 k = FfxFloat32(1.0) / FfxFloat32(3.0); + FfxFloat32 xyz = x + y + z; + FfxFloat32 v = xyz * xyz - FfxFloat32(3.0) * (x * x + y * y + z * z - d * d); + if (v < FfxFloat32(0.0)) return FfxFloat32(1.0); + return k * (xyz + sqrt(v) * FfxBrixelizerGetSign(xyz)); +} + +FFX_GROUPSHARED FfxFloat32 lds_eikonal_sdf_cache[512]; +FfxFloat32 FfxBrixelizerLDSLoadSDF(FfxInt32x3 coord) +{ + if (any(FFX_LESS_THAN(coord, FFX_BROADCAST_INT32X3(0))) || any(FFX_GREATER_THAN(coord, FFX_BROADCAST_INT32X3(7)))) return FfxFloat32(1.0); + return lds_eikonal_sdf_cache[FfxUInt32(coord.x) + FfxUInt32(coord.y) * FfxUInt32(8) + FfxUInt32(coord.z) * FfxUInt32(8 * 8)]; +} + +void FfxBrixelizerLDSStoreSDF(FfxInt32x3 coord, FfxFloat32 sdf) +{ + lds_eikonal_sdf_cache[FfxUInt32(coord.x) + FfxUInt32(coord.y) * FfxUInt32(8) + FfxUInt32(coord.z) * FfxUInt32(8 * 8)] = sdf; +} + +// Collects a list of bricks to clear for indirect args +// those don't have a brick_id->voxel_id mapping are considered free +// those that got eikonal counter are considered dirty as they had something baked in them +// DEFINE_ENTRY(64, 1, 1, CollectClearBricks) +void FfxBrixelizerCollectClearBricks(FfxUInt32 brick_offset) +{ + if (brick_offset >= GetContextInfoNumBricks()) return; + + FfxUInt32 brick_id = FfxBrixelizerMakeBrickID(brick_offset); + FfxUInt32 dim = 8; + FfxUInt32 voxel_id = FfxBrixelizerLoadBrickVoxelID(brick_id); + FfxUInt32 voxel_idx = FfxBrixelizerVoxelGetIndex(voxel_id); + FfxUInt32 cascade_id = FfxBrixelizerGetVoxelCascade(voxel_id); + FfxUInt32 eikonal_counter = LoadBricksEikonalCounters(brick_id); + + // @TODO cleanup this mess + if (GetBuildInfoDoInitialization() > 0) { + StoreBricksEikonalCounters(brick_id, 0); + FfxBrixelizerMarkBrickFree(brick_id); + FfxBrixelizerAddBrickToFreeList(brick_id); + FfxBrixelizerAppendClearBrick(brick_id); + } else { +#ifdef FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + StoreBricksEikonalCounters(brick_id, 0); + FfxBrixelizerMarkBrickFree(brick_id); + FfxBrixelizerAddBrickToFreeList(brick_id); + FfxBrixelizerAppendClearBrick(brick_id); + +#else // !FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + + if (FfxBrixelizerIsInvalidID(voxel_id)) { + FfxBrixelizerAddBrickToFreeList(brick_id); + if (eikonal_counter > 0) { // Means there's been some baking using this brick so need to clear + FfxBrixelizerAppendClearBrick(brick_id); + StoreBricksEikonalCounters(brick_id, 0); + } + } + +#endif // !FFX_BRIXELIZER_DEBUG_FORCE_REBUILD + } +} + +void FfxBrixelizerPrepareClearBricks() +{ + FfxUInt32 tier_cnt = LoadContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_CLEAR_BRICKS); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_CLEAR_BRICKS_32 + FfxUInt32(0), tier_cnt * FfxUInt32(1 << (3))); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_CLEAR_BRICKS_32 + FfxUInt32(1), FfxUInt32(1)); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_CLEAR_BRICKS_32 + FfxUInt32(2), FfxUInt32(1)); +} + +void FfxBrixelizerClearBrickEntry(FfxUInt32 gtid, FfxUInt32 group_id) +{ + FfxUInt32 brick_offset = group_id.x >> (3); + FfxUInt32 stamp_id = group_id.x & ((1 << (3)) - 1); + FfxUInt32 brick_id = LoadBricksClearList(brick_offset); + FfxUInt32 brick_dim = 8; + FfxUInt32x3 local_coord = FfxBrixelizerUnflattenPOT(gtid, 2) + FfxBrixelizerUnflattenPOT(stamp_id, 1) * FfxUInt32(4); + + FfxBrixelizerClearBrick(brick_id, local_coord); +} + +void FfxBrixelizerCollectDirtyBricks(FfxUInt32 brick_offset) +{ + FfxUInt32 brick_id = FfxBrixelizerMakeBrickID(brick_offset); + FfxUInt32 eikonal_counter = LoadBricksEikonalCounters(brick_id); + FfxUInt32 dim = 8; + FfxUInt32 voxel_id = FfxBrixelizerLoadBrickVoxelID(brick_id); + + if (FfxBrixelizerIsValidID(voxel_id)) { + FfxUInt32 voxel_idx = FfxBrixelizerVoxelGetIndex(voxel_id); + FfxUInt32 cascade_idx = FfxBrixelizerGetVoxelCascade(voxel_id); + FfxUInt32x3 clipmap_offset = GetContextInfoCascadeClipmapOffset(cascade_idx); + FfxUInt32x3 voxel_offset = FfxBrixelizerUnflattenPOT(voxel_idx, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 wrapped_voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, voxel_offset), FFX_BRIXELIZER_CASCADE_DEGREE); + if (eikonal_counter < 16) { + FfxBrixelizerAppendDirtyBrick(brick_id); + StoreBricksEikonalCounters(brick_id, eikonal_counter + 16); + } + } +} + +// DEFINE_ENTRY(512, 1, 1, Eikonal) +void FfxBrixelizerEikonal(FfxUInt32 local_coord_packed, FfxUInt32 brick_offset) +{ + FfxUInt32 brick_id = LoadBricksDirtyList(brick_offset); + FfxUInt32 voxel_id = FfxBrixelizerLoadBrickVoxelID(brick_id); + FfxUInt32x3 local_coord = FfxBrixelizerUnflattenPOT(local_coord_packed, 3); + if (FfxBrixelizerIsValidID(voxel_id)) { + FfxFloat32 cell_distance = FfxFloat32(1.0) / (FfxFloat32(8)); + FfxFloat32 e = FfxBrixelizerLoadBrixelDist(brick_id, FfxInt32x3(local_coord)); + + FfxBrixelizerLDSStoreSDF(FfxInt32x3(local_coord), e); + FFX_GROUP_MEMORY_BARRIER; + for (FfxUInt32 j = FfxUInt32(0); j < FfxUInt32(3); j++) { + for (FfxUInt32 i = FfxUInt32(0); i < FfxUInt32(4); i++) { + FfxUInt32 d = FfxUInt32(1) << (FfxUInt32(3) - i); + FfxFloat32x3 min_dists = FFX_BROADCAST_FLOAT32X3(FfxFloat32(1.0)); + min_dists.x = FfxBrixelizerEikonalMin(FfxBrixelizerLDSLoadSDF(FfxInt32x3(local_coord) + FfxInt32x3(d, 0, 0)), FfxBrixelizerLDSLoadSDF(FfxInt32x3(local_coord) + FfxInt32x3(-d, 0, 0))); + min_dists.y = FfxBrixelizerEikonalMin(FfxBrixelizerLDSLoadSDF(FfxInt32x3(local_coord) + FfxInt32x3(0, d, 0)), FfxBrixelizerLDSLoadSDF(FfxInt32x3(local_coord) + FfxInt32x3(0, -d, 0))); + min_dists.z = FfxBrixelizerEikonalMin(FfxBrixelizerLDSLoadSDF(FfxInt32x3(local_coord) + FfxInt32x3(0, 0, d)), FfxBrixelizerLDSLoadSDF(FfxInt32x3(local_coord) + FfxInt32x3(0, 0, -d))); + min_dists = abs(min_dists); + FfxFloat32 e10 = FfxBrixelizerEikonal1D(min_dists.x, min_dists.y, min_dists.z, d * cell_distance); + FfxFloat32 e20 = FfxBrixelizerEikonal2D(min_dists.x, min_dists.y, d * cell_distance); + FfxFloat32 e21 = FfxBrixelizerEikonal2D(min_dists.x, min_dists.z, d * cell_distance); + FfxFloat32 e22 = FfxBrixelizerEikonal2D(min_dists.z, min_dists.y, d * cell_distance); + FfxFloat32 e30 = FfxBrixelizerEikonal3D(min_dists.x, min_dists.y, min_dists.z, d * cell_distance); + e = FfxBrixelizerEikonalMin(e, FfxBrixelizerEikonalMin(e10, FfxBrixelizerEikonalMin(e20, FfxBrixelizerEikonalMin(e21, FfxBrixelizerEikonalMin(e22, e30))))); + e = FfxBrixelizerEikonalMin(e, e10); + FfxBrixelizerLDSStoreSDF(FfxInt32x3(local_coord), e); + } + } + + FfxBrixelizerStoreBrixelDist(brick_id, local_coord, e); + } +} + +void FfxBrixelizerMergeBricks(FfxUInt32 gtid, FfxUInt32 group_id) +{ + FfxUInt32 cnt = LoadContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_MERGE_BRICKS); + FfxUInt32 merge_idx = group_id / FfxUInt32(8); + FfxUInt32 stamp_idx = group_id % FfxUInt32(8); + FfxUInt32 voxel_idx = gtid + stamp_idx * FfxUInt32(64); + FfxUInt32x3 voxel_offset = FfxBrixelizerUnflattenPOT(voxel_idx, FfxUInt32(3)); + if (merge_idx >= cnt) return; + FfxUInt32 brick_A = LoadBricksMergeList(merge_idx * FfxUInt32(2) + FfxUInt32(0)); + FfxUInt32 brick_B = LoadBricksMergeList(merge_idx * FfxUInt32(2) + FfxUInt32(1)); + FfxUInt32x3 atlas_offset_A = FfxBrixelizerGetSDFAtlasOffset(brick_A); + FfxUInt32x3 atlas_offset_B = FfxBrixelizerGetSDFAtlasOffset(brick_B); + { + FfxFloat32 sdf_val_A = LoadSDFAtlas(atlas_offset_A + voxel_offset); + FfxFloat32 sdf_val_B = LoadSDFAtlas(atlas_offset_B + voxel_offset); + StoreSDFAtlas(atlas_offset_B + voxel_offset, min(sdf_val_A, sdf_val_B)); + } +} + +void FfxBrixelizerMergeCascades(FfxUInt32 voxel_idx) +{ + // Assume the same clipmap state so no need to wrap the coords + FfxUInt32 brick_A = LoadCascadeBrickMapArrayUniform(GetBuildInfo().src_cascade_A, voxel_idx); + FfxUInt32 brick_B = LoadCascadeBrickMapArrayUniform(GetBuildInfo().src_cascade_B, voxel_idx); + if (FfxBrixelizerIsValidID(brick_A) && FfxBrixelizerIsValidID(brick_B)) { + FfxUInt32 offset; + IncrementContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_MERGE_BRICKS, FfxUInt32(1), /* out */ offset); + StoreBricksMergeList(offset * FfxUInt32(2) + FfxUInt32(0), brick_A); + StoreBricksMergeList(offset * FfxUInt32(2) + FfxUInt32(1), brick_B); + StoreCascadeBrickMapArrayUniform(GetBuildInfo().dst_cascade, voxel_idx, brick_B); // we store the 2nd brick and merge into it + + FfxUInt32 brick_A_aabb_pack = LoadBricksAABB(FfxBrixelizerBrickGetIndex(brick_A)); + FfxUInt32x3 brick_A_aabb_umin = FfxBrixelizerUnflattenPOT(brick_A_aabb_pack & ((FfxUInt32(1) << FfxUInt32(9)) - FfxUInt32(1)), FfxUInt32(3)); + FfxUInt32x3 brick_A_aabb_umax = FfxBrixelizerUnflattenPOT((brick_A_aabb_pack >> FfxUInt32(9)) & ((FfxUInt32(1) << FfxUInt32(9)) - FfxUInt32(1)), FfxUInt32(3)); + + FfxUInt32 brick_B_aabb_pack = LoadBricksAABB(FfxBrixelizerBrickGetIndex(brick_B)); + FfxUInt32x3 brick_B_aabb_umin = FfxBrixelizerUnflattenPOT(brick_B_aabb_pack & ((FfxUInt32(1) << FfxUInt32(9)) - FfxUInt32(1)), FfxUInt32(3)); + FfxUInt32x3 brick_B_aabb_umax = FfxBrixelizerUnflattenPOT((brick_B_aabb_pack >> FfxUInt32(9)) & ((FfxUInt32(1) << FfxUInt32(9)) - FfxUInt32(1)), FfxUInt32(3)); + + brick_B_aabb_umin = min(brick_A_aabb_umin, brick_B_aabb_umin); + brick_B_aabb_umax = max(brick_A_aabb_umax, brick_B_aabb_umax); + brick_B_aabb_pack = FfxBrixelizerFlattenPOT(brick_B_aabb_umin, 3) | (FfxBrixelizerFlattenPOT(brick_B_aabb_umax, 3) << 9); + + StoreBricksAABB(FfxBrixelizerBrickGetIndex(brick_B), brick_B_aabb_pack); + } else if (brick_B == FFX_BRIXELIZER_UNINITIALIZED_ID || brick_A == FFX_BRIXELIZER_UNINITIALIZED_ID) { + StoreCascadeBrickMapArrayUniform(GetBuildInfo().dst_cascade, voxel_idx, FFX_BRIXELIZER_UNINITIALIZED_ID); + } else if (FfxBrixelizerIsValidID(brick_B)) { + StoreCascadeBrickMapArrayUniform(GetBuildInfo().dst_cascade, voxel_idx, brick_B); + } else { + StoreCascadeBrickMapArrayUniform(GetBuildInfo().dst_cascade, voxel_idx, brick_A); + } +} + +void FfxBrixelizerPrepareEikonalArgs() +{ + FfxUInt32 tier_cnt = LoadContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_DIRTY_BRICKS); + StoreContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_DIRTY_BRICKS, 0); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_EIKONAL_32 + 0, tier_cnt); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_EIKONAL_32 + FfxUInt32(1), 1); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_EIKONAL_32 + 2, 1); +} + +void FfxBrixelizerPrepareMergeBricksArgs() +{ + FfxUInt32 cnt = LoadContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_MERGE_BRICKS); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_MERGE_BRICKS_32 + FfxUInt32(0), cnt * FfxUInt32(8)); // 2^3 of 4^3 lanes + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_MERGE_BRICKS_32 + FfxUInt32(1), FfxUInt32(1)); + StoreIndirectArgs(FFX_BRIXELIZER_INDIRECT_OFFSETS_MERGE_BRICKS_32 + FfxUInt32(2), FfxUInt32(1)); +} + +#endif // ifndef FFX_BRIXELIZER_CONTEXT_OPS_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_debug_aabbs.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_debug_aabbs.h new file mode 100644 index 00000000..60939416 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_debug_aabbs.h @@ -0,0 +1,105 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_brixelizer_common.h" +#include "ffx_brixelizer_host_gpu_shared.h" + +void PushAABB(FfxBrixelizerDebugAABB aabb) +{ + FfxUInt32 offset; + IncrementContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_NUM_DEBUG_AABBS, 1, offset); + if (offset < GetDebugInfoMaxAABBs()) { + StoreDebugAABB(offset, aabb); + } +} + +void FfxBrixelizerDrawAABBTreeAABB(FfxUInt32 aabb_index) +{ + // if g_debug_info.debug_state is set to 1 we only want to draw the cascade bounding box + if (GetDebugInfoDebugState() == 1 && aabb_index > 0) { + return; + } + if (aabb_index == 0) { + FfxBrixelizerCascadeInfo cascade_info = GetCascadeInfo(); + FfxBrixelizerDebugAABB debug_aabb; + debug_aabb.color = FfxFloat32x3(1.0f, 0.0f, 0.0f); + debug_aabb.aabbMin = cascade_info.grid_min; + debug_aabb.aabbMax = cascade_info.grid_max; + PushAABB(debug_aabb); + } else if (aabb_index == 1) { + // root aabb + FfxUInt32 index = 16*16*16 + 4*4*4*6; + FfxBrixelizerDebugAABB debug_aabb; + debug_aabb.color = FfxFloat32x3(0.0f, 1.0f, 1.0f); + debug_aabb.aabbMin = LoadCascadeAABBTreeFloat3(index); + debug_aabb.aabbMax = LoadCascadeAABBTreeFloat3(index + 3); + PushAABB(debug_aabb); + } else if (aabb_index <= 1 + 4*4*4) { + // second level aabb + FfxUInt32 index = 16*16*16 + (aabb_index - 2)*6; + FfxBrixelizerDebugAABB debug_aabb; + debug_aabb.color = FfxFloat32x3(1.0f, 1.0f, 0.0f); + debug_aabb.aabbMin = LoadCascadeAABBTreeFloat3(index); + debug_aabb.aabbMax = LoadCascadeAABBTreeFloat3(index + 3); + + if (ffxAsUInt32(debug_aabb.aabbMin.x) == ffxAsUInt32(debug_aabb.aabbMax.x)) { + return; + } + + PushAABB(debug_aabb); + + } else if (aabb_index <= 1 + 4*4*4 + 16*16*16) { + // leaf aabb + FfxBrixelizerCascadeInfo cascade_info = GetCascadeInfo(); + FfxUInt32 index = aabb_index - (4*4*4 + 1 + 1); + FfxUInt32 packedAABB = LoadCascadeAABBTreeUInt(index); + if (packedAABB == FFX_BRIXELIZER_INVALID_BOTTOM_AABB_NODE) { + return; + } + + FfxUInt32x3 leaf_offset = FfxBrixelizerUnflattenPOT(index, 4) * 32; + FfxUInt32x3 aabbMin = leaf_offset + FfxBrixelizerUnflattenPOT(packedAABB & ((1 << 15) - 1), 5); + FfxUInt32x3 aabbMax = leaf_offset + FfxBrixelizerUnflattenPOT((packedAABB >> 16) & ((1 << 15) - 1), 5) + 1; + + FfxBrixelizerDebugAABB debug_aabb; + debug_aabb.color = FfxFloat32x3(0.0f, 1.0f, 0.0f); + debug_aabb.aabbMin = cascade_info.grid_min + FfxFloat32x3(aabbMin) * cascade_info.voxel_size / 8.0f; + debug_aabb.aabbMax = cascade_info.grid_min + FfxFloat32x3(aabbMax) * cascade_info.voxel_size / 8.0f; + PushAABB(debug_aabb); + } +} + +void FfxBrixelizerDrawInstanceAABB(FfxUInt32 index) +{ + // XXX -- use debug_state to pass in number of instance IDs + if (index >= GetDebugInfoDebugState()) { + return; + } + + FfxUInt32 instance_id = GetDebugInstanceID(index); + FfxBrixelizerInstanceInfo instance_info = LoadInstanceInfo(instance_id); + FfxBrixelizerDebugAABB debug_aabb; + debug_aabb.color = FfxFloat32x3(0.0f, 0.0f, 1.0f); + debug_aabb.aabbMin = instance_info.aabbMin; + debug_aabb.aabbMax = instance_info.aabbMax; + PushAABB(debug_aabb); +} \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_debug_visualization.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_debug_visualization.h new file mode 100644 index 00000000..c8e15647 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_debug_visualization.h @@ -0,0 +1,199 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_DEBUG_VISUALIZATION_H +#define FFX_BRIXELIZER_DEBUG_VISUALIZATION_H + +#include "ffx_brixelizer_host_gpu_shared.h" + +#define FFX_BRIXELIZER_TRAVERSAL_EPS (GetDebugInfoPreviewSDFSolveEpsilon() / FfxFloat32(8.0)) + +#include "ffx_brixelizer_trace_ops.h" + +// XXX -- tmp +FfxUInt32 FfxBrixelizerGetVoxelCascade(FfxUInt32 voxel_id) +{ + return voxel_id >> FFX_BRIXELIZER_CASCADE_ID_SHIFT; +} + +#define FLT_INF 1e30f + +// By Morgan McGuire @morgan3d, http://graphicscodex.com +// Reuse permitted under the BSD license. +// https://www.shadertoy.com/view/4dsSzr +FfxFloat32x3 FFX_HeatmapGradient(FfxFloat32 t) +{ + return clamp((pow(t, 1.5) * 0.8 + 0.2) * FfxFloat32x3(smoothstep(0.0, 0.35, t) + t * 0.5, smoothstep(0.5, 1.0, t), max(1.0 - t * 1.7, t * 7.0 - 6.0)), 0.0, 1.0); +} + +// License? +FfxFloat32x3 FFX_RandomColor(FfxFloat32x2 uv) { + uv = ffxFract(uv * FfxFloat32(15.718281828459045)); + FfxFloat32x3 seeds = FfxFloat32x3(FfxFloat32(0.123), FfxFloat32(0.456), FfxFloat32(0.789)); + seeds = ffxFract((uv.x + FfxFloat32(0.5718281828459045) + seeds) * ((seeds + FFX_MODULO(uv.x, FfxFloat32(0.141592653589793))) * FfxFloat32(27.61803398875) + FfxFloat32(4.718281828459045))); + seeds = ffxFract((uv.y + FfxFloat32(0.5718281828459045) + seeds) * ((seeds + FFX_MODULO(uv.y, FfxFloat32(0.141592653589793))) * FfxFloat32(27.61803398875) + FfxFloat32(4.718281828459045))); + seeds = ffxFract((FfxFloat32(0.5718281828459045) + seeds) * ((seeds + FFX_MODULO(uv.x, FfxFloat32(0.141592653589793))) * FfxFloat32(27.61803398875) + FfxFloat32(4.718281828459045))); + return seeds; +} + +FfxFloat32x3 FFX_ViewSpaceToWorldSpace(FfxFloat32x4 view_space_coord) +{ + return FFX_TRANSFORM_VECTOR(GetDebugInfoInvView(), view_space_coord).xyz; +} + +FfxFloat32x3 FFX_InvProjectPosition(FfxFloat32x3 coord, FfxFloat32x4x4 mat) +{ + coord.y = (FfxFloat32(1.0) - coord.y); + coord.xy = FfxFloat32(2.0) * coord.xy - 1; + FfxFloat32x4 projected = FFX_TRANSFORM_VECTOR(mat, FfxFloat32x4(coord, 1)); + projected.xyz /= projected.w; + return projected.xyz; +} + +FfxFloat32x3 FFX_ScreenSpaceToViewSpace(FfxFloat32x3 screen_uv_coord) +{ + return FFX_InvProjectPosition(screen_uv_coord, GetDebugInfoInvProj()); +} + +FfxFloat32 FFX_HitEdgeDist(FfxFloat32x3 hit, FfxFloat32x3 boxMin, FfxFloat32x3 boxMax) +{ + FfxFloat32x3 a = min(abs(hit - boxMin), abs(hit - boxMax)); + return min(min(a.x + a.y, a.x + a.z), a.y + a.z); +} + +// modified from inigo quilez +FfxFloat32 FFX_BoxHitDist(FfxUInt32x2 tid, FfxFloat32x3 ro, FfxFloat32x3 rd, FfxFloat32x3 boxMin, FfxFloat32x3 boxMax) +{ + FfxFloat32x3 halfSize = (boxMax - boxMin) / 2.0f; + FfxFloat32x3 center = boxMin + halfSize; + FfxFloat32x3 rop = ro - center; + FfxFloat32x3 ird = 1.0f / rd; + FfxFloat32x3 n = rop * ird; + FfxFloat32x3 k = abs(ird) * halfSize; + FfxFloat32x3 t1 = -n - k; + FfxFloat32x3 t2 = -n + k; + + FfxFloat32 tNear = max(max(t1.x, t1.y), t1.z); + FfxFloat32 tFar = min(min(t2.x, t2.y), t2.z); + + if (tNear > tFar || tFar < 0.0f) return FLT_INF; + + FfxFloat32 nearEdgeDist = FFX_HitEdgeDist(ro + tNear * rd, boxMin, boxMax); + FfxFloat32 farEdgeDist = FFX_HitEdgeDist(ro + tFar * rd, boxMin, boxMax); + + const FfxFloat32 nearClip = 0.1f; + if (tNear > nearClip && nearEdgeDist / tNear < 0.001f) { + return tNear; + } else if (tFar > nearClip && farEdgeDist / tFar < 0.001f) { + return tFar; + } + return FLT_INF; +} + +void FfxBrixelizerDebugVisualization(FfxUInt32x2 tid) +{ + FfxUInt32 width, height; + GetDebugOutputDimensions(width, height); + FfxFloat32x2 uv = (FfxFloat32x2(tid.xy) + FfxFloat32(0.5).xx) / FfxFloat32x2(width, height); + + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, FfxFloat32(0.5)); + FfxFloat32x3 view_space_ray = FFX_ScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 view_space_ray_direction = normalize(view_space_ray); + FfxFloat32x3 ray_direction = normalize(FFX_ViewSpaceToWorldSpace(FfxFloat32x4(view_space_ray_direction, FfxFloat32(0.0)))); + FfxFloat32x3 ray_origin = FFX_ViewSpaceToWorldSpace(FfxFloat32x4(0.0, 0.0, 0.0, 1.0)); + + FfxBrixelizerRayDesc ray_desc; + ray_desc.start_cascade_id = GetDebugInfoStartCascadeIndex(); + ray_desc.end_cascade_id = GetDebugInfoEndCascadeIndex(); + ray_desc.t_min = GetDebugInfoTMin(); + ray_desc.t_max = GetDebugInfoTMax(); + ray_desc.origin = ray_origin; + ray_desc.direction = ray_direction; + + FfxBrixelizerHitRaw hit_payload; + FfxBoolean hit = FfxBrixelizerTraverseRaw(ray_desc, hit_payload); + FfxFloat32 hit_dist = FLT_INF; + FfxFloat32x3 out_color = FfxFloat32x3(0.0f, 0.0f, 0.0f); + + if (hit) { + hit_dist = hit_payload.t; + switch (GetDebugInfoDebugState()) { + case FFX_BRIXELIZER_TRACE_DEBUG_MODE_DISTANCE: { + FfxFloat32 dist = (hit_payload.t - ray_desc.t_min) / (ray_desc.t_max - ray_desc.t_min); + out_color = FfxFloat32x3(0.0f, smoothstep(0.0f, 1.0f, dist), smoothstep(0.0f, 1.0f, 1.0f - dist)); + break; + } + case FFX_BRIXELIZER_TRACE_DEBUG_MODE_UVW: { + FfxFloat32x3 uvw = FfxFloat32x3( + FfxBrixelizerUnpackUnsigned8Bits((hit_payload.uvwc >> 0) & 0xff), + FfxBrixelizerUnpackUnsigned8Bits((hit_payload.uvwc >> 8) & 0xff), + FfxBrixelizerUnpackUnsigned8Bits((hit_payload.uvwc >> 16) & 0xff) + ); + out_color = uvw; + break; + } + case FFX_BRIXELIZER_TRACE_DEBUG_MODE_ITERATIONS: + out_color = FFX_HeatmapGradient(FfxFloat32(hit_payload.iter_count) / FfxFloat32(64)); + break; + case FFX_BRIXELIZER_TRACE_DEBUG_MODE_GRAD: { + out_color = FfxBrixelizerGetHitNormal(hit_payload) * FfxFloat32(0.5) + FfxFloat32(0.5); + break; + } + case FFX_BRIXELIZER_TRACE_DEBUG_MODE_BRICK_ID: + out_color = FFX_RandomColor(FfxFloat32x2(FfxFloat32(hit_payload.brick_id % 256) / FfxFloat32(256.0), FfxFloat32((hit_payload.brick_id / 256) % 256) / FfxFloat32(256.0))); + break; + case FFX_BRIXELIZER_TRACE_DEBUG_MODE_CASCADE_ID: { + FfxUInt32 voxel_id = LoadBricksVoxelMap(FfxBrixelizerBrickGetIndex(hit_payload.brick_id)); + FfxUInt32 cascade_id = FfxBrixelizerGetVoxelCascade(voxel_id); + out_color = FFX_RandomColor(FfxFloat32x2(FfxFloat32(cascade_id % 256) / FfxFloat32(256.0), FfxFloat32((cascade_id / 256) % 256) / FfxFloat32(256.0))); + break; + } + } + } else { + out_color = FFX_HeatmapGradient(FfxFloat32(hit_payload.iter_count) / FfxFloat32(64)); + } + + FfxFloat32 aabb_hit_dist = FLT_INF; + FfxFloat32x3 aabb_color = FfxFloat32x3(0.0f, 0.0f, 0.0f); + + FfxUInt32 num_debug_aabbs = min(GetDebugInfoMaxAABBs(), LoadContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_NUM_DEBUG_AABBS)); + + for (FfxUInt32 i = 0; i < num_debug_aabbs; ++i) { + FfxBrixelizerDebugAABB aabb = GetDebugAABB(i); + + FfxFloat32 this_hit_dist = FFX_BoxHitDist(tid, ray_desc.origin, ray_desc.direction, aabb.aabbMin, aabb.aabbMax); + if (this_hit_dist < aabb_hit_dist) { + aabb_hit_dist = this_hit_dist; + aabb_color = aabb.color; + } + } + + if (aabb_hit_dist < hit_dist) { + out_color = aabb_color; + } else if (aabb_hit_dist < FLT_INF) { + out_color = ffxLerp(out_color, aabb_color, 0.25f); + } + + StoreDebugOutput(tid, out_color); +} + +#endif // ifndef FFX_BRIXELIZER_DEBUG_VISUALIZATION_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_host_gpu_shared.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_host_gpu_shared.h new file mode 100644 index 00000000..7afa787d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_host_gpu_shared.h @@ -0,0 +1,230 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_HOST_GPU_SHARED_H +#define FFX_BRIXELIZER_HOST_GPU_SHARED_H + +#include "../ffx_core.h" + +#define FFX_BRIXELIZER_MAX_CASCADES 24 +#define FFX_BRIXELIZER_MAX_INSTANCES (FfxUInt32(1) << FfxUInt32(16)) +#define FFX_BRIXELIZER_CASCADE_RESOLUTION 64 +#define FFX_BRIXELIZER_MAX_INSTANCES (FfxUInt32(1) << FfxUInt32(16)) +#define FFX_BRIXELIZER_INVALID_ID 0x00ffffffu +#define FFX_BRIXELIZER_UNINITIALIZED_ID 0xffffffffu +#define FFX_BRIXELIZER_INVALID_BOTTOM_AABB_NODE 0x7fff +#define FFX_BRIXELIZER_MAX_BRICKS_X8 (1 << 18) +#define FFX_BRIXELIZER_MAX_BRICKS FFX_BRIXELIZER_MAX_BRICKS_X8 +#define FFX_BRIXELIZER_BRICK_AABBS_STRIDE (sizeof(FfxUInt32)) +#define FFX_BRIXELIZER_BRICK_AABBS_SIZE (FFX_BRIXELIZER_MAX_BRICKS_X8 * FFX_BRIXELIZER_BRICK_AABBS_STRIDE) +#define FFX_BRIXELIZER_CASCADE_AABB_TREE_SIZE ((16 * 16 * 16) * sizeof(FfxUInt32) + (4 * 4 * 4 + 1) * sizeof(FfxFloat32x3) * 2) +#define FFX_BRIXELIZER_CASCADE_AABB_TREE_STRIDE (sizeof(FfxUInt32)) +#define FFX_BRIXELIZER_CASCADE_BRICK_MAP_SIZE (FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * sizeof(FfxUInt32)) +#define FFX_BRIXELIZER_CASCADE_BRICK_MAP_STRIDE (sizeof(FfxUInt32)) + +#define FFX_BRIXELIZER_BRICK_ID_MASK 0xffffff + +#define FFX_BRIXELIZER_CASCADE_DEGREE FfxUInt32(6) +#define FFX_BRIXELIZER_CASCADE_WRAP_MASK FfxUInt32(63) + +#define FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE FfxUInt32(512) + +#if defined(FFX_CPU) + #define FFX_BRIXELIZER_CONST static const +#elif defined(FFX_HLSL) + #define FFX_BRIXELIZER_CONST static const +#elif defined(FFX_GLSL) + #define FFX_BRIXELIZER_CONST const +#else + FFX_STATIC_ASSERT(0) +#endif + +#ifdef FFX_CPU + #define FFX_BRIXELIZER_BEGIN_STRUCT(name) typedef struct name { + #define FFX_BRIXELIZER_END_STRUCT(name) } name; + #define FFX_BRIXELIZER_BEGIN_ENUM(name) typedef enum name { + #define FFX_BRIXELIZER_END_ENUM(name) } name; + #define FFX_BRIXELIZER_ENUM_VALUE(name, value) name = value, +#else + #define FFX_BRIXELIZER_BEGIN_STRUCT(name) struct name { + #define FFX_BRIXELIZER_END_STRUCT(name) }; + #define FFX_BRIXELIZER_BEGIN_ENUM(name) + #define FFX_BRIXELIZER_END_ENUM(name) + #define FFX_BRIXELIZER_ENUM_VALUE(name, value) FFX_BRIXELIZER_CONST FfxUInt32 name = value; +#endif + +/// An enumeration of flags which can be specified for different options when doing a cascade update. +/// +/// @ingroup Brixelizer +FFX_BRIXELIZER_BEGIN_ENUM(FfxBrixelizerCascadeUpdateFlags) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_CASCADE_UPDATE_FLAG_NONE, FfxUInt32(0)) ///< No flags. + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_CASCADE_UPDATE_FLAG_RESET, FfxUInt32(1) << FfxUInt32(0)) ///< Reset the cascade. This clears and frees all bricks currently in the cascade ready to rebuild the cascade completely. +FFX_BRIXELIZER_END_ENUM(FfxBrixelizerCascadeUpdateFlags) + +/// An enumeration of the different possible debug outputs for the Brixelizer debug visualization. +/// +/// @ingroup Brixelizer +FFX_BRIXELIZER_BEGIN_ENUM(FfxBrixelizerTraceDebugModes) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_TRACE_DEBUG_MODE_DISTANCE, 0) ///< Display a visualisation of the distance to hit, with closer hits in blue and further hits in green. + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_TRACE_DEBUG_MODE_UVW, 1) ///< Display the UVW coordinates of hits. + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_TRACE_DEBUG_MODE_ITERATIONS, 2) ///< Display a heatmap visualizing number of iterations in the scene. + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_TRACE_DEBUG_MODE_GRAD, 3) ///< Display the normals at hits. + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_TRACE_DEBUG_MODE_BRICK_ID, 4) ///< Display each brick in its own color. + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_TRACE_DEBUG_MODE_CASCADE_ID, 5) ///< Display each cascade in itw own color. +FFX_BRIXELIZER_END_ENUM(FfxBrixelizerTraceDebugModes) + +/// A structure of parameters describing a cascade. This structure is primarily for Brixelizer +/// internal use. +/// +/// @ingroup Brixelizer +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerCascadeInfo) + FfxFloat32x3 grid_min; + FfxFloat32 voxel_size; + + FfxFloat32x3 grid_max; + FfxUInt32 flags; ///< the latest build_flags; see FfxBrixelizerCascadeUpdateFlags + + FfxUInt32x3 clipmap_offset; + FfxUInt32 pad00; + + FfxInt32x3 clipmap_invalidation_offset; + FfxUInt32 pad33; + + FfxInt32x3 ioffset; + FfxUInt32 index; + + FfxFloat32x3 grid_mid; + FfxUInt32 is_enabled; + + FfxUInt32x2 rel_grid_min_fp16; + FfxUInt32x2 rel_grid_max_fp16; + + FfxUInt32 pad11; + FfxUInt32 pad22; + FfxFloat32 ivoxel_size; + FfxUInt32 is_initialized; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerCascadeInfo) + +/// A structure of parameters describing the Brixelizer context. This structure is primarily +/// for Brixelizer internal use. +/// +/// @ingroup Brixelizer +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerContextInfo) + FfxUInt32 num_bricks; + FfxUInt32 frame_index; + FfxFloat32 imesh_unit; + FfxFloat32 mesh_unit; + + FfxBrixelizerCascadeInfo cascades[FFX_BRIXELIZER_MAX_CASCADES]; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerContextInfo) + +// ============================================================================= +// Debug/context counters +// ============================================================================= +// Important to match the first a couple of counters with the FfxBrixelizerScratchCounters to share code +#define MEMBER_LIST \ + MEMBER(brickCount, BRICK_COUNT, 0) \ + MEMBER(dirtyBricks, DIRTY_BRICKS, 1) \ + MEMBER(freeBricks, FREE_BRICKS, 2) \ + MEMBER(clearBricks, CLEAR_BRICKS, 3) \ + MEMBER(mergeBricks, MERGE_BRICKS, 4) \ + MEMBER(numDebugAABBs, NUM_DEBUG_AABBS, 5) + +/// A structure containing all the counters used by the Brixelizer context. These can +/// be read back from the context after processing each update for analysis. +/// brickCount gives the total number of bricks allocated. +/// dirtyBricks gives the total number of bricks requiring an eikonal pass for completion. +/// freeBricks gives the total number of free bricks. This is the maximum number of bricks which can be allocated within a frame. +/// clearBricks gives the total number of bricks to be cleared in a frame. Bricks are cleared by having all distance values reset to 1. +/// mergeBricks gives the total number of bricks to be merged in a frame. +/// numDebugAABBs gives the total number of debug AABBs requested to be drawn in a debug visualization. +/// +/// @ingroup Brixelizer +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerDebugCounters) +#define MEMBER(camel_name, _upper_name, _index) FfxUInt32 camel_name; + MEMBER_LIST +#undef MEMBER +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerDebugCounters) + +FFX_BRIXELIZER_BEGIN_ENUM(FfxBrixelizerContextCounterIndex) +#define MEMBER(_camel_name, upper_name, index) FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_CONTEXT_COUNTER_##upper_name, index) + MEMBER_LIST +#undef MEMBER +FFX_BRIXELIZER_END_ENUM(FfxBrixelizerContextCounterIndex) + +#define MEMBER(_camel_name, _upper_name, _index) + 1 +FFX_BRIXELIZER_CONST FfxUInt32 FFX_BRIXELIZER_NUM_CONTEXT_COUNTERS = 0 MEMBER_LIST; +#undef MEMBER +#undef MEMBER_LIST + +// ============================================================================= +// Scratch counters +// ============================================================================= +#define MEMBER_LIST \ + MEMBER(triangles, TRIANGLES, 0) \ + MEMBER(maxTriangles, MAX_TRIANGLES, 1) \ + MEMBER(references, REFERENCES, 2) \ + MEMBER(maxReferences, MAX_REFERENCES, 3) \ + MEMBER(groupIndex, GROUP_INDEX, 4) \ + MEMBER(compressionBricks, COMPRESSION_BRICKS, 5) \ + MEMBER(storageOffset, STORAGE_OFFSET, 6) \ + MEMBER(storageSize, STORAGE_SIZE, 7) \ + MEMBER(numBricksAllocated, NUM_BRICKS_ALLOCATED, 8) \ + MEMBER(clearBricks, CLEAR_BRICKS, 9) + +/// A structure containing the counters used by the Brixelizer context for each cascade +/// update. This can be readback and used for analysis after each update. The following +/// members contain useful information for analysing Brixelizer resource usage. +/// +/// triangles is used to store the total amount of storage space requested within the triangle buffer during an update. This is useful for determining a sensible value of triangleSwapSize in either FfxBrixelizerRawCascadeUpdateDescription or FfxBrixelizerUpdateDescription. +/// references is used to store the total number of reference allocations requested by Brixelizer during an update. This is useful for determining a sensible value of maxReferences in either FfxBrixelizerRawCascadeUpdateDescription or FfxBrixelizerUpdateDescription. +/// numBricksAllocated is used to store the number of brick allocations requested in an update. This is useful for determining a sensible value of maxBricksPerBake in either FfxBrixelizerRawCascadeUpdateDescription or FfxBrixelizerUpdateDescription. +/// +/// The following counters are used internally by Brixelizer. +/// +/// maxTriangles is used to store the storage size of the triangle buffer. +/// maxReferences is used to store the maxmimum number of references that can be stored. +/// groupIndex is used as a global atomic for wavefront synchronisation. +/// compressionBricks the number of bricks to compress (i.e. calculate AABBs for) this udpate. +/// storageOffset the next free position in the bricks scratch buffer. +/// storageSize the size of the bricks scratch buffer. +/// clearBricks the amount of bricks in the scratch buffer to initialize. +/// +/// @ingroup Brixelizer +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerScratchCounters) +#define MEMBER(camel_name, _upper_name, _index) FfxUInt32 camel_name; + MEMBER_LIST +#undef MEMBER +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerScratchCounters) + +FFX_BRIXELIZER_BEGIN_ENUM(FfxBrixelizerScratchCounterIndex) +#define MEMBER(_camel_name, upper_name, index) FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_SCRATCH_COUNTER_##upper_name, index) + MEMBER_LIST +#undef MEMBER +FFX_BRIXELIZER_END_ENUM(FfxBrixelizerScratchCounterIndex) + +#define MEMBER(_camel_name, _upper_name, _index) + 1 +FFX_BRIXELIZER_CONST FfxUInt32 FFX_BRIXELIZER_NUM_SCRATCH_COUNTERS = 0 MEMBER_LIST; +#undef MEMBER +#undef MEMBER_LIST + +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_host_gpu_shared_private.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_host_gpu_shared_private.h new file mode 100644 index 00000000..8f8a80b2 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_host_gpu_shared_private.h @@ -0,0 +1,222 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_HOST_GPU_SHARED_PRIVATE_H +#define FFX_BRIXELIZER_HOST_GPU_SHARED_PRIVATE_H + +#include "../ffx_core.h" +#include "ffx_brixelizer_host_gpu_shared.h" + +FFX_BRIXELIZER_BEGIN_ENUM(FfxBrixelizerInstanceFlagsInternal) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INSTANCE_FLAG_USE_U16_INDEX, (FfxUInt32(1) << FfxUInt32(0))) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INSTANCE_FLAG_USE_RGBA16_VERTEX, (FfxUInt32(1) << FfxUInt32(2))) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INSTANCE_FLAG_USE_INDEXLESS_QUAD_LIST, (FfxUInt32(1) << FfxUInt32(3))) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INSTANCE_FLAG_UV_FORMAT_RG16_UNORM, (FfxUInt32(1) << FfxUInt32(4))) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INSTANCE_FLAG_UV_FORMAT_RG32_FLOAT, (FfxUInt32(1) << FfxUInt32(5))) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INSTANCE_FLAG_COLOR_FORMAT_RGBA32_FLOAT, (FfxUInt32(1) << FfxUInt32(6))) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INSTANCE_FLAG_COLOR_FORMAT_RGBA8_UNORM, (FfxUInt32(1) << FfxUInt32(7))) +FFX_BRIXELIZER_END_ENUM(FfxBrixelizerInstanceFlagsInternal) + +#define FFX_BRIXELIZER_STATIC_CONFIG_VOXELIZER_GROUP_SIZE FfxUInt32(256) +#define FFX_BRIXELIZER_STATIC_CONFIG_SCAN_REFERENCES_GROUP_SIZE FfxUInt32(256) +#define FFX_BRIXELIZER_STATIC_CONFIG_MAX_VERTEX_BUFFERS FfxUInt32(8192) +#define FFX_BRIXELIZER_STATIC_CONFIG_COMPACT_REFERENCES_GROUP_SIZE FfxUInt32(64) +#define FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_GROUP_SIZE FfxUInt32(32) +#define FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_REFS_PER_GROUP FFX_BRIXELIZER_STATIC_CONFIG_EMIT_SDF_GROUP_SIZE +#define FFX_BRIXELIZER_STATIC_CONFIG_INDIRECT_DISPATCH_STRIDE32 FfxUInt32(4) +#define FFX_BRIXELIZER_STATIC_CONFIG_INDIRECT_DISPATCH_STRIDE FfxUInt32(16) + +// index deliberately starts at 1 +#define MEMBER_LIST \ + MEMBER(CompactReferences, COMPACT_REFERENCES, 1) \ + MEMBER(EmitSDF, EMIT_SDF, 2) \ + MEMBER(Voxelize, VOXELIZE, 3) \ + MEMBER(Compress, COMPRESS, 4) \ + MEMBER(Eikonal, EIKONAL, 5) \ + MEMBER(ClearBricks, CLEAR_BRICKS, 6) \ + MEMBER(MergeBricks, MERGE_BRICKS, 7) \ + MEMBER(InstanceOpsTrianglePass1, INSTANCE_OPS_TRIANGLE_PASS_1, 8) \ + MEMBER(InstanceOpsDeferredReleaseBrits, INSTANCE_OPS_DEFERRED_RELEASE_BRITS, 9) \ + MEMBER(ClearBrits, CLEAR_BRITS, 10) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerIndirectOffsets) + FfxUInt32x4 pad; +#define MEMBER(pascal_name, _upper_name, _index) FfxUInt32x4 pascal_name; + MEMBER_LIST +#undef MEMBER +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerIndirectOffsets) + +#define MEMBER(_pascal_name, _upper_name, _index) + 1 +FFX_BRIXELIZER_CONST FfxUInt32 FFX_BRIXELIZER_NUM_INDIRECT_OFFSETS = 1 MEMBER_LIST; +#undef MEMBER + +FFX_BRIXELIZER_BEGIN_ENUM(FfxBrixelizerIndirectOffsetsEnum) +#define MEMBER(_pascal_name, upper_name, index) FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INDIRECT_OFFSETS_##upper_name, index * FFX_BRIXELIZER_STATIC_CONFIG_INDIRECT_DISPATCH_STRIDE) + MEMBER_LIST +#undef MEMBER +#define MEMBER(_pascal_name, upper_name, index) FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_INDIRECT_OFFSETS_##upper_name##_32, index * FFX_BRIXELIZER_STATIC_CONFIG_INDIRECT_DISPATCH_STRIDE32) + MEMBER_LIST +#undef MEMBER +FFX_BRIXELIZER_END_ENUM(FfxBrixelizerIndirectOffsetsEnum) + +#undef MEMBER_LIST + +FFX_BRIXELIZER_BEGIN_ENUM(FfxBrixelizerJobFlagsInternal) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_JOB_FLAG_NONE, FfxUInt32(0)) + FFX_BRIXELIZER_ENUM_VALUE(FFX_BRIXELIZER_JOB_FLAG_INVALIDATE, (FfxUInt32(1) << FfxUInt32(0))) +FFX_BRIXELIZER_END_ENUM(FfxBrixelizerJobFlagsInternal) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerBasicMeshInfo) + FfxUInt32 flags; + FfxUInt32 indexBufferID; + FfxUInt32 indexBufferOffset; + FfxUInt32 vertexBufferID; + FfxUInt32 vertexBufferOffset; + FfxUInt32 vertexCount; + FfxUInt32 vertexStride; + FfxUInt32 triangleCount; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerBasicMeshInfo) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerInstanceInfo) + FfxFloat32x3 aabbMin; // voxel aligned + FfxUInt32 pack0; // | 16: vertex buffer id | 16: index buffer id | + + FfxFloat32x3 aabbMax; // voxel aligned + FfxUInt32 pack1; // ! 6: vertex stride | 10: flags | | | + + FfxUInt32 indexBufferOffset; + FfxUInt32 vertexBufferOffset; + FfxUInt32 vertexCount; + FfxUInt32 triangleCount; + + FfxUInt32x3 padding; + FfxUInt32 index; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerInstanceInfo) + +#ifdef FFX_GPU +FfxBrixelizerBasicMeshInfo ffxBrixelizerInstanceInfoGetMeshInfo(FFX_PARAMETER_IN FfxBrixelizerInstanceInfo instance_info) +{ + FfxBrixelizerBasicMeshInfo info; + info.flags = (instance_info.pack1 >> 16) & FfxUInt32(0x1ff); + info.triangleCount = instance_info.triangleCount; + info.indexBufferID = (instance_info.pack0 >> 0) & FfxUInt32(0xffff); + info.indexBufferOffset = instance_info.indexBufferOffset; + info.vertexBufferID = (instance_info.pack0 >> 16) & FfxUInt32(0xffff); + info.vertexBufferOffset = instance_info.vertexBufferOffset; + info.vertexStride = (instance_info.pack1 >> 26) & 0x3f; + return info; +} +#endif + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerBrixelizationJob) + FfxUInt32x3 aabbMin; // in local cascade voxel size + FfxUInt32 instanceIdx; + + FfxUInt32x3 aabbMax; // in local cascade voxel size + FfxUInt32 flags; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerBrixelizationJob) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerIndexRef) + FfxUInt32 surface_id; + FfxUInt32 instance_id; + FfxUInt32 triangle_index; + FfxUInt32 pad0; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerIndexRef) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerTriangleReference) + FfxUInt32 voxel_idx; + FfxUInt32 triangle_id; + FfxUInt32 local_ref_idx; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerTriangleReference) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerInstanceReference) + FfxUInt32 voxel_idx; + FfxUInt32 instance_id; + FfxUInt32 local_ref_idx; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerInstanceReference) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerTriangle) + FfxUInt32 job_idx; + FfxUInt32 triangle_index; + FfxUInt32x3 face3; + + FfxFloat32x3 wp0; + FfxFloat32x3 wp1; + FfxFloat32x3 wp2; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerTriangle) + +#define FFX_BRIXELIZER_TRIANGLE_SMALL_FLAG (FfxUInt32(1) << FfxUInt32(31)) +#define FFX_BRIXELIZER_TRIANGLE_OFFSET_MASK (0x7fffffffu) + +#define FFX_BRIXELIZER_INVALID_ALLOCATION 0x00ffffffu +#define FFX_BRIXELIZER_VOXEL_ID_MASK 0xffffff +#define FFX_BRIXELIZER_CASCADE_ID_SHIFT 24 + +#ifdef FFX_GPU +FfxBoolean FfxBrixelizerTriangleIsSmall(FfxUInt32 id) { return ((id & FFX_BRIXELIZER_TRIANGLE_SMALL_FLAG) != 0); } +FfxUInt32 FfxBrixelizerTriangleIDGetOffset(FfxUInt32 id) { return id & FFX_BRIXELIZER_TRIANGLE_OFFSET_MASK; } +FfxBoolean FfxBrixelizerIsInvalidID(FfxUInt32 id) { return (id & FFX_BRIXELIZER_INVALID_ID) == FFX_BRIXELIZER_INVALID_ID; } +#endif + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerBuildInfo) + FfxInt32 tree_iteration; + FfxUInt32 max_bricks_per_bake; + FfxUInt32 num_jobs; + FfxUInt32 cascade_index; + + FfxUInt32 cascade_shift; // [1, 2, 4] for 1x, 2x and 4x + FfxUInt32 is_dynamic; + FfxUInt32 do_initialization; + FfxUInt32 num_job_voxels; + + FfxUInt32 src_cascade_A; + FfxUInt32 src_cascade_B; + FfxUInt32 dst_cascade; + FfxUInt32 merge_instance_idx; + + FfxUInt32x3 _padding; + FfxUInt32 build_flags; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerBuildInfo) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerDebugAABB) + FfxFloat32x3 color; + FfxFloat32x3 aabbMin; + FfxFloat32x3 aabbMax; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerDebugAABB) + +FFX_BRIXELIZER_BEGIN_STRUCT(FfxBrixelizerDebugInfo) + FfxFloat32x4x4 inv_view; ///< Stored in row-major order. + + FfxFloat32x4x4 inv_proj; ///< Stored in row-major order. + + FfxFloat32 t_min; + FfxFloat32 t_max; + FfxFloat32 preview_sdf_solve_eps; + FfxUInt32 start_cascade_idx; + + FfxUInt32 end_cascade_idx; + FfxUInt32 debug_state; + FfxUInt32 max_aabbs; + FfxUInt32 _padding; +FFX_BRIXELIZER_END_STRUCT(FfxBrixelizerDebugInfo) + +#endif // FFX_BRIXELIZER_HOST_GPU_SHARED_PRIVATE_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_mesh_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_mesh_common.h new file mode 100644 index 00000000..2f9da247 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_mesh_common.h @@ -0,0 +1,173 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_MESH_COMMON_H +#define FFX_BRIXELIZER_MESH_COMMON_H + +#include "ffx_brixelizer_common_private.h" + +struct FfxBrixelizerTrianglePos { + FfxUInt32x3 face3; + + FfxFloat32x3 wp0; + FfxFloat32x3 wp1; + FfxFloat32x3 wp2; +}; + +FfxFloat32x3 FFX_Fetch_PositionRGBA16(FfxUInt32 buffer_id, FfxUInt32 offset, FfxUInt32 vertex_id, FfxUInt32 stride) +{ + FfxUInt32x2 pack = LoadVertexBufferUInt2(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); + + FfxFloat32x2 xy = ffxUnpackF32(pack.x); + FfxFloat32x2 zw = ffxUnpackF32(pack.y); + +#if 0 + FfxFloat32 x = f16tof32((pack.x >> FfxUInt32(0)) & FfxUInt32(0xFFFF)); + FfxFloat32 y = f16tof32((pack.x >> FfxUInt32(16)) & FfxUInt32(0xFFFF)); + FfxFloat32 z = f16tof32((pack.y >> FfxUInt32(0)) & FfxUInt32(0xFFFF)); + FfxFloat32 w = f16tof32((pack.y >> FfxUInt32(16)) & FfxUInt32(0xFFFF)); +#endif + + return FfxFloat32x4(xy, zw).xyz; +} + +FfxFloat32x4 FFX_Fetch_Unorm4(FfxUInt32 buffer_id, FfxUInt32 offset, FfxUInt32 vertex_id, FfxUInt32 stride) +{ + FfxUInt32 pack = LoadVertexBufferUInt(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); + FfxFloat32 x = FfxFloat32((pack >> FfxUInt32(0)) & FfxUInt32(0xFF)) / FfxFloat32(255.0); + FfxFloat32 y = FfxFloat32((pack >> FfxUInt32(8)) & FfxUInt32(0xFF)) / FfxFloat32(255.0); + FfxFloat32 z = FfxFloat32((pack >> FfxUInt32(16)) & FfxUInt32(0xFF)) / FfxFloat32(255.0); + FfxFloat32 w = FfxFloat32((pack >> FfxUInt32(24)) & FfxUInt32(0xFF)) / FfxFloat32(255.0); + return FfxFloat32x4(x, y, z, w); +} + +FfxFloat32x2 FFX_Fetch_RG16_UNORM(FfxUInt32 buffer_id, FfxUInt32 offset, FfxUInt32 vertex_id, FfxUInt32 stride) +{ + FfxUInt32 pack = LoadVertexBufferUInt(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); + FfxFloat32 x = FfxFloat32((pack >> FfxUInt32(0)) & 0xFFFFu) / FfxFloat32(65535.0); + FfxFloat32 y = FfxFloat32((pack >> FfxUInt32(16)) & 0xFFFFu) / FfxFloat32(65535.0); + return FfxFloat32x2(x, y); +} + +void FFX_Fetch_Face_Indices_U32(FfxUInt32 buffer_id, FFX_PARAMETER_OUT FfxUInt32x3 face3, FfxUInt32 offset, FfxUInt32 triangle_id) +{ + face3 = LoadVertexBufferUInt3(buffer_id, (offset + FfxUInt32(12) * triangle_id) / FFX_BRIXELIZER_SIZEOF_UINT); +} + +void FFX_Fetch_Face_Indices_U16(FfxUInt32 buffer_id, FFX_PARAMETER_OUT FfxUInt32x3 face3, FfxUInt32 offset, FfxUInt32 triangle_id) +{ + FfxUInt32 word_offset = offset / 2; + + FfxUInt32 word_id_0 = word_offset + triangle_id * FfxUInt32(3) + FfxUInt32(0); + FfxUInt32 dword_id_0 = word_id_0 / FfxUInt32(2); + FfxUInt32 shift_0 = FfxUInt32(16) * (word_id_0 & FfxUInt32(1)); + + FfxUInt32 word_id_1 = word_offset + triangle_id * FfxUInt32(3) + FfxUInt32(1); + FfxUInt32 dword_id_1 = word_id_1 / FfxUInt32(2); + FfxUInt32 shift_1 = FfxUInt32(16) * (word_id_1 & FfxUInt32(1)); + + FfxUInt32 word_id_2 = word_offset + triangle_id * FfxUInt32(3) + FfxUInt32(2); + FfxUInt32 dword_id_2 = word_id_2 / FfxUInt32(2); + FfxUInt32 shift_2 = FfxUInt32(16) * (word_id_2 & FfxUInt32(1)); + + FfxUInt32 u0 = LoadVertexBufferUInt(buffer_id, dword_id_0); + u0 = (u0 >> shift_0) & FfxUInt32(0xFFFF); + FfxUInt32 u1 = LoadVertexBufferUInt(buffer_id, dword_id_1); + u1 = (u1 >> shift_1) & FfxUInt32(0xFFFF); + FfxUInt32 u2 = LoadVertexBufferUInt(buffer_id, dword_id_2); + u2 = (u2 >> shift_2) & FfxUInt32(0xFFFF); + face3 = FfxUInt32x3(u0, u1, u2); +} + +FfxFloat32x2 FFX_Fetch_float2(FfxUInt32 buffer_id, FfxUInt32 offset, FfxUInt32 vertex_id, FfxUInt32 stride) +{ + return LoadVertexBufferFloat2(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); +} + +FfxFloat32x3 FFX_Fetch_float3(FfxUInt32 buffer_id, FfxUInt32 offset, FfxUInt32 vertex_id, FfxUInt32 stride) +{ + return LoadVertexBufferFloat3(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); +} + +FfxFloat32x4 FFX_Fetch_float4(FfxUInt32 buffer_id, FfxUInt32 offset, FfxUInt32 vertex_id, FfxUInt32 stride) +{ + return LoadVertexBufferFloat4(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); +} + +FfxFloat32x3 FFX_Fetch_Position(FfxUInt32 flags, FfxUInt32 buffer_id, FfxUInt32 offset, FfxUInt32 vertex_id, FfxUInt32 stride) +{ + if (FFX_HAS_FLAG(flags, FFX_BRIXELIZER_INSTANCE_FLAG_USE_RGBA16_VERTEX)) { + FfxUInt32x2 pack = LoadVertexBufferUInt2(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); + + FfxFloat32x2 xy = ffxUnpackF32(pack.x); + FfxFloat32x2 zw = ffxUnpackF32(pack.y); + + return FfxFloat32x4(xy, zw).xyz; + } else + return LoadVertexBufferFloat3(buffer_id, (offset + stride * vertex_id) / FFX_BRIXELIZER_SIZEOF_UINT); +} + +FfxUInt32x3 FfxBrixelizerFetchFace(FfxUInt32 flags, FfxUInt32 indexBufferID, FfxUInt32 indexBufferOffset, FfxUInt32 triangle_idx) +{ + if (FFX_HAS_FLAG(flags, FFX_BRIXELIZER_INSTANCE_FLAG_USE_INDEXLESS_QUAD_LIST)) { // Procedural quad index buffer + FfxUInt32 quad_id = triangle_idx / FfxUInt32(2); // 2 triangles per quad + FfxUInt32 base_vertex = quad_id * FfxUInt32(4); // 4 vertices per quad + if (FFX_HAS_FLAG(triangle_idx, FfxUInt32(1))) { + return FFX_BROADCAST_UINT32X3(base_vertex) + FfxUInt32x3(FfxUInt32(2), FfxUInt32(3), FfxUInt32(0)); + } else { + return FFX_BROADCAST_UINT32X3(base_vertex) + FfxUInt32x3(FfxUInt32(0), FfxUInt32(1), FfxUInt32(2)); + } + } else { + FfxUInt32x3 face3; + if (FFX_HAS_FLAG(flags, FFX_BRIXELIZER_INSTANCE_FLAG_USE_U16_INDEX)) { + FFX_Fetch_Face_Indices_U16(indexBufferID, /* out */ face3, /* in */ indexBufferOffset, /* in */ triangle_idx); + } else { // FFX_BRIXELIZER_INDEX_TYPE_U32 + FFX_Fetch_Face_Indices_U32(indexBufferID, /* out */ face3, /* in */ indexBufferOffset, /* in */ triangle_idx); + } + return face3; + } +} + +FfxBrixelizerTrianglePos FfxBrixelizerFetchTriangle(FfxUInt32 flags, FfxUInt32 indexBufferID, FfxUInt32 indexBufferOffset, FfxUInt32 vertexBufferID, FfxUInt32 vertexBufferOffset, FfxUInt32 vertexBufferStride, + FfxUInt32 instance_idx, FfxUInt32 triangle_idx) +{ + FfxUInt32x3 face3 = FfxBrixelizerFetchFace(flags, indexBufferID, indexBufferOffset, triangle_idx); + FfxFloat32x3 p0 = FFX_Fetch_Position(flags, vertexBufferID, vertexBufferOffset, face3.x, vertexBufferStride); + FfxFloat32x3 p1 = FFX_Fetch_Position(flags, vertexBufferID, vertexBufferOffset, face3.y, vertexBufferStride); + FfxFloat32x3 p2 = FFX_Fetch_Position(flags, vertexBufferID, vertexBufferOffset, face3.z, vertexBufferStride); + FfxBrixelizerTrianglePos tri; + + FfxFloat32x3x4 obj_to_anchor = LoadInstanceTransform(instance_idx); + tri.face3 = face3; + tri.wp0 = FFX_TRANSFORM_VECTOR(obj_to_anchor, FfxFloat32x4(p0, FfxFloat32(1.0))).xyz; + tri.wp1 = FFX_TRANSFORM_VECTOR(obj_to_anchor, FfxFloat32x4(p1, FfxFloat32(1.0))).xyz; + tri.wp2 = FFX_TRANSFORM_VECTOR(obj_to_anchor, FfxFloat32x4(p2, FfxFloat32(1.0))).xyz; + return tri; +} + +FfxBrixelizerTrianglePos FfxBrixelizerFetchTriangle(FfxBrixelizerBasicMeshInfo mesh_info, FfxUInt32 instance_id, FfxUInt32 triangle_id) +{ + return FfxBrixelizerFetchTriangle(mesh_info.flags, mesh_info.indexBufferID, mesh_info.indexBufferOffset, mesh_info.vertexBufferID, mesh_info.vertexBufferOffset, + mesh_info.vertexStride, instance_id, triangle_id); +} + +#endif // FFX_BRIXELIZER_MESH_COMMON_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_resources.h new file mode 100644 index 00000000..98b54d96 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_resources.h @@ -0,0 +1,91 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_RESOURCES_H +#define FFX_BRIXELIZER_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CASCADE_AABB_TREE 1 // 24 elements +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CASCADE_AABB_TREES 1 // 24 elements (Same as the previous ID, used for binding the descriptor array) +// The cascade octree previously occupied 24 elements here. +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CASCADE_BRICK_MAP 25 // 24 elements +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CASCADE_BRICK_MAPS 25 // 24 elements (Same as the previous ID, used for binding the descriptor array) +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CASCADE_READBACK_BUFFERS 49 // 3 * 24 elements + +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_INSTANCE_INFO_BUFFER 121 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_INSTANCE_TRANSFORM_BUFFER 122 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_JOB_BUFFER 123 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_JOB_INDEX_BUFFER 124 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_INDIRECT_ARGS_1 125 + +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_COUNTERS 126 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_INDEX_SWAP 127 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_VOXEL_ALLOCATION_FAIL_COUNTER 128 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_BRICKS_STORAGE 129 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_BRICKS_STORAGE_OFFSETS 130 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_BRICKS_COMPRESSION_LIST 131 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_BRICKS_CLEAR_LIST 132 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_JOB_COUNTERS 133 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_JOB_COUNTERS_SCAN 134 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_JOB_GLOBAL_COUNTERS_SCAN 135 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_CR1_REFERENCES 136 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_CR1_COMPACTED_REFERENCES 137 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_CR1_REF_COUNTERS 138 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_CR1_REF_COUNTER_SCAN 139 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_CR1_REF_GLOBAL_SCAN 140 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_CR1_STAMP_SCAN 141 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_CR1_STAMP_GLOBAL_SCAN 142 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_DEBUG_AABBS 143 + +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_BRICKS_VOXEL_MAP 144 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_BRICKS_AABB 145 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_BRICKS_FREE_LIST 146 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_BRICKS_CLEAR_LIST 147 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_BRICKS_EIKONAL_LIST 148 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_BRICKS_MERGE_LIST 149 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_BRICKS_EIKONAL_COUNTERS 150 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_COUNTERS 151 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_COUNTERS_READBACK_0 152 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_COUNTERS_READBACK_1 153 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_COUNTERS_READBACK_2 154 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_CONTEXT_SDF_ATLAS 155 + +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_UPLOAD_INSTANCE_INFO_BUFFER 156 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_UPLOAD_INSTANCE_TRANSFORM_BUFFER 157 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_UPLOAD_JOB_BUFFER 158 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_UPLOAD_JOB_INDEX_BUFFER 159 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_DEBUG_OUTPUT 160 +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_SCRATCH_BUFFER 161 + +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_UPLOAD_DEBUG_INSTANCE_ID_BUFFER 162 + +#define FFX_BRIXELIZER_RESOURCE_IDENTIFIER_COUNT 163 + +#define FFX_BRIXELIZER_CONSTANTBUFFER_IDENTIFIER_CASCADE_INFO 0 +#define FFX_BRIXELIZER_CONSTANTBUFFER_IDENTIFIER_CONTEXT_INFO 1 +#define FFX_BRIXELIZER_CONSTANTBUFFER_IDENTIFIER_BUILD_INFO 2 +#define FFX_BRIXELIZER_CONSTANTBUFFER_IDENTIFIER_DEBUG_INFO 3 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif //!defined( FFX_BRIXELIZER_RESOURCES_H ) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_trace_ops.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_trace_ops.h new file mode 100644 index 00000000..752bacf1 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizer/ffx_brixelizer_trace_ops.h @@ -0,0 +1,354 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_TRACE_OPS_H +#define FFX_BRIXELIZER_TRACE_OPS_H + +#include "../ffx_core.h" + +#include "ffx_brixelizer_host_gpu_shared.h" + +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIndex); +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 cascadeID); +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw); +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex); + +#include "ffx_brixelizer_brick_common.h" + +/// A structure encapsulating the parameters for a ray to be marched using Brixelizer. +/// +/// @ingroup Brixelizer +struct FfxBrixelizerRayDesc { + FfxUInt32 start_cascade_id; ///< The index of the most detailed cascade for ray traversal. + FfxUInt32 end_cascade_id; ///< The index of the least detailed cascade for ray traversal. + FfxFloat32 t_min; ///< The minimum distance at which to accept a hit. + FfxFloat32 t_max; ///< The maximum distance at which to accept a hit. + FfxFloat32x3 origin; ///< The origin of the ray. + FfxFloat32x3 direction; ///< The direction of the ray. This input should be normalized. +}; + +/// A structure encapsulating all data associated with a ray SDF hit. +/// +/// @ingroup Brixelizer +struct FfxBrixelizerHitRaw { + FfxFloat32 t; ///< The distance from the ray origin to the hit. + FfxUInt32 brick_id; ///< The ID of a hit brick. + FfxUInt32 uvwc; ///< Packed UVW coordinates of the hit location. UVW coordinates are in brick space. + FfxUInt32 iter_count; ///< The count of iterations to find the intersection. +}; + +/// A structure encapsulating minimal data associated with a ray SDF hit. +/// +/// @ingroup Brixelizer +struct FfxBrixelizerHit { + FfxFloat32 t; ///< The distance from the ray origin to the hit. +}; + +/// A structure encapsulating the distance to a ray hit and the normal of the surface hit. +/// +/// @ingroup Brixelizer +struct FfxBrixelizerHitWithNormal { + FfxFloat32 t; ///< The distance from the ray origin to the hit. + FfxFloat32x3 normal; ///< The normal of the SDF surface at the hit location. +}; + +FfxFloat32 FfxBrixelizerGetIntersectCorner(FfxBrixelizerCascadeInfo CINFO, FfxFloat32x3 corner_sign, FfxFloat32x3 ray_cursor, FfxFloat32x3 ray_idirection, FfxFloat32 EPS, inout FfxUInt32x3 coord, FfxFloat32 voxel_k) +{ + FfxFloat32x3 relative_cascade_origin = CINFO.grid_min - ray_cursor; + coord = FfxUInt32x3(-relative_cascade_origin / (CINFO.voxel_size * voxel_k)); + FfxFloat32x3 node_max = relative_cascade_origin + (FfxFloat32x3(coord.x, coord.y, coord.z) + corner_sign) * (CINFO.voxel_size * voxel_k); + FfxFloat32x3 tbot = ray_idirection * node_max; + FfxFloat32 hit_max = min(tbot.x, min(tbot.y, tbot.z)) + EPS; + return hit_max; +} + +/// This function is used for running a ray query against the Brixelizer SDF acceleration structure. +/// The "raw" version returns the data immediately accessible from the SDF structure generated by a hit. +/// +/// @param [in] ray_desc A structure encapsulating the parameters of the ray for ray traversal. See FfxBrixelizerRayDesc. +/// @param [out] hit A structure of values to be filled in with details of any hit. +/// +/// @retval +/// true The ray hit the SDF and hit data has been written to the hit parameter. +/// @retval +/// false The ray did not intersect the SDF and no hit data has been written. +/// +/// @ingroup Brixelizer +FfxBoolean FfxBrixelizerTraverseRaw(in FfxBrixelizerRayDesc ray_desc, out FfxBrixelizerHitRaw hit) +{ + FfxUInt32 cascade_id = ray_desc.start_cascade_id; + FfxUInt32 g_end_cascade = ray_desc.end_cascade_id; + + FfxFloat32x3 ray_origin = ray_desc.origin; + FfxFloat32 ray_t = ray_desc.t_min; + FfxFloat32x3 ray_direction = ray_desc.direction; + FfxFloat32x3 ray_idirection = FfxFloat32(1.0) / ray_desc.direction; + FfxFloat32x3 corner_sign = FfxFloat32x3( + ray_direction.x > FfxFloat32(0.0) ? FfxFloat32(1.0) : FfxFloat32(0.0), + ray_direction.y > FfxFloat32(0.0) ? FfxFloat32(1.0) : FfxFloat32(0.0), + ray_direction.z > FfxFloat32(0.0) ? FfxFloat32(1.0) : FfxFloat32(0.0) + ); + hit.iter_count = 0; + FfxUInt32 local_iter_cnt = 0; + cascade_id = ffxWaveMin(cascade_id); + for (; cascade_id <= g_end_cascade; cascade_id++) { + cascade_id = ffxWaveReadLaneFirstU1(cascade_id); + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(cascade_id); + const FfxFloat32 voxel_size = CINFO.voxel_size; + local_iter_cnt = 0; + + FfxFloat32 orig_ray_t = ray_t; + + FfxFloat32 EPS = CINFO.voxel_size / FfxFloat32(1024.0); + FfxFloat32 cascade_hit_min; + FfxFloat32 cascade_hit_max; + FfxFloat32x3 ray_cursor = ray_origin + ray_direction * ray_t; + FfxFloat32 top_level_max; + const FfxUInt32 ITER_LIMIT = 32; + FfxFloat32x3 cascade_aabb_min = LoadCascadeAABBTreesFloat3(cascade_id, (16 * 16 * 16) + (2 * 4 * 4 * 4 + 0) * 3); + FfxFloat32x3 cascade_aabb_max = LoadCascadeAABBTreesFloat3(cascade_id, (16 * 16 * 16) + (2 * 4 * 4 * 4 + 1) * 3); + + // if the ray cursor isn't inside the current cascade skip to the next one + if (!((CINFO.is_enabled > 0) && all(FFX_GREATER_THAN(ray_cursor, CINFO.grid_min)) && all(FFX_LESS_THAN(ray_cursor, CINFO.grid_max)))) { + continue; + } + + if (FfxBrixelizerIntersectAABB(ray_origin, ray_idirection, cascade_aabb_min, cascade_aabb_max, + /* out */ cascade_hit_min, + /* out */ cascade_hit_max)) { + FfxFloat32 stamp_size = FfxFloat32(16.0); + FfxUInt32 level = 0; + cascade_hit_max = min(cascade_hit_max, ray_desc.t_max); + + while (ray_t < cascade_hit_max) { + hit.iter_count++; + local_iter_cnt++; + if (local_iter_cnt > ITER_LIMIT) + break; + + ray_cursor = ray_origin + ray_direction * ray_t; + + FfxFloat32x3 stamp_aabb_min; + FfxFloat32x3 stamp_aabb_max; + + FfxUInt32x3 stamp_coord; + FfxFloat32 stamp_hit_max = ray_t + FfxBrixelizerGetIntersectCorner(CINFO, corner_sign, ray_cursor, ray_idirection, EPS, /* inout */ stamp_coord, stamp_size); + FfxUInt32 stamp_idx = FfxBrixelizerFlattenPOT(stamp_coord, FfxUInt32(2) << level); + if (level == 0) { + top_level_max = stamp_hit_max; + stamp_aabb_min = LoadCascadeAABBTreesFloat3(cascade_id, (16 * 16 * 16) + (2 * stamp_idx + 0) * 3); + stamp_aabb_max = LoadCascadeAABBTreesFloat3(cascade_id, (16 * 16 * 16) + (2 * stamp_idx + 1) * 3); + } else { + FfxUInt32 bottom_stamp_pack = LoadCascadeAABBTreesUInt(cascade_id, stamp_idx); + if (bottom_stamp_pack == FFX_BRIXELIZER_INVALID_BOTTOM_AABB_NODE) { + stamp_aabb_min = FFX_BROADCAST_FLOAT32X3(0.0); + stamp_aabb_max = FFX_BROADCAST_FLOAT32X3(0.0); + } else { + FfxUInt32x3 bottom_iaabb_min = FfxBrixelizerUnflattenPOT(bottom_stamp_pack & 0x7fff, 5); + FfxUInt32x3 bottom_iaabb_max = FfxBrixelizerUnflattenPOT((bottom_stamp_pack >> 16) & 0x7fff, 5); + FfxFloat32x3 bottom_stamp_world_coord = FfxFloat32x3(stamp_coord) * CINFO.voxel_size * FfxFloat32(4.0) + CINFO.grid_min; + stamp_aabb_min = bottom_stamp_world_coord + FfxFloat32x3(bottom_iaabb_min) * CINFO.voxel_size / FfxFloat32(8.0); + stamp_aabb_max = bottom_stamp_world_coord + FfxFloat32x3(bottom_iaabb_max + FFX_BROADCAST_UINT32X3(1)) * CINFO.voxel_size / FfxFloat32(8.0); + } + } + + FfxFloat32 stamp_aabb_hit_max; + FfxFloat32 stamp_aabb_hit_min; + if (ffxAsUInt32(stamp_aabb_min.x) == ffxAsUInt32(stamp_aabb_max.x) || !FfxBrixelizerIntersectAABB(ray_origin, ray_idirection, stamp_aabb_min, stamp_aabb_max, + /* out */ stamp_aabb_hit_min, + /* out */ stamp_aabb_hit_max)) { // empty node + ray_t = stamp_hit_max; // Advance the ray + if (level == 0) { + continue; + } else { + if (ray_t > top_level_max) { + level = 0; + stamp_size = FfxFloat32(16.0); + } + continue; + } + } else { + if (level == 0) { + level = 1; + stamp_size = FfxFloat32(4.0); + continue; + } else { + stamp_aabb_hit_max = min(stamp_aabb_hit_max, ray_desc.t_max); + + while (ray_t < stamp_aabb_hit_max) { + hit.iter_count++; + local_iter_cnt++; + if (local_iter_cnt > ITER_LIMIT) + break; + + ray_cursor = ray_origin + ray_direction * ray_t; + + FfxUInt32x3 voxel; + FfxFloat32 voxel_hit_max = FfxBrixelizerGetIntersectCorner(CINFO, corner_sign, ray_cursor, ray_idirection, EPS, /* inout */ voxel, FfxFloat32(1.0)); + if (voxel_hit_max < EPS) { + ray_t = ray_t + voxel_hit_max; + break; + } + voxel_hit_max += ray_t; + FfxUInt32 brick_id = FfxBrixelizerLoadBrickIDUniform(FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(CINFO, voxel), 6), cascade_id); + if (brick_id == FFX_BRIXELIZER_UNINITIALIZED_ID) { + hit.iter_count = ITER_LIMIT + 1; + local_iter_cnt = ITER_LIMIT + 1; + break; + } + if (FfxBrixelizerIsValidID(brick_id)) { + FfxFloat32x3 voxel_min = FfxFloat32x3(voxel.x, voxel.y, voxel.z) * CINFO.voxel_size + CINFO.grid_min; + FfxUInt32 brick_aabb_pack = LoadBricksAABB(FfxBrixelizerBrickGetIndex(brick_id)); + FfxUInt32x3 brick_aabb_umin = FfxBrixelizerUnflattenPOT(brick_aabb_pack & ((1 << 9) - 1), 3); + FfxUInt32x3 brick_aabb_umax = FfxBrixelizerUnflattenPOT((brick_aabb_pack >> 9) & ((1 << 9) - 1), 3) + FFX_BROADCAST_UINT32X3(1); + FfxFloat32x3 brick_aabb_min = voxel_min - FFX_BROADCAST_FLOAT32X3(CINFO.voxel_size / FfxFloat32(2.0 * 7.0)) + FfxFloat32x3(brick_aabb_umin) * (CINFO.voxel_size / FfxFloat32(7.0)); + FfxFloat32x3 brick_aabb_max = voxel_min - FFX_BROADCAST_FLOAT32X3(CINFO.voxel_size / FfxFloat32(2.0 * 7.0)) + FfxFloat32x3(brick_aabb_umax) * (CINFO.voxel_size / FfxFloat32(7.0)); + FfxFloat32 brick_hit_min; + FfxFloat32 brick_hit_max; + if (FfxBrixelizerIntersectAABB(ray_cursor, ray_idirection, brick_aabb_min, brick_aabb_max, + /* out */ brick_hit_min, + /* out */ brick_hit_max)) { + + FfxFloat32x3 uvw = (ray_cursor + brick_hit_min * ray_direction - voxel_min) * CINFO.ivoxel_size; + FfxFloat32 dist = FfxFloat32(1.0); + FfxFloat32 total_dist = 0.0f; + FfxFloat32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxFloat32x3 uvw_min = (brick_offset + FFX_BROADCAST_FLOAT32X3(FfxFloat32(0.5))) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE); + FfxFloat32x3 uvw_max = uvw_min + FFX_BROADCAST_FLOAT32X3(FfxFloat32(7.0)) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE); + for (FfxUInt32 i = 0; i < 8; i++) { + hit.iter_count++; + dist = FfxBrixelizerSampleBrixelDistance(uvw_min, uvw_max, uvw) - FFX_BRIXELIZER_TRAVERSAL_EPS; + if (dist < FFX_BRIXELIZER_TRAVERSAL_EPS) { + hit.t = ray_t + brick_hit_min + total_dist * voxel_size; + if (hit.t > ray_desc.t_max) { + return false; + } + + hit.brick_id = brick_id; + hit.uvwc = PackUVWC(FfxFloat32x4(uvw, 0.0)); + return true; + } + uvw += ray_direction * dist; + total_dist += dist; + if (any(FFX_GREATER_THAN(abs(uvw - FFX_BROADCAST_FLOAT32X3(0.5)), FFX_BROADCAST_FLOAT32X3(0.501)))) + break; + } + } + } + ray_t = voxel_hit_max; + } + if (ray_t > top_level_max) { + level = 0; + stamp_size = FfxFloat32(16.0); + } + if (local_iter_cnt > ITER_LIMIT) + break; + ray_t = stamp_hit_max; + continue; + } + } + } + } + + if (local_iter_cnt > ITER_LIMIT) { + ray_t = max(orig_ray_t, ray_t - CINFO.voxel_size); + continue; + } + + // advance ray to end of current cascade + FfxBrixelizerIntersectAABB(ray_origin, ray_idirection, CINFO.grid_min, CINFO.grid_max, /* out */ cascade_hit_min, /* out */ cascade_hit_max); + ray_t = max(orig_ray_t, cascade_hit_max - CINFO.voxel_size); + } + + return false; +} + +/// Calculate a normal from a hit described by an FfxBrixelizerHitRaw structure. +/// +/// @param [in] hit A ray hit with the SDF returned by FfxBrixelizerTraverseRaw. +/// +/// @retval A normal to the hit described by the hit paramter. +/// +/// @ingroup Brixelizer +FfxFloat32x3 FfxBrixelizerGetHitNormal(FfxBrixelizerHitRaw hit) +{ + FfxFloat32x3 uvw = FfxFloat32x3( + FfxBrixelizerUnpackUnsigned8Bits((hit.uvwc >> 0) & 0xff), + FfxBrixelizerUnpackUnsigned8Bits((hit.uvwc >> 8) & 0xff), + FfxBrixelizerUnpackUnsigned8Bits((hit.uvwc >> 16) & 0xff) + ); + uvw += FFX_BROADCAST_FLOAT32X3(1.0 / 512.0); + FfxUInt32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(hit.brick_id); + FfxFloat32x3 uvw_min = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(0.5)) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + FfxFloat32x3 uvw_max = (FfxFloat32x3(brick_offset) + FFX_BROADCAST_FLOAT32X3(float(8.0 - 0.5))) / FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE; + return FfxBrixelizerGetBrixelGrad(uvw_min, uvw_max, uvw); +} + +/// This function is used for running a ray query against the Brixelizer SDF acceleration structure. +/// This version simply returns the distance to a hit if a hit is encountered. +/// +/// @param [in] ray_desc A structure encapsulating the parameters of the ray for ray traversal. See FfxBrixelizerRayDesc. +/// @param [out] hit A structure of values to be filled in with details of any hit. +/// +/// @retval +/// true The ray hit the SDF and hit data has been written to the hit parameter. +/// @retval +/// false The ray did not intersect the SDF and no hit data has been written. +/// +/// @ingroup Brixelizer +FfxBoolean FfxBrixelizerTraverse(FfxBrixelizerRayDesc ray_desc, out FfxBrixelizerHit hit) +{ + FfxBrixelizerHitRaw raw_payload; + FfxBoolean result = FfxBrixelizerTraverseRaw(ray_desc, raw_payload); + hit.t = raw_payload.t; + return result; +} + +/// This function is used for running a ray query against the Brixelizer SDF acceleration structure. +/// This version returns the distance to a hit and a normal to the SDF geometry at a hit location when a hit +/// is encountered. +/// +/// +/// @param [in] ray_desc A structure encapsulating the parameters of the ray for ray traversal. See FfxBrixelizerRayDesc. +/// @param [out] hit A structure of values to be filled in with details of any hit. +/// +/// @retval +/// true The ray hit the SDF and hit data has been written to the hit parameter. +/// @retval +/// false The ray did not intersect the SDF and no hit data has been written. +/// +/// @ingroup Brixelizer +FfxBoolean FfxBrixelizerTraverseWithNormal(FfxBrixelizerRayDesc ray_desc, out FfxBrixelizerHitWithNormal hit) +{ + FfxBrixelizerHitRaw raw_payload; + FfxBoolean result = FfxBrixelizerTraverseRaw(ray_desc, raw_payload); + if (!result) { + return false; + } + hit.t = raw_payload.t; + hit.normal = FfxBrixelizerGetHitNormal(raw_payload); + return true; +} + +#endif // FFX_BRIXELIZER_TRACE_OPS_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/CMakeCompileBrixelizerGIShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/CMakeCompileBrixelizerGIShaders.txt new file mode 100644 index 00000000..0f314829 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/CMakeCompileBrixelizerGIShaders.txt @@ -0,0 +1,68 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(BRIXELIZER_GI_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(BRIXELIZER_GI_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/brixelizer" + "${FFX_GPU_PATH}/brixelizergi") + +set(BRIXELIZER_GI_PERMUTATION_ARGS + -DFFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED={0,1} + -DFFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR={0,1} + -DFFX_BRIXELIZER_GI_OPTION_DISABLE_DENOISER={0,1}) + +if (NOT BRIXELIZER_GI_SHADER_EXT) + set(BRIXELIZER_GI_SHADER_EXT *) +endif() + +file(GLOB BRIXELIZER_GI_SHADERS + "shaders/brixelizergi/ffx_brixelizergi_blur_x.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_blur_y.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_clear_cache.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_debug_visualization.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_downsample.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_emit_irradiance_cache.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_emit_primary_ray_radiance.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_fill_screen_probes.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_generate_disocclusion_mask.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_interpolate_screen_probes.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_prepare_clear_cache.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_project_screen_probes.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_propagate_sh.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_reproject_gi.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_reproject_screen_probes.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_spawn_screen_probes.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_specular_pre_trace.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_specular_trace.${BRIXELIZER_GI_SHADER_EXT}" + "shaders/brixelizergi/ffx_brixelizergi_upsample.${BRIXELIZER_GI_SHADER_EXT}") + +# compile all the shaders +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${BRIXELIZER_GI_BASE_ARGS}" "${BRIXELIZER_GI_API_BASE_ARGS}" "${BRIXELIZER_GI_PERMUTATION_ARGS}" "${BRIXELIZER_GI_INCLUDE_ARGS}" + "${BRIXELIZER_GI_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" BRIXELIZER_GI_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${BRIXELIZER_GI_PERMUTATION_OUTPUTS}") \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_callbacks_glsl.h new file mode 100644 index 00000000..82a56797 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_callbacks_glsl.h @@ -0,0 +1,1269 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_CALLBACKS_GLSL_H +#define FFX_BRIXELIZER_GI_CALLBACKS_GLSL_H + +#include "../ffx_core.h" + +#include "ffx_brixelizer_host_gpu_shared.h" +#include "ffx_brixelizergi_host_interface.h" + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +FfxBrixelizerGIConstants GetGIConstants(); +FfxUInt32x2 GetBufferDimensions(); +FfxFloat32x2 GetBufferDimensionsF32(); +FfxFloat32x2 GetProbeBufferDimensionsF32(); +FfxUInt32 GetFrameIndex(); +FfxUInt32x2 GetTileBufferDimensions(); +FfxFloat32x3 GetCameraPosition(); +FfxFloat32x4x4 GetViewMatrix(); +FfxFloat32x4x4 GetViewProjectionMatrix(); +FfxFloat32x4x4 GetInverseViewMatrix(); +FfxFloat32x4x4 GetInverseProjectionMatrix(); +FfxFloat32x4x4 GetInverseViewProjectionMatrix(); +FfxFloat32x4x4 GetPreviousViewProjectionMatrix(); +FfxFloat32x4x4 GetPreviousInverseViewMatrix(); +FfxFloat32x4x4 GetPreviousInverseProjectionMatrix(); +FfxFloat32 GetRoughnessThreshold(); +FfxUInt32 GetRoughnessChannel(); +FfxFloat32 GetEnvironmentMapIntensity(); +FfxUInt32 GetTracingConstantsStartCascade(); +FfxUInt32 GetTracingConstantsEndCascade(); +FfxFloat32 GetTracingConstantsRayPushoff(); +FfxFloat32 GetTracingConstantsTMin(); +FfxFloat32 GetTracingConstantsTMax(); +FfxFloat32 GetTracingConstantsSDFSolveEpsilon(); +FfxFloat32 GetTracingConstantsSpecularRayPushoff(); +FfxFloat32 GetTracingConstantsSpecularSDFSolveEpsilon(); +FfxUInt32 GetPassConstantsCascadeIndex(); +FfxFloat32 GetPassConstantsEnergyDecayK(); +FfxBrixelizerGIScalingConstants GetScalingConstants(); +FfxUInt32 GetScalingRoughnessChannel(); +FfxUInt32 LoadTempSpawnMask(FfxUInt32x2 coord); +void StoreTempSpawnMask(FfxUInt32x2 coord, FfxUInt32 value); +FfxUInt32 LoadTempRandomSeed(FfxUInt32x2 coord); +void StoreTempRandomSeed(FfxUInt32x2 coord, FfxUInt32 value); +FfxUInt32x4 LoadTempSpecularPretraceTarget(FfxUInt32x2 coord); +void StoreTempSpecularPretraceTarget(FfxUInt32x2 coord, FfxUInt32x4 value); +FfxFloat32x4 LoadStaticScreenProbesStat(FfxUInt32x2 coord); +void StoreStaticScreenProbesStat(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x4 SampleSpecularTargetSRV(FfxFloat32x2 uv); +FfxFloat32x4 LoadSpecularTargetSRV(FfxUInt32x2 coord); +FfxFloat32x4 LoadSpecularTarget(FfxUInt32x2 coord); +void StoreSpecularTarget(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxUInt32x4 LoadStaticProbeInfo(FfxUInt32 index); +void StoreStaticProbeInfo(FfxUInt32 index, FfxUInt32x4 value); +FfxUInt32x2 LoadStaticProbeSHBuffer(FfxUInt32 index); +void StoreStaticProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value); +FfxUInt32x4 LoadTempProbeInfo(FfxUInt32 index); +void StoreTempProbeInfo(FfxUInt32 index, FfxUInt32x4 info); +FfxUInt32x2 LoadTempProbeSHBuffer(FfxUInt32 index); +void StoreTempProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value); +FfxFloat32x3 SamplePrevLitOutput(FfxFloat32x2 uv); +FfxFloat32 LoadDepth(FfxUInt32x2 pixel_coordinate); +FfxFloat32 LoadRoughness(FfxUInt32x2 pixel_coordinate); +FfxFloat32 LoadPrevDepth(FfxUInt32x2 pixel_coordinate); +FfxFloat32 SampleDepth(FfxFloat32x2 uv); +FfxFloat32 SamplePrevDepth(FfxFloat32x2 uv); +FfxFloat32x3 LoadWorldNormal(FfxUInt32x2 pixel_coordinate); +FfxFloat32x3 LoadPrevWorldNormal(FfxUInt32x2 pixel_coordinate); +FfxFloat32x3 SampleWorldNormal(FfxFloat32x2 uv); +FfxFloat32x3 SamplePrevWorldNormal(FfxFloat32x2 uv); +FfxFloat32x2 SampleMotionVector(FfxFloat32x2 uv); +FfxFloat32x2 LoadMotionVector(FfxUInt32x2 pixel_coordinate); +FfxUInt32 LoadDisocclusionMask(FfxUInt32x2 pixel_coordinate); +void StoreDisocclusionMask(FfxUInt32x2 pixel_coordinate, float value); +FfxUInt32 LoadRaySwapIndirectArgs(FfxUInt32 elementIdx); +void StoreRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value); +void IncrementRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxUInt32x2 LoadBricksDirectSH(FfxUInt32 elementIdx); +void StoreBricksDirectSH(FfxUInt32 elementIdx, FfxUInt32x2 value); +FfxUInt32x2 LoadBricksSH(FfxUInt32 elementIdx); +void StoreBricksSH(FfxUInt32 elementIdx, FfxUInt32x2 value); +FfxUInt32x4 LoadBricksSHState(FfxUInt32 elementIdx); +void StoreBricksSHState(FfxUInt32 elementIdx, FfxUInt32x4 value); +FfxUInt32 LoadTempSpecularRaySwap(FfxUInt32 elementIdx); +void StoreTempSpecularRaySwap(FfxUInt32 elementIdx, FfxUInt32 value); +FfxFloat32x2 SampleBlueNoise(FfxUInt32x2 pixel, FfxUInt32 sample_index, FfxUInt32 dimension_offset); +FfxFloat32x2 SampleBlueNoise(in FfxUInt32x2 pixel, in FfxUInt32 sample_index); +FfxFloat32x4 LoadStaticScreenProbesSRV(FfxUInt32x2 coord); +FfxFloat32x4 SampleStaticScreenProbesSRV(FfxFloat32x2 uv); +FfxFloat32x4 LoadStaticScreenProbes(FfxUInt32x2 coord); +void StoreStaticScreenProbes(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x4 SampleStaticGITargetSRV(FfxFloat32x2 uv); +FfxFloat32x4 LoadStaticGITargetSRV(FfxUInt32x2 coord); +void StoreStaticGITarget(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x4 LoadDebugTraget(FfxUInt32x2 coord); +void StoreDebugTarget(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 world_space_reflected_direction); +FfxFloat32x3 SampleRadianceCacheSRV(FfxFloat32x3 uvw); +FfxFloat32x3 LoadRadianceCache(FfxUInt32x3 coord); +void StoreRadianceCache(FfxUInt32x3 coord, FfxFloat32x3 value); +void StoreDebugVisualization(FfxUInt32x2 pixel_coordinate, FfxFloat32x4 value); + +FfxFloat32 LoadSourceDepth(FfxUInt32x2 coord); +FfxFloat32x3 LoadSourceNormal(FfxUInt32x2 coord); +FfxFloat32x4 GatherSourceDepth(FfxFloat32x2 uv); +FfxFloat32x4 GatherSourcePrevDepth(FfxFloat32x2 uv); +FfxFloat32x3 SampleSourceNormal(FfxFloat32x2 uv); +FfxFloat32x3 SampleSourcePrevNormal(FfxFloat32x2 uv); +FfxFloat32 SampleSourceRoughness(FfxFloat32x2 uv); +FfxFloat32x2 SampleSourceMotionVector(FfxFloat32x2 uv); +FfxFloat32x3 SampleSourcePrevLitOutput(FfxFloat32x2 uv); +FfxFloat32x3 SampleDownsampledDiffuseGI(FfxFloat32x2 uv); +FfxFloat32x3 SampleDownsampledSpecularGI(FfxFloat32x2 uv); + +void StoreDownsampledDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value); +void StoreDownsampledPrevDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value); +void StoreDownsampledNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreDownsampledPrevNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreDownsampledRoughness(FfxUInt32x2 pixel_coordinate, FfxFloat32 value); +void StoreDownsampledMotionVector(FfxUInt32x2 pixel_coordinate, FfxFloat32x2 value); +void StoreDownsampledPrevLitOutput(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreUpsampledDiffuseGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreUpsampledSpecularGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); + +FfxBrixelizerContextInfo GetContextInfo(); +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 cascadeID); +FfxBrixelizerCascadeInfo GetCascadeInfoNonUniform(FfxUInt32 cascadeID); +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw); +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx); +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx); +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIndex); +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIndex); +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadCascadeBrickMapArrayNonUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex); + +// CBVs + +#if defined BRIXELIZER_GI_BIND_CB_SDFGI + layout (set = 0, binding = BRIXELIZER_GI_BIND_CB_SDFGI, std140) uniform GIConstants_t + { + FfxBrixelizerGIConstants data; + } g_sdfgi_constants; +#endif + +#if defined BRIXELIZER_GI_BIND_CB_PASS_CONSTANTS + layout (set = 0, binding = BRIXELIZER_GI_BIND_CB_PASS_CONSTANTS, std140) uniform PassConstants_t + { + FfxBrixelizerGIPassConstants data; + } g_pass_constants; +#endif + +#if defined BRIXELIZER_GI_BIND_CB_SCALING_CONSTANTS + layout (set = 0, binding = BRIXELIZER_GI_BIND_CB_SCALING_CONSTANTS, std140) uniform ScalingConstants_t + { + FfxBrixelizerGIScalingConstants data; + } g_scaling_constants; +#endif + +// SRVs + +#if defined BRIXELIZER_GI_BIND_SRV_DISOCCLUSION_MASK + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_DISOCCLUSION_MASK) uniform texture2D g_r_disocclusion_mask; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_GI_TARGET + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_STATIC_GI_TARGET) uniform texture2D g_sdfgi_r_static_gitarget; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_SCREEN_PROBES + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_STATIC_SCREEN_PROBES) uniform texture2D g_sdfgi_r_static_screen_probes; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SPECULAR_TARGET + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SPECULAR_TARGET) uniform texture2D g_sdfgi_r_specular_target; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_RADIANCE_CACHE + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_RADIANCE_CACHE) uniform texture3D g_bctx_radiance_cache; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_PREV_LIT_OUTPUT + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_PREV_LIT_OUTPUT) uniform texture2D g_prev_lit_output; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH) uniform texture2D g_depth; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH) uniform texture2D g_history_depth; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL) uniform texture2D g_normal; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL) uniform texture2D g_history_normal; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ROUGHNESS + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_ROUGHNESS) uniform texture2D g_roughness; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D g_motion_vectors; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ENVIRONMENT_MAP + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_ENVIRONMENT_MAP) uniform textureCube g_environment_map; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_BLUE_NOISE + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_INPUT_BLUE_NOISE) uniform texture2D g_blue_noise; +#endif + +// Downsampled SRVs + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_PREV_LIT_OUTPUT + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SOURCE_PREV_LIT_OUTPUT) uniform texture2D g_src_prev_lit_output; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_DEPTH + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SOURCE_DEPTH) uniform texture2D g_src_depth; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_DEPTH + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_DEPTH) uniform texture2D g_src_history_depth; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_NORMAL + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SOURCE_NORMAL) uniform texture2D g_src_normal; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_NORMAL + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_NORMAL) uniform texture2D g_src_history_normal; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_ROUGHNESS + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SOURCE_ROUGHNESS) uniform texture2D g_src_roughness; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_MOTION_VECTORS + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_SOURCE_MOTION_VECTORS) uniform texture2D g_src_motion_vectors; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_DIFFUSE_GI + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_DIFFUSE_GI) uniform texture2D g_downsampled_diffuse_gi; +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_SPECULAR_GI + layout (set = 0, binding = BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_SPECULAR_GI) uniform texture2D g_downsampled_specular_gi; +#endif + +// UAVs + +#if defined BRIXELIZER_GI_BIND_UAV_DISOCCLUSION_MASK + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DISOCCLUSION_MASK, r8) uniform image2D g_rw_disocclusion_mask; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES, rgba16f) uniform image2D g_sdfgi_rw_static_screen_probes; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_GI_TARGET + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_STATIC_GI_TARGET, rgba16f) uniform image2D g_sdfgi_rw_static_gitarget; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_TARGET + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DEBUG_TARGET, rgba16f) uniform image2D g_sdfgi_rw_debug_target; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RADIANCE_CACHE + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_RADIANCE_CACHE, r11f_g11f_b10f) uniform image3D g_rw_bctx_radiance_cache; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPAWN_MASK + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_TEMP_SPAWN_MASK, r32ui) uniform uimage2D g_sdfgi_rw_temp_spawn_mask; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_RAND_SEED + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_TEMP_RAND_SEED, r8ui) uniform uimage2D g_sdfgi_rw_temp_rand_seed; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_PRETRACE_TARGET + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_PRETRACE_TARGET, rgba32ui) uniform uimage2D g_sdfgi_rw_temp_specular_pretrace_target; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES_STAT + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES_STAT, rgba16f) uniform image2D g_sdfgi_rw_static_screen_probes_stat; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_SPECULAR_TARGET + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_SPECULAR_TARGET, rgba16f) uniform image2D g_sdfgi_rw_specular_target; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_VISUALIZATION + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DEBUG_VISUALIZATION, rgba16f) uniform image2D g_rw_debug_visualization; +#endif + +// Downsampled resources + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_PREV_LIT_OUTPUT + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_PREV_LIT_OUTPUT, rgba16f) uniform image2D g_downsampled_prev_lit_output; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_DEPTH + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_DEPTH, r32f) uniform image2D g_downsampled_depth; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_DEPTH + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_DEPTH, r32f) uniform image2D g_downsampled_history_depth; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_NORMAL + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_NORMAL, rgba16f) uniform image2D g_downsampled_normal; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_NORMAL + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_NORMAL, rgba16f) uniform image2D g_downsampled_history_normal; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_ROUGHNESS + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_ROUGHNESS, r8) uniform image2D g_downsampled_roughness; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_MOTION_VECTORS + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_MOTION_VECTORS, rg16f) uniform image2D g_downsampled_motion_vectors; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_DIFFUSE_GI + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_UPSAMPLED_DIFFUSE_GI, rgba16f) uniform image2D g_upsampled_diffuse_gi; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_SPECULAR_GI + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_UPSAMPLED_SPECULAR_GI, rgba16f) uniform image2D g_upsampled_specular_gi; +#endif + +// UAVs + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_INFO + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_INFO, std430) buffer BrixelizerGIStaticProbeInfo_t + { + FfxUInt32x4 data[]; + } g_sdfgi_rw_static_probe_info; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_SH_BUFFER + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_SH_BUFFER, std430) buffer BrixelizerGIStaticProbeSH_t + { + FfxUInt32x2 data[]; + } g_sdfgi_rw_static_probe_sh_buffer; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_INFO + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_INFO, std430) buffer BrixelizerGITempProbeInfo_t + { + FfxUInt32x4 data[]; + } g_sdfgi_rw_temp_probe_info; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_SH_BUFFER + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_SH_BUFFER, std430) buffer BrixelizerGITempProbeSH_t + { + FfxUInt32x2 data[]; + } g_sdfgi_rw_temp_probe_sh_buffer; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS, std430) buffer BrixelizerGIRaySwapIndirectArgs_t + { + FfxUInt32 data[]; + } g_sdfgi_rw_ray_swap_indirect_args; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH, std430) buffer BrixelizerGIBricksDirectSH_t + { + FfxUInt32x2 data[]; + } g_bctx_bricks_direct_sh; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_BRICKS_SH, std430) buffer BrixelizerGIBricksSH_t + { + FfxUInt32x2 data[]; + } g_bctx_bricks_sh; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE, std430) buffer BrixelizerGIBricksSHState_t + { + FfxUInt32x4 data[]; + } g_bctx_bricks_sh_state; +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP + layout (set = 0, binding = BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP, std430) buffer BrixelizerGITempSpecularRaySwap_t + { + FfxUInt32 data[]; + } g_sdfgi_rw_temp_specular_ray_swap; +#endif + +// Brixelizer Resources + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO + layout (set = 0, binding = BRIXELIZER_BIND_CB_CONTEXT_INFO, std140) uniform BrixelizerContextInfo_t + { + FfxBrixelizerContextInfo data; + } g_bx_context_info; +#endif + +#if defined BRIXELIZER_BIND_SRV_SDF_ATLAS + layout (set = 0, binding = BRIXELIZER_BIND_SRV_SDF_ATLAS) uniform texture3D r_sdf_atlas; +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_AABB + layout (set = 0, binding = BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_AABB, std430) readonly buffer BrixelizerBricksAABB_t + { + FfxUInt32 data[]; + } r_bctx_bricks_aabb; +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_VOXEL_MAP + layout (set = 0, binding = BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_VOXEL_MAP, std430) readonly buffer BrixelizerVoxelMap_t + { + FfxUInt32 data[]; + } r_bctx_bricks_voxel_map; +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_COUNTERS + layout (set = 0, binding = BRIXELIZER_BIND_SRV_CONTEXT_COUNTERS, std430) readonly buffer BrixelizerCounters_t + { + FfxUInt32 data[]; + } r_bctx_counters; +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_CLEAR_LIST + layout (set = 0, binding = BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_CLEAR_LIST, std430) readonly buffer BrixelizerBricksClearList_t + { + FfxUInt32 data[]; + } r_bctx_bricks_clear_list; +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_AABB_TREES + layout (set = 0, binding = BRIXELIZER_BIND_SRV_CASCADE_AABB_TREES, std430) readonly buffer BrixelizerCascadeAABBTrees_t + { + FfxUInt32 data[]; + } r_cascade_aabbtrees[24]; +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_BRICK_MAPS + layout (set = 0, binding = BRIXELIZER_BIND_SRV_CASCADE_BRICK_MAPS, std430) readonly buffer BrixelizerCascadeBrickMaps_t + { + FfxUInt32 data[]; + } r_cascade_brick_maps[24]; +#endif + +layout (set = 0, binding = 1000) uniform sampler g_clamp_linear_sampler; +layout (set = 0, binding = 1001) uniform sampler g_clamp_nearest_sampler; +layout (set = 0, binding = 1002) uniform sampler g_wrap_linear_sampler; +layout (set = 0, binding = 1003) uniform sampler g_wrap_nearest_sampler; + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxBrixelizerContextInfo GetContextInfo() +{ + return g_bx_context_info.data; +} + +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 cascadeID) +{ + return g_bx_context_info.data.cascades[cascadeID]; +} + +FfxBrixelizerCascadeInfo GetCascadeInfoNonUniform(FfxUInt32 cascadeID) +{ + return g_bx_context_info.data.cascades[nonuniformEXT(cascadeID)]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_SDF_ATLAS +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw) +{ + return textureLod(sampler3D(r_sdf_atlas, g_wrap_linear_sampler), uvw, 0.0f).r; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_COUNTERS +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx) +{ + return r_bctx_counters.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_CLEAR_LIST +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx) +{ + return r_bctx_bricks_clear_list.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_AABB_TREES +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return FfxFloat32x3(uintBitsToFloat(r_cascade_aabbtrees[cascadeID].data[elementIndex + 0]), + uintBitsToFloat(r_cascade_aabbtrees[cascadeID].data[elementIndex + 1]), + uintBitsToFloat(r_cascade_aabbtrees[cascadeID].data[elementIndex + 2])); +} + +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return r_cascade_aabbtrees[cascadeID].data[elementIndex]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_VOXEL_MAP +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIndex) +{ + return r_bctx_bricks_voxel_map.data[elementIndex]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_AABB +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIndex) +{ + return r_bctx_bricks_aabb.data[elementIndex]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_BRICK_MAPS +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return r_cascade_brick_maps[cascadeID].data[elementIndex]; +} + +FfxUInt32 LoadCascadeBrickMapArrayNonUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return r_cascade_brick_maps[nonuniformEXT(cascadeID)].data[elementIndex]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ENVIRONMENT_MAP +FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 world_space_reflected_direction) +{ + return textureLod(samplerCube(g_environment_map, g_wrap_linear_sampler), world_space_reflected_direction, 0.0f).rgb * GetEnvironmentMapIntensity(); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_RADIANCE_CACHE +FfxFloat32x3 SampleRadianceCacheSRV(FfxFloat32x3 uvw) +{ + return textureLod(sampler3D(g_bctx_radiance_cache, g_clamp_nearest_sampler), uvw, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RADIANCE_CACHE +FfxFloat32x3 LoadRadianceCache(FfxUInt32x3 coord) +{ + return imageLoad(g_rw_bctx_radiance_cache, FfxInt32x3(coord)).rgb; +} + +void StoreRadianceCache(FfxUInt32x3 coord, FfxFloat32x3 value) +{ + imageStore(g_rw_bctx_radiance_cache, FfxInt32x3(coord), FfxFloat32x4(value, 0.0f)); +} +#endif + +// GI Resources + +#if defined BRIXELIZER_GI_BIND_CB_SDFGI +FfxBrixelizerGIConstants GetGIConstants() +{ + return g_sdfgi_constants.data; +} + +FfxUInt32x2 GetBufferDimensions() +{ + return g_sdfgi_constants.data.buffer_dimensions; +} + +FfxFloat32x2 GetBufferDimensionsF32() +{ + return g_sdfgi_constants.data.buffer_dimensions_f32; +} + +FfxFloat32x2 GetProbeBufferDimensionsF32() +{ + return g_sdfgi_constants.data.probe_buffer_dimensions_f32; +} + +FfxUInt32 GetFrameIndex() +{ + return g_sdfgi_constants.data.frame_index; +} + +FfxUInt32x2 GetTileBufferDimensions() +{ + return g_sdfgi_constants.data.tile_buffer_dimensions; +} + +FfxFloat32x3 GetCameraPosition() +{ + return g_sdfgi_constants.data.camera_position; +} + +FfxFloat32x4x4 GetViewMatrix() +{ + return g_sdfgi_constants.data.view; +} + +FfxFloat32x4x4 GetViewProjectionMatrix() +{ + return g_sdfgi_constants.data.view_proj; +} + +FfxFloat32x4x4 GetInverseViewMatrix() +{ + return g_sdfgi_constants.data.inv_view; +} + +FfxFloat32x4x4 GetInverseProjectionMatrix() +{ + return g_sdfgi_constants.data.inv_proj; +} + +FfxFloat32x4x4 GetInverseViewProjectionMatrix() +{ + return g_sdfgi_constants.data.inv_view_proj; +} + +FfxFloat32x4x4 GetPreviousViewProjectionMatrix() +{ + return g_sdfgi_constants.data.prev_view_proj; +} + +FfxFloat32x4x4 GetPreviousInverseViewMatrix() +{ + return g_sdfgi_constants.data.prev_inv_view; +} + +FfxFloat32x4x4 GetPreviousInverseProjectionMatrix() +{ + return g_sdfgi_constants.data.prev_inv_proj; +} + +FfxFloat32 GetRoughnessThreshold() +{ + return g_sdfgi_constants.data.roughnessThreshold; +} + +FfxUInt32 GetRoughnessChannel() +{ + return g_sdfgi_constants.data.roughnessChannel; +} + +FfxFloat32 GetEnvironmentMapIntensity() +{ + return g_sdfgi_constants.data.environmentMapIntensity; +} + +FfxUInt32 GetTracingConstantsStartCascade() +{ + return g_sdfgi_constants.data.tracing_constants.start_cascade; +} + +FfxUInt32 GetTracingConstantsEndCascade() +{ + return g_sdfgi_constants.data.tracing_constants.end_cascade; +} + +FfxFloat32 GetTracingConstantsRayPushoff() +{ + return g_sdfgi_constants.data.tracing_constants.ray_pushoff; +} + +FfxFloat32 GetTracingConstantsTMin() +{ + return g_sdfgi_constants.data.tracing_constants.t_min; +} + +FfxFloat32 GetTracingConstantsTMax() +{ + return g_sdfgi_constants.data.tracing_constants.t_max; +} + +FfxFloat32 GetTracingConstantsSDFSolveEpsilon() +{ + return g_sdfgi_constants.data.tracing_constants.sdf_solve_eps; +} + +FfxFloat32 GetTracingConstantsSpecularRayPushoff() +{ + return g_sdfgi_constants.data.tracing_constants.specular_ray_pushoff; +} + +FfxFloat32 GetTracingConstantsSpecularSDFSolveEpsilon() +{ + return g_sdfgi_constants.data.tracing_constants.specular_sdf_solve_eps; +} +#endif + +#if defined BRIXELIZER_GI_BIND_CB_PASS_CONSTANTS +FfxUInt32 GetPassConstantsCascadeIndex() +{ + return g_pass_constants.data.cascade_idx; +} + +FfxFloat32 GetPassConstantsEnergyDecayK() +{ + return g_pass_constants.data.energy_decay_k; +} +#endif + +#if defined BRIXELIZER_GI_BIND_CB_SCALING_CONSTANTS +FfxBrixelizerGIScalingConstants GetScalingConstants() +{ + return g_scaling_constants.data; +} + +FfxUInt32 GetScalingRoughnessChannel() +{ + return g_scaling_constants.data.roughnessChannel; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPAWN_MASK +FfxUInt32 LoadTempSpawnMask(FfxUInt32x2 coord) +{ + return imageLoad(g_sdfgi_rw_temp_spawn_mask, FfxInt32x2(coord)).r; +} + +void StoreTempSpawnMask(FfxUInt32x2 coord, FfxUInt32 value) +{ + imageStore(g_sdfgi_rw_temp_spawn_mask, FfxInt32x2(coord), FfxUInt32x4(value, 0, 0, 0)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_RAND_SEED +FfxUInt32 LoadTempRandomSeed(FfxUInt32x2 coord) +{ + return imageLoad(g_sdfgi_rw_temp_rand_seed, FfxInt32x2(coord)).r; +} + +void StoreTempRandomSeed(FfxUInt32x2 coord, FfxUInt32 value) +{ + imageStore(g_sdfgi_rw_temp_rand_seed, FfxInt32x2(coord), FfxUInt32x4(value, 0, 0, 0)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_PRETRACE_TARGET +FfxUInt32x4 LoadTempSpecularPretraceTarget(FfxUInt32x2 coord) +{ + return imageLoad(g_sdfgi_rw_temp_specular_pretrace_target, FfxInt32x2(coord)); +} + +void StoreTempSpecularPretraceTarget(FfxUInt32x2 coord, FfxUInt32x4 value) +{ + imageStore(g_sdfgi_rw_temp_specular_pretrace_target, FfxInt32x2(coord), value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES_STAT +FfxFloat32x4 LoadStaticScreenProbesStat(FfxUInt32x2 coord) +{ + return imageLoad(g_sdfgi_rw_static_screen_probes_stat, FfxInt32x2(coord)); +} + +void StoreStaticScreenProbesStat(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + imageStore(g_sdfgi_rw_static_screen_probes_stat, FfxInt32x2(coord), value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SPECULAR_TARGET +FfxFloat32x4 SampleSpecularTargetSRV(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_sdfgi_r_specular_target, g_clamp_nearest_sampler), uv, 0.0f); +} + +FfxFloat32x4 LoadSpecularTargetSRV(FfxUInt32x2 coord) +{ + return texelFetch(g_sdfgi_r_specular_target, FfxInt32x2(coord), 0); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_SPECULAR_TARGET +FfxFloat32x4 LoadSpecularTarget(FfxUInt32x2 coord) +{ + return imageLoad(g_sdfgi_rw_specular_target, FfxInt32x2(coord)); +} + +void StoreSpecularTarget(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + imageStore(g_sdfgi_rw_specular_target, FfxInt32x2(coord), value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_INFO +FfxUInt32x4 LoadStaticProbeInfo(FfxUInt32 index) +{ + return g_sdfgi_rw_static_probe_info.data[index]; +} + +void StoreStaticProbeInfo(FfxUInt32 index, FfxUInt32x4 value) +{ + g_sdfgi_rw_static_probe_info.data[index] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_SH_BUFFER +FfxUInt32x2 LoadStaticProbeSHBuffer(FfxUInt32 index) +{ + return g_sdfgi_rw_static_probe_sh_buffer.data[index]; +} + +void StoreStaticProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value) +{ + g_sdfgi_rw_static_probe_sh_buffer.data[index] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_INFO +FfxUInt32x4 LoadTempProbeInfo(FfxUInt32 index) +{ + return g_sdfgi_rw_temp_probe_info.data[index]; +} + +void StoreTempProbeInfo(FfxUInt32 index, FfxUInt32x4 info) +{ + g_sdfgi_rw_temp_probe_info.data[index] = info; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_SH_BUFFER +FfxUInt32x2 LoadTempProbeSHBuffer(FfxUInt32 index) +{ + return g_sdfgi_rw_temp_probe_sh_buffer.data[index]; +} + +void StoreTempProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value) +{ + g_sdfgi_rw_temp_probe_sh_buffer.data[index] = value; + +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_PREV_LIT_OUTPUT +FfxFloat32x3 SamplePrevLitOutput(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_prev_lit_output, g_clamp_nearest_sampler), uv, FfxFloat32(0.0f)).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH +FfxFloat32 LoadDepth(FfxUInt32x2 pixel_coordinate) +{ + return texelFetch(g_depth, FfxInt32x2(pixel_coordinate), 0).x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ROUGHNESS +FfxFloat32 LoadRoughness(FfxUInt32x2 pixel_coordinate) +{ + FfxFloat32 roughness = texelFetch(g_roughness, FfxInt32x2(pixel_coordinate), 0)[GetRoughnessChannel()]; + + if (g_sdfgi_constants.data.isRoughnessPerceptual == 1) + roughness *= roughness; + + return roughness; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH +FfxFloat32 LoadPrevDepth(FfxUInt32x2 pixel_coordinate) +{ + return texelFetch(g_history_depth, FfxInt32x2(pixel_coordinate), 0).x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH +FfxFloat32 SampleDepth(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_depth, g_clamp_nearest_sampler), uv, 0.0f).x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH +FfxFloat32 SamplePrevDepth(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_history_depth, g_clamp_nearest_sampler), uv, 0.0f).x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL +FfxFloat32x3 LoadWorldNormal(FfxUInt32x2 pixel_coordinate) +{ + return normalize(texelFetch(g_normal, FfxInt32x2(pixel_coordinate), 0).xyz * g_sdfgi_constants.data.normalsUnpackMul + g_sdfgi_constants.data.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL +FfxFloat32x3 LoadPrevWorldNormal(FfxUInt32x2 pixel_coordinate) +{ + return normalize(texelFetch(g_history_normal, FfxInt32x2(pixel_coordinate), 0).xyz * g_sdfgi_constants.data.normalsUnpackMul + g_sdfgi_constants.data.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL +FfxFloat32x3 SampleWorldNormal(FfxFloat32x2 uv) +{ + return normalize(textureLod(sampler2D(g_normal, g_clamp_nearest_sampler), uv, 0.0f).xyz * g_sdfgi_constants.data.normalsUnpackMul + g_sdfgi_constants.data.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL +FfxFloat32x3 SamplePrevWorldNormal(FfxFloat32x2 uv) +{ + return normalize(textureLod(sampler2D(g_history_normal, g_clamp_nearest_sampler), uv, 0.0f).xyz * g_sdfgi_constants.data.normalsUnpackMul + g_sdfgi_constants.data.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS +FfxFloat32x2 SampleMotionVector(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_motion_vectors, g_clamp_nearest_sampler), uv, 0.0f).xy * g_sdfgi_constants.data.motionVectorScale; +} + +FfxFloat32x2 LoadMotionVector(FfxUInt32x2 pixel_coordinate) +{ + return texelFetch(g_motion_vectors, FfxInt32x2(pixel_coordinate), 0).xy * g_sdfgi_constants.data.motionVectorScale; +} +#endif // BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS + +#if defined BRIXELIZER_GI_BIND_SRV_DISOCCLUSION_MASK +FfxUInt32 LoadDisocclusionMask(FfxUInt32x2 pixel_coordinate) +{ + return FfxUInt32(texelFetch(g_r_disocclusion_mask, FfxInt32x2(pixel_coordinate), 0).x); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DISOCCLUSION_MASK +void StoreDisocclusionMask(FfxUInt32x2 pixel_coordinate, FfxFloat32 value) +{ + imageStore(g_rw_disocclusion_mask, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f, 0.0f, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS +FfxUInt32 LoadRaySwapIndirectArgs(FfxUInt32 elementIdx) +{ + return g_sdfgi_rw_ray_swap_indirect_args.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS +void StoreRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value) +{ + g_sdfgi_rw_ray_swap_indirect_args.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS +void IncrementRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + originalValue = atomicAdd(g_sdfgi_rw_ray_swap_indirect_args.data[elementIdx], value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH +FfxUInt32x2 LoadBricksDirectSH(FfxUInt32 elementIdx) +{ + return g_bctx_bricks_direct_sh.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH +void StoreBricksDirectSH(FfxUInt32 elementIdx, FfxUInt32x2 value) +{ + g_bctx_bricks_direct_sh.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH +FfxUInt32x2 LoadBricksSH(FfxUInt32 elementIdx) +{ + return g_bctx_bricks_sh.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH +void StoreBricksSH(FfxUInt32 elementIdx, FfxUInt32x2 value) +{ + g_bctx_bricks_sh.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE +FfxUInt32x4 LoadBricksSHState(FfxUInt32 elementIdx) +{ + return g_bctx_bricks_sh_state.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE +void StoreBricksSHState(FfxUInt32 elementIdx, FfxUInt32x4 value) +{ + g_bctx_bricks_sh_state.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP +FfxUInt32 LoadTempSpecularRaySwap(FfxUInt32 elementIdx) +{ + return g_sdfgi_rw_temp_specular_ray_swap.data[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP +void StoreTempSpecularRaySwap(FfxUInt32 elementIdx, FfxUInt32 value) +{ + g_sdfgi_rw_temp_specular_ray_swap.data[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_BLUE_NOISE +FfxFloat32x2 SampleBlueNoise(FfxUInt32x2 pixel, FfxUInt32 sample_index, FfxUInt32 dimension_offset) +{ + FfxInt32x2 coord = FfxInt32x2(pixel.x & 127u, pixel.y & 127u); + FfxFloat32x2 xi = texelFetch(g_blue_noise, FfxInt32x2(coord), 0).xy; + // xi.x = frac(xi.x + FfxFloat32((pixel.x >> 7) & 0xFFu) * GOLDEN_RATIO); + // xi.y = frac(xi.y + FfxFloat32((pixel.y >> 7) & 0xFFu) * GOLDEN_RATIO); + // return fmod(xi + (sample_index & 255) * GOLDEN_RATIO, 1.0f); + return xi; +} +#endif + +FfxFloat32x2 SampleBlueNoise(in FfxUInt32x2 pixel, in FfxUInt32 sample_index) +{ + return SampleBlueNoise(pixel, sample_index, 0); +} + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_SCREEN_PROBES +FfxFloat32x4 LoadStaticScreenProbesSRV(FfxUInt32x2 coord) +{ + return texelFetch(g_sdfgi_r_static_screen_probes, FfxInt32x2(coord), 0); +} + +FfxFloat32x4 SampleStaticScreenProbesSRV(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_sdfgi_r_static_screen_probes, g_clamp_nearest_sampler), uv, 0.0f); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES +FfxFloat32x4 LoadStaticScreenProbes(FfxUInt32x2 coord) +{ + return imageLoad(g_sdfgi_rw_static_screen_probes, FfxInt32x2(coord)); +} + +void StoreStaticScreenProbes(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + imageStore(g_sdfgi_rw_static_screen_probes, FfxInt32x2(coord), value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_GI_TARGET +FfxFloat32x4 SampleStaticGITargetSRV(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_sdfgi_r_static_gitarget, g_clamp_nearest_sampler), uv, 0.0f); +} + +FfxFloat32x4 LoadStaticGITargetSRV(FfxUInt32x2 coord) +{ + return texelFetch(g_sdfgi_r_static_gitarget, FfxInt32x2(coord), 0); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_GI_TARGET +void StoreStaticGITarget(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + imageStore(g_sdfgi_rw_static_gitarget, FfxInt32x2(coord), value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_TARGET +FfxFloat32x4 LoadDebugTraget(FfxUInt32x2 coord) +{ + return imageLoad(g_sdfgi_rw_debug_target, FfxInt32x2(coord)); +} + +void StoreDebugTarget(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + imageStore(g_sdfgi_rw_debug_target, FfxInt32x2(coord), value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_VISUALIZATION +void StoreDebugVisualization(FfxUInt32x2 pixel_coordinate, FfxFloat32x4 value) +{ + imageStore(g_rw_debug_visualization, FfxInt32x2(pixel_coordinate), value); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_DEPTH +FfxFloat32 LoadSourceDepth(FfxUInt32x2 coord) +{ + return texelFetch(g_src_depth, FfxInt32x2(coord), 0).r; +} + +FfxFloat32x4 GatherSourceDepth(FfxFloat32x2 uv) +{ + return textureGather(sampler2D(g_src_depth, g_clamp_nearest_sampler), uv, 0); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_DEPTH +FfxFloat32x4 GatherSourcePrevDepth(FfxFloat32x2 uv) +{ + return textureGather(sampler2D(g_src_history_depth, g_clamp_nearest_sampler), uv, 0); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_NORMAL +FfxFloat32x3 LoadSourceNormal(FfxUInt32x2 coord) +{ + return normalize(texelFetch(g_src_normal, FfxInt32x2(coord), 0).xyz * g_sdfgi_constants.data.normalsUnpackMul + g_sdfgi_constants.data.normalsUnpackAdd); +} + +FfxFloat32x3 SampleSourceNormal(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_src_normal, g_clamp_nearest_sampler), uv, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_NORMAL +FfxFloat32x3 SampleSourcePrevNormal(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_src_history_normal, g_clamp_nearest_sampler), uv, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_ROUGHNESS +FfxFloat32 SampleSourceRoughness(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_src_roughness, g_clamp_nearest_sampler), uv, 0.0f)[GetScalingRoughnessChannel()]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_MOTION_VECTORS +FfxFloat32x2 SampleSourceMotionVector(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_src_motion_vectors, g_clamp_nearest_sampler), uv, 0.0f).xy; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_PREV_LIT_OUTPUT +FfxFloat32x3 SampleSourcePrevLitOutput(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_src_prev_lit_output, g_clamp_nearest_sampler), uv, 0.0f).xyz; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_DIFFUSE_GI +FfxFloat32x3 SampleDownsampledDiffuseGI(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_downsampled_diffuse_gi, g_clamp_nearest_sampler), uv, 0.0f).xyz; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_SPECULAR_GI +FfxFloat32x3 SampleDownsampledSpecularGI(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_downsampled_specular_gi, g_clamp_nearest_sampler), uv, 0.0f).xyz; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_DEPTH +void StoreDownsampledDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value) +{ + imageStore(g_downsampled_depth, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f, 0.0f, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_DEPTH +void StoreDownsampledPrevDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value) +{ + imageStore(g_downsampled_history_depth, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f, 0.0f, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_NORMAL +void StoreDownsampledNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + imageStore(g_downsampled_normal, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_NORMAL +void StoreDownsampledPrevNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + imageStore(g_downsampled_history_normal, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_ROUGHNESS +void StoreDownsampledRoughness(FfxUInt32x2 pixel_coordinate, FfxFloat32 value) +{ + imageStore(g_downsampled_roughness, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f, 0.0f, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_MOTION_VECTORS +void StoreDownsampledMotionVector(FfxUInt32x2 pixel_coordinate, FfxFloat32x2 value) +{ + imageStore(g_downsampled_motion_vectors, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_PREV_LIT_OUTPUT +void StoreDownsampledPrevLitOutput(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + imageStore(g_downsampled_prev_lit_output, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 0.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_DIFFUSE_GI +void StoreUpsampledDiffuseGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + imageStore(g_upsampled_diffuse_gi, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 1.0f)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_SPECULAR_GI +void StoreUpsampledSpecularGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + imageStore(g_upsampled_specular_gi, FfxInt32x2(pixel_coordinate), FfxFloat32x4(value, 1.0f)); +} +#endif + +#endif // #if defined(FFX_GPU) + +#endif // FFX_BRIXELIZER_GI_CALLBACKS_GLSL_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_callbacks_hlsl.h new file mode 100644 index 00000000..9d05a14d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_callbacks_hlsl.h @@ -0,0 +1,1246 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_CALLBACKS_HLSL_H +#define FFX_BRIXELIZER_GI_CALLBACKS_HLSL_H + +#include "../ffx_core.h" + +#include "ffx_brixelizer_host_gpu_shared.h" +#include "ffx_brixelizergi_host_interface.h" + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +FfxBrixelizerGIConstants GetGIConstants(); +FfxUInt32x2 GetBufferDimensions(); +FfxFloat32x2 GetBufferDimensionsF32(); +FfxFloat32x2 GetProbeBufferDimensionsF32(); +FfxUInt32 GetFrameIndex(); +FfxUInt32x2 GetTileBufferDimensions(); +FfxFloat32x3 GetCameraPosition(); +FfxFloat32x4x4 GetViewMatrix(); +FfxFloat32x4x4 GetViewProjectionMatrix(); +FfxFloat32x4x4 GetInverseViewMatrix(); +FfxFloat32x4x4 GetInverseProjectionMatrix(); +FfxFloat32x4x4 GetInverseViewProjectionMatrix(); +FfxFloat32x4x4 GetPreviousViewProjectionMatrix(); +FfxFloat32x4x4 GetPreviousInverseViewMatrix(); +FfxFloat32x4x4 GetPreviousInverseProjectionMatrix(); +FfxFloat32 GetRoughnessThreshold(); +FfxUInt32 GetRoughnessChannel(); +FfxFloat32 GetEnvironmentMapIntensity(); +FfxUInt32 GetTracingConstantsStartCascade(); +FfxUInt32 GetTracingConstantsEndCascade(); +FfxFloat32 GetTracingConstantsRayPushoff(); +FfxFloat32 GetTracingConstantsTMin(); +FfxFloat32 GetTracingConstantsTMax(); +FfxFloat32 GetTracingConstantsSDFSolveEpsilon(); +FfxFloat32 GetTracingConstantsSpecularRayPushoff(); +FfxFloat32 GetTracingConstantsSpecularSDFSolveEpsilon(); +FfxUInt32 GetPassConstantsCascadeIndex(); +FfxFloat32 GetPassConstantsEnergyDecayK(); +FfxBrixelizerGIScalingConstants GetScalingConstants(); +FfxUInt32 GetScalingRoughnessChannel(); +FfxUInt32 LoadTempSpawnMask(FfxUInt32x2 coord); +void StoreTempSpawnMask(FfxUInt32x2 coord, FfxUInt32 value); +FfxUInt32 LoadTempRandomSeed(FfxUInt32x2 coord); +void StoreTempRandomSeed(FfxUInt32x2 coord, FfxUInt32 value); +FfxUInt32x4 LoadTempSpecularPretraceTarget(FfxUInt32x2 coord); +void StoreTempSpecularPretraceTarget(FfxUInt32x2 coord, FfxUInt32x4 value); +FfxFloat32x4 LoadStaticScreenProbesStat(FfxUInt32x2 coord); +void StoreStaticScreenProbesStat(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x4 SampleSpecularTargetSRV(FfxFloat32x2 uv); +FfxFloat32x4 LoadSpecularTargetSRV(FfxUInt32x2 coord); +FfxFloat32x4 LoadSpecularTarget(FfxUInt32x2 coord); +void StoreSpecularTarget(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxUInt32x4 LoadStaticProbeInfo(FfxUInt32 index); +void StoreStaticProbeInfo(FfxUInt32 index, FfxUInt32x4 value); +FfxUInt32x2 LoadStaticProbeSHBuffer(FfxUInt32 index); +void StoreStaticProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value); +FfxUInt32x4 LoadTempProbeInfo(FfxUInt32 index); +void StoreTempProbeInfo(FfxUInt32 index, FfxUInt32x4 info); +FfxUInt32x2 LoadTempProbeSHBuffer(FfxUInt32 index); +void StoreTempProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value); +FfxFloat32x3 SamplePrevLitOutput(FfxFloat32x2 uv); +FfxFloat32 LoadDepth(FfxUInt32x2 pixel_coordinate); +FfxFloat32 LoadRoughness(FfxUInt32x2 pixel_coordinate); +FfxFloat32 LoadPrevDepth(FfxUInt32x2 pixel_coordinate); +FfxFloat32 SampleDepth(FfxFloat32x2 uv); +FfxFloat32 SamplePrevDepth(FfxFloat32x2 uv); +FfxFloat32x3 LoadWorldNormal(FfxUInt32x2 pixel_coordinate); +FfxFloat32x3 LoadPrevWorldNormal(FfxUInt32x2 pixel_coordinate); +FfxFloat32x3 SampleWorldNormal(FfxFloat32x2 uv); +FfxFloat32x3 SamplePrevWorldNormal(FfxFloat32x2 uv); +FfxFloat32x2 SampleMotionVector(FfxFloat32x2 uv); +FfxFloat32x2 LoadMotionVector(FfxUInt32x2 pixel_coordinate); +FfxUInt32 LoadDisocclusionMask(FfxUInt32x2 pixel_coordinate); +void StoreDisocclusionMask(FfxUInt32x2 pixel_coordinate, float value); +FfxUInt32 LoadRaySwapIndirectArgs(FfxUInt32 elementIdx); +void StoreRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value); +void IncrementRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue); +FfxUInt32x2 LoadBricksDirectSH(FfxUInt32 elementIdx); +void StoreBricksDirectSH(FfxUInt32 elementIdx, FfxUInt32x2 value); +FfxUInt32x2 LoadBricksSH(FfxUInt32 elementIdx); +void StoreBricksSH(FfxUInt32 elementIdx, FfxUInt32x2 value); +FfxUInt32x4 LoadBricksSHState(FfxUInt32 elementIdx); +void StoreBricksSHState(FfxUInt32 elementIdx, FfxUInt32x4 value); +FfxUInt32 LoadTempSpecularRaySwap(FfxUInt32 elementIdx); +void StoreTempSpecularRaySwap(FfxUInt32 elementIdx, FfxUInt32 value); +FfxFloat32x2 SampleBlueNoise(FfxUInt32x2 pixel, FfxUInt32 sample_index, FfxUInt32 dimension_offset); +FfxFloat32x2 SampleBlueNoise(in FfxUInt32x2 pixel, in FfxUInt32 sample_index); +FfxFloat32x4 LoadStaticScreenProbesSRV(FfxUInt32x2 coord); +FfxFloat32x4 SampleStaticScreenProbesSRV(FfxFloat32x2 uv); +FfxFloat32x4 LoadStaticScreenProbes(FfxUInt32x2 coord); +void StoreStaticScreenProbes(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x4 SampleStaticGITargetSRV(FfxFloat32x2 uv); +FfxFloat32x4 LoadStaticGITargetSRV(FfxUInt32x2 coord); +void StoreStaticGITarget(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x4 LoadDebugTraget(FfxUInt32x2 coord); +void StoreDebugTarget(FfxUInt32x2 coord, FfxFloat32x4 value); +FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 world_space_reflected_direction); +FfxFloat32x3 SampleRadianceCacheSRV(FfxFloat32x3 uvw); +FfxFloat32x3 LoadRadianceCache(FfxUInt32x3 coord); +void StoreRadianceCache(FfxUInt32x3 coord, FfxFloat32x3 value); +void StoreDebugVisualization(FfxUInt32x2 pixel_coordinate, FfxFloat32x4 value); + +FfxFloat32 LoadSourceDepth(FfxUInt32x2 coord); +FfxFloat32x3 LoadSourceNormal(FfxUInt32x2 coord); +FfxFloat32x4 GatherSourceDepth(FfxFloat32x2 uv); +FfxFloat32x4 GatherSourcePrevDepth(FfxFloat32x2 uv); +FfxFloat32x3 SampleSourceNormal(FfxFloat32x2 uv); +FfxFloat32x3 SampleSourcePrevNormal(FfxFloat32x2 uv); +FfxFloat32 SampleSourceRoughness(FfxFloat32x2 uv); +FfxFloat32x2 SampleSourceMotionVector(FfxFloat32x2 uv); +FfxFloat32x3 SampleSourcePrevLitOutput(FfxFloat32x2 uv); +FfxFloat32x3 SampleDownsampledDiffuseGI(FfxFloat32x2 uv); +FfxFloat32x3 SampleDownsampledSpecularGI(FfxFloat32x2 uv); + +void StoreDownsampledDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value); +void StoreDownsampledPrevDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value); +void StoreDownsampledNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreDownsampledPrevNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreDownsampledRoughness(FfxUInt32x2 pixel_coordinate, FfxFloat32 value); +void StoreDownsampledMotionVector(FfxUInt32x2 pixel_coordinate, FfxFloat32x2 value); +void StoreDownsampledPrevLitOutput(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreUpsampledDiffuseGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); +void StoreUpsampledSpecularGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value); + +FfxBrixelizerContextInfo GetContextInfo(); +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 cascadeID); +FfxBrixelizerCascadeInfo GetCascadeInfoNonUniform(FfxUInt32 cascadeID); +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw); +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx); +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx); +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIndex); +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIndex); +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex); +FfxUInt32 LoadCascadeBrickMapArrayNonUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex); + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define DECLARE_SAMPLER_REGISTER(regIndex) s##regIndex +#define FFX_BRIXELIZER_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_BRIXELIZER_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_BRIXELIZER_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) +#define FFX_BRIXELIZER_DECLARE_SAMPLER(regIndex) register(DECLARE_SAMPLER_REGISTER(regIndex)) + +// CBVs + +#if defined BRIXELIZER_GI_BIND_CB_SDFGI + ConstantBuffer g_sdfgi_constants : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_GI_BIND_CB_SDFGI); +#endif + +#if defined BRIXELIZER_GI_BIND_CB_PASS_CONSTANTS + ConstantBuffer g_pass_constants : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_GI_BIND_CB_PASS_CONSTANTS); +#endif + +#if defined BRIXELIZER_GI_BIND_CB_SCALING_CONSTANTS + ConstantBuffer g_scaling_constants : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_GI_BIND_CB_SCALING_CONSTANTS); +#endif + +// SRVs + +#if defined BRIXELIZER_GI_BIND_SRV_DISOCCLUSION_MASK + Texture2D g_r_disocclusion_mask : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_DISOCCLUSION_MASK); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_GI_TARGET + Texture2D g_sdfgi_r_static_gitarget : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_STATIC_GI_TARGET); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_SCREEN_PROBES + Texture2D g_sdfgi_r_static_screen_probes : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_STATIC_SCREEN_PROBES); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SPECULAR_TARGET + Texture2D g_sdfgi_r_specular_target : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SPECULAR_TARGET); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_RADIANCE_CACHE + Texture3D g_bctx_radiance_cache : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_RADIANCE_CACHE); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_PREV_LIT_OUTPUT + Texture2D g_prev_lit_output : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_PREV_LIT_OUTPUT); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH + Texture2D g_depth : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH + Texture2D g_history_depth : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL + Texture2D g_normal : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL + Texture2D g_history_normal : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ROUGHNESS + Texture2D g_roughness : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_ROUGHNESS); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS + Texture2D g_motion_vectors : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ENVIRONMENT_MAP + TextureCube g_environment_map : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_ENVIRONMENT_MAP); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_BLUE_NOISE + Texture2D g_blue_noise : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_INPUT_BLUE_NOISE); +#endif + +// Downsampled SRVs + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_PREV_LIT_OUTPUT + Texture2D g_src_prev_lit_output : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SOURCE_PREV_LIT_OUTPUT); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_DEPTH + Texture2D g_src_depth : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SOURCE_DEPTH); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_DEPTH + Texture2D g_src_history_depth : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_DEPTH); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_NORMAL + Texture2D g_src_normal : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SOURCE_NORMAL); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_NORMAL + Texture2D g_src_history_normal : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_NORMAL); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_ROUGHNESS + Texture2D g_src_roughness : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SOURCE_ROUGHNESS); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_MOTION_VECTORS + Texture2D g_src_motion_vectors : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_SOURCE_MOTION_VECTORS); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_DIFFUSE_GI + Texture2D g_downsampled_diffuse_gi : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_DIFFUSE_GI); +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_SPECULAR_GI + Texture2D g_downsampled_specular_gi : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_SPECULAR_GI); +#endif + + +// UAVs + +#if defined BRIXELIZER_GI_BIND_UAV_DISOCCLUSION_MASK + RWTexture2D g_rw_disocclusion_mask : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DISOCCLUSION_MASK); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES + RWTexture2D g_sdfgi_rw_static_screen_probes : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PUSH_OFF_MAP + RWTexture2D g_sdfgi_rw_static_pushoff_map : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_STATIC_PUSH_OFF_MAP); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_GI_TARGET + RWTexture2D g_sdfgi_rw_static_gitarget : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_STATIC_GI_TARGET); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_TARGET + RWTexture2D g_sdfgi_rw_debug_target : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DEBUG_TARGET); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RADIANCE_CACHE + RWTexture3D g_rw_bctx_radiance_cache : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_RADIANCE_CACHE); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPAWN_MASK + RWTexture2D g_sdfgi_rw_temp_spawn_mask : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_TEMP_SPAWN_MASK); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_RAND_SEED + RWTexture2D g_sdfgi_rw_temp_rand_seed : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_TEMP_RAND_SEED); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_PRETRACE_TARGET + RWTexture2D g_sdfgi_rw_temp_specular_pretrace_target : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_PRETRACE_TARGET); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_BLUR_MASK + RWTexture2D g_sdfgi_rw_temp_blur_mask : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_TEMP_BLUR_MASK); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES_STAT + RWTexture2D g_sdfgi_rw_static_screen_probes_stat : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES_STAT); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_SPECULAR_TARGET + RWTexture2D g_sdfgi_rw_specular_target : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_SPECULAR_TARGET); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_SCREEN_PROBES_OUTPUT_COPY + RWTexture2D g_rw_screen_probes_output_copy : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_SCREEN_PROBES_OUTPUT_COPY); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_VISUALIZATION + RWTexture2D g_rw_debug_visualization : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DEBUG_VISUALIZATION); +#endif + +// Downsampled resources + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_PREV_LIT_OUTPUT + RWTexture2D g_downsampled_prev_lit_output : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_PREV_LIT_OUTPUT); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_DEPTH + RWTexture2D g_downsampled_depth : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_DEPTH); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_DEPTH + RWTexture2D g_downsampled_history_depth : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_DEPTH); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_NORMAL + RWTexture2D g_downsampled_normal : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_NORMAL); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_NORMAL + RWTexture2D g_downsampled_history_normal : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_NORMAL); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_ROUGHNESS + RWTexture2D g_downsampled_roughness : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_ROUGHNESS); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_MOTION_VECTORS + RWTexture2D g_downsampled_motion_vectors : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_MOTION_VECTORS); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_DIFFUSE_GI + RWTexture2D g_upsampled_diffuse_gi : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_UPSAMPLED_DIFFUSE_GI); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_SPECULAR_GI + RWTexture2D g_upsampled_specular_gi : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_UPSAMPLED_SPECULAR_GI); +#endif + +// UAVs + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_INFO + RWStructuredBuffer g_sdfgi_rw_static_probe_info : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_INFO); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_SH_BUFFER + RWStructuredBuffer g_sdfgi_rw_static_probe_sh_buffer : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_SH_BUFFER); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_INFO + RWStructuredBuffer g_sdfgi_rw_temp_probe_info : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_INFO); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_SH_BUFFER + RWStructuredBuffer g_sdfgi_rw_temp_probe_sh_buffer : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_SH_BUFFER); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS + RWStructuredBuffer g_sdfgi_rw_ray_swap_indirect_args : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH + RWStructuredBuffer g_bctx_bricks_direct_sh : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH + RWStructuredBuffer g_bctx_bricks_sh : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_BRICKS_SH); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE + RWStructuredBuffer g_bctx_bricks_sh_state : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE); +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP + RWStructuredBuffer g_sdfgi_rw_temp_specular_ray_swap : FFX_BRIXELIZER_DECLARE_UAV(BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP); +#endif + +// Brixelizer Resources + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO + ConstantBuffer g_bx_context_info : FFX_BRIXELIZER_DECLARE_CB(BRIXELIZER_BIND_CB_CONTEXT_INFO); +#endif + +#if defined BRIXELIZER_BIND_SRV_SDF_ATLAS + Texture3D r_sdf_atlas : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_SDF_ATLAS); +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_AABB + StructuredBuffer r_bctx_bricks_aabb : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_AABB); +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_VOXEL_MAP + StructuredBuffer r_bctx_bricks_voxel_map : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_VOXEL_MAP); +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_COUNTERS + StructuredBuffer r_bctx_counters : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_CONTEXT_COUNTERS); +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_CLEAR_LIST + StructuredBuffer r_bctx_bricks_clear_list : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_CLEAR_LIST); +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_AABB_TREES + StructuredBuffer r_cascade_aabbtrees[24] : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_CASCADE_AABB_TREES); +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_BRICK_MAPS + StructuredBuffer r_cascade_brick_maps[24] : FFX_BRIXELIZER_DECLARE_SRV(BRIXELIZER_BIND_SRV_CASCADE_BRICK_MAPS); +#endif + +#if defined BRIXELIZER_BIND_SAMPLER_CLAMP_LINEAR_SAMPLER + SamplerState g_clamp_linear_sampler : FFX_BRIXELIZER_DECLARE_SAMPLER(BRIXELIZER_BIND_SAMPLER_CLAMP_LINEAR_SAMPLER); +#endif + +#if defined BRIXELIZER_BIND_SAMPLER_CLAMP_NEAREST_SAMPLER + SamplerState g_clamp_nearest_sampler : FFX_BRIXELIZER_DECLARE_SAMPLER(BRIXELIZER_BIND_SAMPLER_CLAMP_NEAREST_SAMPLER); +#endif + +#if defined BRIXELIZER_BIND_SAMPLER_WRAP_LINEAR_SAMPLER + SamplerState g_wrap_linear_sampler : FFX_BRIXELIZER_DECLARE_SAMPLER(BRIXELIZER_BIND_SAMPLER_WRAP_LINEAR_SAMPLER); +#endif + +#if defined BRIXELIZER_BIND_SAMPLER_WRAP_NEAREST_SAMPLER + SamplerState g_wrap_nearest_sampler : FFX_BRIXELIZER_DECLARE_SAMPLER(BRIXELIZER_BIND_SAMPLER_WRAP_NEAREST_SAMPLER); +#endif + +#if defined BRIXELIZER_BIND_CB_CONTEXT_INFO +FfxBrixelizerContextInfo GetContextInfo() +{ + return g_bx_context_info; +} + +FfxBrixelizerCascadeInfo GetCascadeInfo(FfxUInt32 cascadeID) +{ + return g_bx_context_info.cascades[cascadeID]; +} + +FfxBrixelizerCascadeInfo GetCascadeInfoNonUniform(FfxUInt32 cascadeID) +{ + return g_bx_context_info.cascades[NonUniformResourceIndex(cascadeID)]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_SDF_ATLAS +FfxFloat32 SampleSDFAtlas(FfxFloat32x3 uvw) +{ + return r_sdf_atlas.SampleLevel(g_wrap_linear_sampler, uvw, 0.0f); +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_COUNTERS +FfxUInt32 LoadContextCounter(FfxUInt32 elementIdx) +{ + return r_bctx_counters[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_CLEAR_LIST +FfxUInt32 LoadBricksClearList(FfxUInt32 elementIdx) +{ + return r_bctx_bricks_clear_list[elementIdx]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_AABB_TREES +FfxFloat32x3 LoadCascadeAABBTreesFloat3(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return FfxFloat32x3(asfloat(r_cascade_aabbtrees[cascadeID][elementIndex + 0]), + asfloat(r_cascade_aabbtrees[cascadeID][elementIndex + 1]), + asfloat(r_cascade_aabbtrees[cascadeID][elementIndex + 2])); +} + +FfxUInt32 LoadCascadeAABBTreesUInt(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return r_cascade_aabbtrees[cascadeID][elementIndex]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_VOXEL_MAP +FfxUInt32 LoadBricksVoxelMap(FfxUInt32 elementIndex) +{ + return r_bctx_bricks_voxel_map[elementIndex]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CONTEXT_BRICKS_AABB +FfxUInt32 LoadBricksAABB(FfxUInt32 elementIndex) +{ + return r_bctx_bricks_aabb[elementIndex]; +} +#endif + +#if defined BRIXELIZER_BIND_SRV_CASCADE_BRICK_MAPS +FfxUInt32 LoadCascadeBrickMapArrayUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return r_cascade_brick_maps[cascadeID][elementIndex]; +} + +FfxUInt32 LoadCascadeBrickMapArrayNonUniform(FfxUInt32 cascadeID, FfxUInt32 elementIndex) +{ + return r_cascade_brick_maps[NonUniformResourceIndex(cascadeID)][elementIndex]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ENVIRONMENT_MAP +FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 world_space_reflected_direction) +{ + return g_environment_map.SampleLevel(g_wrap_linear_sampler, world_space_reflected_direction, 0.0).xyz * GetEnvironmentMapIntensity(); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_RADIANCE_CACHE +FfxFloat32x3 SampleRadianceCacheSRV(FfxFloat32x3 uvw) +{ + return g_bctx_radiance_cache.SampleLevel(g_clamp_nearest_sampler, uvw, 0.0f); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RADIANCE_CACHE +FfxFloat32x3 LoadRadianceCache(FfxUInt32x3 coord) +{ + return g_rw_bctx_radiance_cache[coord]; +} + +void StoreRadianceCache(FfxUInt32x3 coord, FfxFloat32x3 value) +{ + g_rw_bctx_radiance_cache[coord] = value; +} +#endif + +// GI Resources + +#if defined BRIXELIZER_GI_BIND_CB_SDFGI +FfxBrixelizerGIConstants GetGIConstants() +{ + return g_sdfgi_constants; +} + +FfxUInt32x2 GetBufferDimensions() +{ + return g_sdfgi_constants.buffer_dimensions; +} + +FfxFloat32x2 GetBufferDimensionsF32() +{ + return g_sdfgi_constants.buffer_dimensions_f32; +} + +FfxFloat32x2 GetProbeBufferDimensionsF32() +{ + return g_sdfgi_constants.probe_buffer_dimensions_f32; +} + +FfxUInt32 GetFrameIndex() +{ + return g_sdfgi_constants.frame_index; +} + +FfxUInt32x2 GetTileBufferDimensions() +{ + return g_sdfgi_constants.tile_buffer_dimensions; +} + +FfxFloat32x3 GetCameraPosition() +{ + return g_sdfgi_constants.camera_position; +} + +FfxFloat32x4x4 GetViewMatrix() +{ + return g_sdfgi_constants.view; +} + +FfxFloat32x4x4 GetViewProjectionMatrix() +{ + return g_sdfgi_constants.view_proj; +} + +FfxFloat32x4x4 GetInverseViewMatrix() +{ + return g_sdfgi_constants.inv_view; +} + +FfxFloat32x4x4 GetInverseProjectionMatrix() +{ + return g_sdfgi_constants.inv_proj; +} + +FfxFloat32x4x4 GetInverseViewProjectionMatrix() +{ + return g_sdfgi_constants.inv_view_proj; +} + +FfxFloat32x4x4 GetPreviousViewProjectionMatrix() +{ + return g_sdfgi_constants.prev_view_proj; +} + +FfxFloat32x4x4 GetPreviousInverseViewMatrix() +{ + return g_sdfgi_constants.prev_inv_view; +} + +FfxFloat32x4x4 GetPreviousInverseProjectionMatrix() +{ + return g_sdfgi_constants.prev_inv_proj; +} + +FfxFloat32 GetRoughnessThreshold() +{ + return g_sdfgi_constants.roughnessThreshold; +} + +FfxUInt32 GetRoughnessChannel() +{ + return g_sdfgi_constants.roughnessChannel; +} + +FfxFloat32 GetEnvironmentMapIntensity() +{ + return g_sdfgi_constants.environmentMapIntensity; +} + +FfxUInt32 GetTracingConstantsStartCascade() +{ + return g_sdfgi_constants.tracing_constants.start_cascade; +} + +FfxUInt32 GetTracingConstantsEndCascade() +{ + return g_sdfgi_constants.tracing_constants.end_cascade; +} + +FfxFloat32 GetTracingConstantsRayPushoff() +{ + return g_sdfgi_constants.tracing_constants.ray_pushoff; +} + +FfxFloat32 GetTracingConstantsTMin() +{ + return g_sdfgi_constants.tracing_constants.t_min; +} + +FfxFloat32 GetTracingConstantsTMax() +{ + return g_sdfgi_constants.tracing_constants.t_max; +} + +FfxFloat32 GetTracingConstantsSDFSolveEpsilon() +{ + return g_sdfgi_constants.tracing_constants.sdf_solve_eps; +} + +FfxFloat32 GetTracingConstantsSpecularRayPushoff() +{ + return g_sdfgi_constants.tracing_constants.specular_ray_pushoff; +} + +FfxFloat32 GetTracingConstantsSpecularSDFSolveEpsilon() +{ + return g_sdfgi_constants.tracing_constants.specular_sdf_solve_eps; +} +#endif + +#if defined BRIXELIZER_GI_BIND_CB_PASS_CONSTANTS +FfxUInt32 GetPassConstantsCascadeIndex() +{ + return g_pass_constants.cascade_idx; +} + +FfxFloat32 GetPassConstantsEnergyDecayK() +{ + return g_pass_constants.energy_decay_k; +} +#endif + +#if defined BRIXELIZER_GI_BIND_CB_SCALING_CONSTANTS +FfxBrixelizerGIScalingConstants GetScalingConstants() +{ + return g_scaling_constants; +} + +FfxUInt32 GetScalingRoughnessChannel() +{ + return g_scaling_constants.roughnessChannel; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPAWN_MASK +FfxUInt32 LoadTempSpawnMask(FfxUInt32x2 coord) +{ + return g_sdfgi_rw_temp_spawn_mask[coord]; +} + +void StoreTempSpawnMask(FfxUInt32x2 coord, FfxUInt32 value) +{ + g_sdfgi_rw_temp_spawn_mask[coord] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_RAND_SEED +FfxUInt32 LoadTempRandomSeed(FfxUInt32x2 coord) +{ + return g_sdfgi_rw_temp_rand_seed[coord]; +} + +void StoreTempRandomSeed(FfxUInt32x2 coord, FfxUInt32 value) +{ + g_sdfgi_rw_temp_rand_seed[coord] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_PRETRACE_TARGET +FfxUInt32x4 LoadTempSpecularPretraceTarget(FfxUInt32x2 coord) +{ + return g_sdfgi_rw_temp_specular_pretrace_target[coord]; +} + +void StoreTempSpecularPretraceTarget(FfxUInt32x2 coord, FfxUInt32x4 value) +{ + g_sdfgi_rw_temp_specular_pretrace_target[coord] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES_STAT +FfxFloat32x4 LoadStaticScreenProbesStat(FfxUInt32x2 coord) +{ + return g_sdfgi_rw_static_screen_probes_stat[coord]; +} + +void StoreStaticScreenProbesStat(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + g_sdfgi_rw_static_screen_probes_stat[coord] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SPECULAR_TARGET +FfxFloat32x4 SampleSpecularTargetSRV(FfxFloat32x2 uv) +{ + return g_sdfgi_r_specular_target.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f); +} + +FfxFloat32x4 LoadSpecularTargetSRV(FfxUInt32x2 coord) +{ + return g_sdfgi_r_specular_target[coord]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_SPECULAR_TARGET +FfxFloat32x4 LoadSpecularTarget(FfxUInt32x2 coord) +{ + return g_sdfgi_rw_specular_target[coord]; +} + +void StoreSpecularTarget(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + g_sdfgi_rw_specular_target[coord] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_INFO +FfxUInt32x4 LoadStaticProbeInfo(FfxUInt32 index) +{ + return g_sdfgi_rw_static_probe_info[index]; +} + +void StoreStaticProbeInfo(FfxUInt32 index, FfxUInt32x4 value) +{ + g_sdfgi_rw_static_probe_info[index] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_PROBE_SH_BUFFER +FfxUInt32x2 LoadStaticProbeSHBuffer(FfxUInt32 index) +{ + return g_sdfgi_rw_static_probe_sh_buffer[index]; +} + +void StoreStaticProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value) +{ + g_sdfgi_rw_static_probe_sh_buffer[index] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_INFO +FfxUInt32x4 LoadTempProbeInfo(FfxUInt32 index) +{ + return g_sdfgi_rw_temp_probe_info[index]; +} + +void StoreTempProbeInfo(FfxUInt32 index, FfxUInt32x4 info) +{ + g_sdfgi_rw_temp_probe_info[index] = info; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_PROBE_SH_BUFFER +FfxUInt32x2 LoadTempProbeSHBuffer(FfxUInt32 index) +{ + return g_sdfgi_rw_temp_probe_sh_buffer[index]; +} + +void StoreTempProbeSHBuffer(FfxUInt32 index, FfxUInt32x2 value) +{ + g_sdfgi_rw_temp_probe_sh_buffer[index] = value; + +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_PREV_LIT_OUTPUT +FfxFloat32x3 SamplePrevLitOutput(FfxFloat32x2 uv) +{ + return g_prev_lit_output.SampleLevel(g_clamp_nearest_sampler, uv, 0.0).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH +FfxFloat32 LoadDepth(FfxUInt32x2 pixel_coordinate) +{ + return g_depth[pixel_coordinate].x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_ROUGHNESS +FfxFloat32 LoadRoughness(FfxUInt32x2 pixel_coordinate) +{ + FfxFloat32 roughness = g_roughness[pixel_coordinate][GetRoughnessChannel()]; + + if (g_sdfgi_constants.isRoughnessPerceptual == 1) + roughness *= roughness; + + return roughness; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH +FfxFloat32 LoadPrevDepth(FfxUInt32x2 pixel_coordinate) +{ + return g_history_depth[pixel_coordinate].x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_DEPTH +FfxFloat32 SampleDepth(FfxFloat32x2 uv) +{ + return g_depth.SampleLevel(g_clamp_nearest_sampler, uv, 0.0).x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_DEPTH +FfxFloat32 SamplePrevDepth(FfxFloat32x2 uv) +{ + return g_history_depth.SampleLevel(g_clamp_nearest_sampler, uv, 0.0).x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL +FfxFloat32x3 LoadWorldNormal(FfxUInt32x2 pixel_coordinate) +{ + return normalize(g_normal.Load(FfxInt32x3(pixel_coordinate, 0)).xyz * g_sdfgi_constants.normalsUnpackMul + g_sdfgi_constants.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL +FfxFloat32x3 LoadPrevWorldNormal(FfxUInt32x2 pixel_coordinate) +{ + return normalize(g_history_normal.Load(FfxInt32x3(pixel_coordinate, 0)).xyz * g_sdfgi_constants.normalsUnpackMul + g_sdfgi_constants.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_NORMAL +FfxFloat32x3 SampleWorldNormal(FfxFloat32x2 uv) +{ + return normalize(g_normal.SampleLevel(g_clamp_nearest_sampler, uv, 0.0).xyz * g_sdfgi_constants.normalsUnpackMul + g_sdfgi_constants.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_HISTORY_NORMAL +FfxFloat32x3 SamplePrevWorldNormal(FfxFloat32x2 uv) +{ + return normalize(g_history_normal.SampleLevel(g_clamp_nearest_sampler, uv, 0.0).xyz * g_sdfgi_constants.normalsUnpackMul + g_sdfgi_constants.normalsUnpackAdd); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS +FfxFloat32x2 SampleMotionVector(FfxFloat32x2 uv) +{ + return g_motion_vectors.SampleLevel(g_clamp_nearest_sampler, uv, 0.0).xy * g_sdfgi_constants.motionVectorScale; +} + +FfxFloat32x2 LoadMotionVector(FfxUInt32x2 pixel_coordinate) +{ + return g_motion_vectors[pixel_coordinate].xy * g_sdfgi_constants.motionVectorScale; +} +#endif // BRIXELIZER_GI_BIND_SRV_INPUT_MOTION_VECTORS + +#if defined BRIXELIZER_GI_BIND_SRV_DISOCCLUSION_MASK +FfxUInt32 LoadDisocclusionMask(FfxUInt32x2 pixel_coordinate) +{ + return g_r_disocclusion_mask[pixel_coordinate].x; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DISOCCLUSION_MASK +void StoreDisocclusionMask(FfxUInt32x2 pixel_coordinate, float value) +{ + g_rw_disocclusion_mask[pixel_coordinate] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS +FfxUInt32 LoadRaySwapIndirectArgs(FfxUInt32 elementIdx) +{ + return g_sdfgi_rw_ray_swap_indirect_args[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS +void StoreRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value) +{ + g_sdfgi_rw_ray_swap_indirect_args[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_RAY_SWAP_INDIRECT_ARGS +void IncrementRaySwapIndirectArgs(FfxUInt32 elementIdx, FfxUInt32 value, inout FfxUInt32 originalValue) +{ + InterlockedAdd(g_sdfgi_rw_ray_swap_indirect_args[elementIdx], value, originalValue); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH +FfxUInt32x2 LoadBricksDirectSH(FfxUInt32 elementIdx) +{ + return g_bctx_bricks_direct_sh[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_DIRECT_SH +void StoreBricksDirectSH(FfxUInt32 elementIdx, FfxUInt32x2 value) +{ + g_bctx_bricks_direct_sh[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH +FfxUInt32x2 LoadBricksSH(FfxUInt32 elementIdx) +{ + return g_bctx_bricks_sh[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH +void StoreBricksSH(FfxUInt32 elementIdx, FfxUInt32x2 value) +{ + g_bctx_bricks_sh[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE +FfxUInt32x4 LoadBricksSHState(FfxUInt32 elementIdx) +{ + return g_bctx_bricks_sh_state[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_BRICKS_SH_STATE +void StoreBricksSHState(FfxUInt32 elementIdx, FfxUInt32x4 value) +{ + g_bctx_bricks_sh_state[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP +FfxUInt32 LoadTempSpecularRaySwap(FfxUInt32 elementIdx) +{ + return g_sdfgi_rw_temp_specular_ray_swap[elementIdx]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_TEMP_SPECULAR_RAY_SWAP +void StoreTempSpecularRaySwap(FfxUInt32 elementIdx, FfxUInt32 value) +{ + g_sdfgi_rw_temp_specular_ray_swap[elementIdx] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_INPUT_BLUE_NOISE +FfxFloat32x2 SampleBlueNoise(FfxUInt32x2 pixel, FfxUInt32 sample_index, FfxUInt32 dimension_offset) +{ + FfxInt32x2 coord = FfxInt32x2(pixel.x & 127u, pixel.y & 127u); + FfxFloat32x2 xi = g_blue_noise[coord].xy; + // xi.x = frac(xi.x + FfxFloat32((pixel.x >> 7) & 0xFFu) * GOLDEN_RATIO); + // xi.y = frac(xi.y + FfxFloat32((pixel.y >> 7) & 0xFFu) * GOLDEN_RATIO); + // return fmod(xi + (sample_index & 255) * GOLDEN_RATIO, 1.0f); + return xi; +} +#endif + +FfxFloat32x2 SampleBlueNoise(in FfxUInt32x2 pixel, in FfxUInt32 sample_index) +{ + return SampleBlueNoise(pixel, sample_index, 0); +} + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_SCREEN_PROBES +FfxFloat32x4 LoadStaticScreenProbesSRV(FfxUInt32x2 coord) +{ + return g_sdfgi_r_static_screen_probes[coord]; +} + +FfxFloat32x4 SampleStaticScreenProbesSRV(FfxFloat32x2 uv) +{ + return g_sdfgi_r_static_screen_probes.SampleLevel(g_clamp_nearest_sampler, uv, FfxFloat32(0.0)); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_SCREEN_PROBES +FfxFloat32x4 LoadStaticScreenProbes(FfxUInt32x2 coord) +{ + return g_sdfgi_rw_static_screen_probes[coord]; +} + +void StoreStaticScreenProbes(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + g_sdfgi_rw_static_screen_probes[coord] = value; + +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_STATIC_GI_TARGET +FfxFloat32x4 SampleStaticGITargetSRV(FfxFloat32x2 uv) +{ + return g_sdfgi_r_static_gitarget.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f); +} + +FfxFloat32x4 LoadStaticGITargetSRV(FfxUInt32x2 coord) +{ + return g_sdfgi_r_static_gitarget[coord]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_STATIC_GI_TARGET +void StoreStaticGITarget(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + g_sdfgi_rw_static_gitarget[coord] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_TARGET +FfxFloat32x4 LoadDebugTraget(FfxUInt32x2 coord) +{ + return g_sdfgi_rw_debug_target[coord]; +} + +void StoreDebugTarget(FfxUInt32x2 coord, FfxFloat32x4 value) +{ + g_sdfgi_rw_debug_target[coord] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DEBUG_VISUALIZATION +void StoreDebugVisualization(FfxUInt32x2 pixel_coordinate, FfxFloat32x4 value) +{ + g_rw_debug_visualization[pixel_coordinate] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_DEPTH +FfxFloat32 LoadSourceDepth(FfxUInt32x2 coord) +{ + return g_src_depth[coord].r; +} + +FfxFloat32x4 GatherSourceDepth(FfxFloat32x2 uv) +{ + return g_src_depth.Gather(g_clamp_nearest_sampler, uv); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_DEPTH +FfxFloat32x4 GatherSourcePrevDepth(FfxFloat32x2 uv) +{ + return g_src_history_depth.Gather(g_clamp_nearest_sampler, uv); +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_NORMAL +FfxFloat32x3 LoadSourceNormal(FfxUInt32x2 coord) +{ + return normalize(g_src_normal.Load(FfxInt32x3(coord, 0)).xyz * g_sdfgi_constants.normalsUnpackMul + g_sdfgi_constants.normalsUnpackAdd); +} + +FfxFloat32x3 SampleSourceNormal(FfxFloat32x2 uv) +{ + return g_src_normal.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_HISTORY_NORMAL +FfxFloat32x3 SampleSourcePrevNormal(FfxFloat32x2 uv) +{ + return g_src_history_normal.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_ROUGHNESS +FfxFloat32 SampleSourceRoughness(FfxFloat32x2 uv) +{ + return g_src_roughness.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f)[GetScalingRoughnessChannel()]; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_MOTION_VECTORS +FfxFloat32x2 SampleSourceMotionVector(FfxFloat32x2 uv) +{ + return g_src_motion_vectors.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f).xy; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_SOURCE_PREV_LIT_OUTPUT +FfxFloat32x3 SampleSourcePrevLitOutput(FfxFloat32x2 uv) +{ + return g_src_prev_lit_output.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_DIFFUSE_GI +FfxFloat32x3 SampleDownsampledDiffuseGI(FfxFloat32x2 uv) +{ + return g_downsampled_diffuse_gi.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_SRV_DOWNSAMPLED_SPECULAR_GI +FfxFloat32x3 SampleDownsampledSpecularGI(FfxFloat32x2 uv) +{ + return g_downsampled_specular_gi.SampleLevel(g_clamp_nearest_sampler, uv, 0.0f).rgb; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_DEPTH +void StoreDownsampledDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value) +{ + g_downsampled_depth[pixel_coordinate] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_DEPTH +void StoreDownsampledPrevDepth(FfxUInt32x2 pixel_coordinate, FfxFloat32 value) +{ + g_downsampled_history_depth[pixel_coordinate] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_NORMAL +void StoreDownsampledNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + g_downsampled_normal[pixel_coordinate] = FfxFloat32x4(value, 0.0f); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_HISTORY_NORMAL +void StoreDownsampledPrevNormal(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + g_downsampled_history_normal[pixel_coordinate] = FfxFloat32x4(value, 0.0f); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_ROUGHNESS +void StoreDownsampledRoughness(FfxUInt32x2 pixel_coordinate, FfxFloat32 value) +{ + g_downsampled_roughness[pixel_coordinate] = value; +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_MOTION_VECTORS +void StoreDownsampledMotionVector(FfxUInt32x2 pixel_coordinate, FfxFloat32x2 value) +{ + g_downsampled_motion_vectors[pixel_coordinate] = FfxFloat32x4(value, 0.0f, 0.0f); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_DOWNSAMPLED_PREV_LIT_OUTPUT +void StoreDownsampledPrevLitOutput(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + g_downsampled_prev_lit_output[pixel_coordinate] = FfxFloat32x4(value, 0.0f); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_DIFFUSE_GI +void StoreUpsampledDiffuseGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + g_upsampled_diffuse_gi[pixel_coordinate] = FfxFloat32x4(value, 1.0f); +} +#endif + +#if defined BRIXELIZER_GI_BIND_UAV_UPSAMPLED_SPECULAR_GI +void StoreUpsampledSpecularGI(FfxUInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + g_upsampled_specular_gi[pixel_coordinate] = FfxFloat32x4(value, 1.0f); +} +#endif + +#endif // #if defined(FFX_GPU) + +#endif // FFX_BRIXELIZER_GI_CALLBACKS_HLSL_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_common.h new file mode 100644 index 00000000..3c8356bf --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_common.h @@ -0,0 +1,143 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_COMMON_H +#define FFX_BRIXELIZER_GI_COMMON_H + +#include "../ffx_core.h" + +struct FfxRay +{ + FfxBoolean valid; + FfxFloat32 roughness; + FfxFloat32x3 camera_pos; + FfxFloat32x3 normal; + FfxFloat32x3 origin; + FfxFloat32x3 direction; + FfxFloat32x3 major_direction; +}; + +FfxBoolean ffxIsBackground(FfxFloat32 depth) +{ +#if FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED == 1 + return depth < 1.e-12f; +# else // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED + return depth >= (1.0f - 1.e-12f); +# endif // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED +} + +FfxFloat32x3 ffxViewSpaceToWorldSpace(FfxFloat32x4 view_space_coord) +{ + return FFX_MATRIX_MULTIPLY(GetInverseViewMatrix(), view_space_coord).xyz; +} + +FfxFloat32x3 ffxPreviousViewSpaceToWorldSpace(FfxFloat32x4 view_space_coord) +{ + return FFX_MATRIX_MULTIPLY(GetPreviousInverseViewMatrix(), view_space_coord).xyz; +} + +// Transforms origin to uv space +// Mat must be able to transform origin from its current space into clip space. +FfxFloat32x3 ffxProjectPosition(FfxFloat32x3 origin, FfxFloat32x4x4 mat) +{ + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(origin, FfxFloat32(1.0))); + projected.xyz /= projected.w; + projected.xy = FfxFloat32(0.5) * projected.xy + FfxFloat32(0.5); + projected.y = (FfxFloat32(1.0) - projected.y); + return projected.xyz; +} + +FfxFloat32x3 ffxInvProjectPosition(FfxFloat32x3 coord, FfxFloat32x4x4 mat) +{ + coord.y = (FfxFloat32(1.0) - coord.y); + coord.xy = FfxFloat32(2.0) * coord.xy - FfxFloat32(1.0); + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(coord, FfxFloat32(1.0))); + projected.xyz /= projected.w; + return projected.xyz; +} + +FfxFloat32 ffxGetLinearDepth(FfxFloat32x2 uv, FfxFloat32 depth) +{ + const FfxFloat32x3 view_space_pos = ffxInvProjectPosition(FfxFloat32x3(uv, depth), GetInverseProjectionMatrix()); + return abs(view_space_pos.z); +} + +FfxFloat32x3 ffxScreenSpaceToViewSpace(FfxFloat32x3 screen_uv_coord) +{ + return ffxInvProjectPosition(screen_uv_coord, GetInverseProjectionMatrix()); +} + +FfxFloat32x3 ffxPreviousScreenSpaceToViewSpace(FfxFloat32x3 screen_uv_coord) +{ + return ffxInvProjectPosition(screen_uv_coord, GetPreviousInverseProjectionMatrix()); +} + +FfxFloat32x3 ffxGetWorldPosition(FfxFloat32x2 uv, FfxFloat32 depth) +{ + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, depth); + FfxFloat32x3 view_space_position = ffxScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 world_space_origin = ffxViewSpaceToWorldSpace(FfxFloat32x4(view_space_position, 1.0)).xyz; + return world_space_origin; +} + +FfxFloat32x3 ffxGetPreviousWorldPosition(FfxFloat32x2 uv, FfxFloat32 depth) +{ + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, depth); + FfxFloat32x3 view_space_position = ffxPreviousScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 world_space_origin = ffxPreviousViewSpaceToWorldSpace(FfxFloat32x4(view_space_position, 1.0)).xyz; + return world_space_origin; +} + +#if FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED == 1 +FFX_STATIC const FfxFloat32 FfxBrixelizerGIFrontendConstants_BackgroundDepth = FfxFloat32(0.0); +#else // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED +FFX_STATIC const FfxFloat32 FfxBrixelizerGIFrontendConstants_BackgroundDepth = FfxFloat32(1.0); +#endif // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED + +FfxBoolean FfxBrixelizerGIIsDepthACloserThanB(FfxFloat32 a, FfxFloat32 b) +{ +#if FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED == 1 + return a > b; +#else // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED + return a < b; +#endif // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED +} + +FfxFloat32 FfxBrixelizerGIDepthCloserOp(FfxFloat32 a, FfxFloat32 b) +{ +#ifdef FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED + return max(a, b); +#else // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED + return min(a, b); +#endif // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED +} + +FfxFloat32 FfxBrixelizerGIDepthFarthestOp(FfxFloat32 a, FfxFloat32 b) +{ +#if FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED == 1 + return min(a, b); +#else // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED + return max(a, b); +#endif // !FFX_BRIXELIZER_GI_OPTION_DEPTH_INVERTED +} + +#endif // FFX_BRIXELIZER_GI_COMMON_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_host_interface.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_host_interface.h new file mode 100644 index 00000000..cce186eb --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_host_interface.h @@ -0,0 +1,109 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_HOST_INTERFACE_H +#define FFX_BRIXELIZER_GI_HOST_INTERFACE_H + +#include "../ffx_core.h" + +#define FFX_BRIXELIZER_GI_INVALID_ID 0x00FFFFFFu + +struct FfxBrixelizerGITracingConstants +{ + FfxUInt32 start_cascade; + FfxUInt32 end_cascade; + FfxUInt32 debug_state; + FfxUInt32 debug_traversal_state; + + FfxFloat32 ray_pushoff; + FfxFloat32 sdf_solve_eps; + FfxFloat32 specular_ray_pushoff; + FfxFloat32 specular_sdf_solve_eps; + + FfxFloat32 preview_ray_pushoff; + FfxFloat32 preview_sdf_solve_eps; + FfxFloat32 t_min; + FfxFloat32 t_max; +}; + +struct FfxBrixelizerGIConstants +{ + FfxFloat32x4x4 view; + FfxFloat32x4x4 view_proj; + FfxFloat32x4x4 inv_view; + FfxFloat32x4x4 inv_proj; + FfxFloat32x4x4 inv_view_proj; + FfxFloat32x4x4 prev_view_proj; + FfxFloat32x4x4 prev_inv_view; + FfxFloat32x4x4 prev_inv_proj; + + FfxUInt32 target_height; + FfxUInt32 target_width; + FfxFloat32 environmentMapIntensity; + FfxUInt32 roughnessChannel; + + FfxUInt32 isRoughnessPerceptual; + FfxFloat32 roughnessThreshold; + FfxFloat32 normalsUnpackMul; + FfxFloat32 normalsUnpackAdd; + + FfxFloat32x2 motionVectorScale; + FfxUInt32 debug_type; + FfxFloat32 _padding; + + FfxUInt32x2 buffer_dimensions; + FfxUInt32x2 probe_buffer_dimensions; + + FfxFloat32x2 buffer_dimensions_f32; + FfxFloat32x2 ibuffer_dimensions; + + FfxFloat32x2 probe_buffer_dimensions_f32; + FfxFloat32x2 iprobe_buffer_dimensions; + + FfxUInt32x2 tile_buffer_dimensions; + FfxFloat32x2 tile_buffer_dimensions_f32; + + FfxUInt32x2 brick_tile_buffer_dimensions; + FfxFloat32x2 brick_tile_buffer_dimensions_f32; + + FfxFloat32x3 camera_position; + FfxUInt32 frame_index; + + FfxBrixelizerGITracingConstants tracing_constants; +}; + +struct FfxBrixelizerGIPassConstants +{ + FfxUInt32 cascade_idx; + FfxFloat32 energy_decay_k; + FfxUInt32x2 _padding; +}; + +struct FfxBrixelizerGIScalingConstants +{ + FfxUInt32x2 sourceSize; + FfxUInt32x2 downsampledSize; + FfxUInt32 roughnessChannel; + FfxUInt32x3 _padding; +}; + +#endif // FFX_BRIXELIZER_GI_HOST_INTERFACE_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_main.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_main.h new file mode 100644 index 00000000..b7c771bd --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_main.h @@ -0,0 +1,2029 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_MAIN_H +#define FFX_BRIXELIZER_GI_MAIN_H + +#include "../ffx_core.h" +#include "ffx_brixelizer_brick_common_private.h" + +FFX_STATIC FfxFloat32 s_sdf_solve_eps; + +#define FFX_BRIXELIZER_TRAVERSAL_EPS s_sdf_solve_eps +#include "ffx_brixelizergi_common.h" +#include "ffx_brixelizergi_probe_shading.h" +#include "ffx_brixelizer_trace_ops.h" + +// Z-up +FfxFloat32x3 FfxBrixelizerGIUVToHemioct(FfxFloat32x2 e) +{ + e = FfxFloat32(2.0) * e - FFX_BROADCAST_FLOAT32X2(FfxFloat32(1.0)); + FfxFloat32x2 temp = FfxFloat32x2(e.x + e.y, e.x - e.y) * FfxFloat32(0.5); + FfxFloat32x3 v = FfxFloat32x3(temp, FfxFloat32(1.0) - abs(temp.x) - abs(temp.y)); + return normalize(v); +} + +FfxFloat32x2 FfxBrixelizerGIHemioctToUV(FfxFloat32x3 v) +{ + FfxFloat32x2 p = v.xy * (FfxFloat32(1.0) / (abs(v.x) + abs(v.y) + v.z)); + return FfxFloat32x2(p.x + p.y, p.x - p.y) * FfxFloat32(0.5) + FFX_BROADCAST_FLOAT32X2(FfxFloat32(0.5)); +} + +FfxFloat32x3x3 FfxBrixelizerGICreateTBN(FfxFloat32x3 N) +{ + FfxFloat32x3 U; + if (abs(N.z) > FfxFloat32(0.0)) { + FfxFloat32 k = ffxSqrt(N.y * N.y + N.z * N.z); + U.x = FfxFloat32(0.0); + U.y = -N.z / k; + U.z = N.y / k; + } else { + FfxFloat32 k = ffxSqrt(N.x * N.x + N.y * N.y); + U.x = N.y / k; + U.y = -N.x / k; + U.z = FfxFloat32(0.0); + } + FfxFloat32x3x3 TBN; + TBN[0] = U; + TBN[1] = cross(N, U); + TBN[2] = N; + return TBN; +} + +FfxFloat32x3 FfxBrixelizerGITransform(FfxFloat32x3x3 TBN, FfxFloat32x3 direction) +{ + return direction.x * TBN[0] + direction.y * TBN[1] + direction.z * TBN[2]; // FFX_MATRIX_MULTIPLY(direction, TBN); // +} + +FfxFloat32x2 FfxBrixelizerGIGetUV(FfxUInt32x2 tid) +{ + return (FfxFloat32x2(tid) + FFX_BROADCAST_FLOAT32X2(FfxFloat32(0.5))) / GetBufferDimensionsF32(); +} + +FfxUInt32x2 FfxBrixelizerGIRoundDown(FfxUInt32x2 p, FfxUInt32 v) +{ + return v * (p / v); +} + +// From "Temporal Reprojection Anti-Aliasing" +// https://github.com/playdeadgames/temporal +/********************************************************************** +Copyright (c) [2015] [Playdead] + +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. +********************************************************************/ +FfxFloat32x3 FfxBrixelizerGIClipAABB(FfxFloat32x3 aabb_min, FfxFloat32x3 aabb_max, FfxFloat32x3 prev_sample) +{ + // Main idea behind clipping - it prevents clustering when neighbor color space + // is distant from history sample + + // Here we find intersection between color vector and aabb color box + + // Note: only clips towards aabb center + FfxFloat32x3 aabb_center = 0.5 * (aabb_max + aabb_min); + FfxFloat32x3 extent_clip = 0.5 * (aabb_max - aabb_min) + 0.001; + + // Find color vector + FfxFloat32x3 color_vector = prev_sample - aabb_center; + // Transform into clip space + FfxFloat32x3 color_vector_clip = color_vector / extent_clip; + // Find ffxMax absolute component + color_vector_clip = abs(color_vector_clip); + FfxFloat32 max_abs_unit = ffxMax(ffxMax(color_vector_clip.x, color_vector_clip.y), color_vector_clip.z); + + if (max_abs_unit > 1.0) { + return aabb_center + color_vector / max_abs_unit; // clip towards color vector + } else { + return prev_sample; // point is inside aabb + } +} + +FfxFloat32x3 FfxBrixelizerGIClipAABB(FfxFloat32x3 prev_sample, FfxFloat32x3 center, FfxFloat32 aabb_size) +{ + return FfxBrixelizerGIClipAABB(center - FFX_BROADCAST_FLOAT32X3(aabb_size), center + FFX_BROADCAST_FLOAT32X3(aabb_size), prev_sample); +} + +// https://www.pcg-random.org/ +FfxUInt32 FfxBrixelizerGIpcg(FfxUInt32 v) +{ + FfxUInt32 state = v * 747796405u + 2891336453u; + FfxUInt32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +FfxUInt32 FfxBrixelizerGIPackNormalTo32bits(FfxFloat32x3 normal) +{ + FfxFloat32x2 octuv = FfxBrixelizerOctahedronToUV(normal); + FfxUInt32 ix = FfxUInt32(octuv.x * FfxFloat32(65535.0)); + FfxUInt32 iy = FfxUInt32(octuv.y * FfxFloat32(65535.0)); + return ix | (iy << 16); +} + +FfxFloat32x3 FfxBrixelizerGIUnpackNormalFrom32bits(FfxUInt32 payload) +{ + FfxFloat32 ox = FfxFloat32(payload & 0xffff) / FfxFloat32(65535.0); + FfxFloat32 oy = FfxFloat32((payload >> 16) & 0xffff) / FfxFloat32(65535.0); + return FfxBrixelizerUVToOctahedron(FfxFloat32x2(ox, oy)); +} + +FfxFloat32 FfxBrixelizerGIUnpackUnorm16(FfxUInt32 a) +{ + return FfxFloat32(a & 0xffffu) / FfxFloat32(255.0 * 255.0); +} + +FfxUInt32 FfxBrixelizerGIPackUnorm16(FfxFloat32 a) +{ + return FfxUInt32(ffxSaturate(a) * FfxFloat32(255.0 * 255.0)); +} + +FfxFloat32 FfxBrixelizerGIUnpackUnorm8(FfxUInt32 a) +{ + return FfxFloat32(a & 0xffu) / 255.0; +} + +FfxUInt32 FfxBrixelizerGIPackUnorm8(FfxFloat32 a) +{ + return FfxUInt32(ffxSaturate(a) * 255.0); +} + +// Probes are spawned in screen space and placed on gbuffer +struct FfxBrixelizerGIProbeSpawnInfo +{ + FfxUInt32x2 seed_pixel; + FfxFloat32x3 normal; + FfxFloat32 depth; + FfxFloat32 eps; + FfxFloat32 pushoff; +}; + +FfxUInt32x4 FfxBrixelizerGIProbeSpawnInfoPack(in FfxBrixelizerGIProbeSpawnInfo p) +{ + FfxUInt32x4 pack = FfxUInt32x4(0, 0, 0, 0); + pack.x |= p.seed_pixel.x; + pack.x |= p.seed_pixel.y << 16u; + pack.y = FfxBrixelizerGIPackNormalTo32bits(p.normal); + pack.z = ffxAsUInt32(p.depth); + pack.w = ffxPackF32(FfxFloat32x2(p.eps, p.pushoff)); + return pack; +} +FfxUInt32x4 FfxBrixelizerGIProbeSpawnInfoInvalidPack() +{ + FfxBrixelizerGIProbeSpawnInfo pinfo; + + pinfo.seed_pixel.x = 0xffffu; + pinfo.seed_pixel.y = 0xffffu; + pinfo.normal = FFX_BROADCAST_FLOAT32X3(0.0); + pinfo.depth = FfxBrixelizerGIFrontendConstants_BackgroundDepth; + pinfo.eps = FfxFloat32(0.0); + pinfo.pushoff = FfxFloat32(0.0); + return FfxBrixelizerGIProbeSpawnInfoPack(pinfo); +} +FfxBrixelizerGIProbeSpawnInfo FfxBrixelizerGIProbeSpawnInfoUnpack(FfxUInt32x4 pack) +{ + FfxBrixelizerGIProbeSpawnInfo pinfo; + + pinfo.seed_pixel.x = pack.x & 0xffffu; + pinfo.seed_pixel.y = (pack.x >> 16u) & 0xffffu; + pinfo.normal = FfxBrixelizerGIUnpackNormalFrom32bits(pack.y); + pinfo.depth = ffxAsFloat(pack.z); + FfxFloat32x2 hpack = ffxUnpackF32(pack.w); + pinfo.eps = hpack.x; + pinfo.pushoff = hpack.y; + return pinfo; +} +FfxFloat32x3 FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(in FfxBrixelizerGIProbeSpawnInfo p) +{ + FfxFloat32x2 uv = FfxBrixelizerGIGetUV(p.seed_pixel); + return ffxGetWorldPosition(uv, p.depth); +} +FfxFloat32x3 FfxBrixelizerGIProbeSpawnInfoGetPrevSpawnPosition(in FfxBrixelizerGIProbeSpawnInfo p) +{ + FfxFloat32x2 uv = FfxBrixelizerGIGetUV(p.seed_pixel); + return ffxGetPreviousWorldPosition(uv, p.depth); +} +FfxFloat32x3 FfxBrixelizerGIProbeSpawnInfoGetRayDirection(in FfxBrixelizerGIProbeSpawnInfo p, FfxUInt32x2 probe_coord, FfxUInt32x2 cell) +{ + FfxFloat32x2 xi = SampleBlueNoise(probe_coord * 8u + cell, GetFrameIndex()); + FfxFloat32x2 hemioct_uv = (FfxFloat32x2(cell) + xi) / 8.0; + FfxFloat32x3 ray_direction = FfxBrixelizerGIUVToHemioct(hemioct_uv); + FfxFloat32x3x3 TBN = FfxBrixelizerGICreateTBN(p.normal); + return FfxBrixelizerGITransform(TBN, ray_direction); +} +FfxFloat32x3 FfxBrixelizerGIProbeSpawnInfoGetRayUnjitteredDirection(in FfxBrixelizerGIProbeSpawnInfo p, FfxUInt32x2 cell) +{ + FfxFloat32x2 hemioct_uv = (FfxFloat32x2(cell) + FFX_BROADCAST_FLOAT32X2(0.5)) / 8.0; + FfxFloat32x3 ray_direction = FfxBrixelizerGIUVToHemioct(hemioct_uv); + FfxFloat32x3x3 TBN = FfxBrixelizerGICreateTBN(p.normal); + return FfxBrixelizerGITransform(TBN, ray_direction); +} +FfxFloat32x3 FfxBrixelizerGIProbeSpawnInfoProjectOnHemisphere(in FfxBrixelizerGIProbeSpawnInfo p, FfxFloat32x3 dir) +{ + FfxFloat32x3x3 TBN = FfxBrixelizerGICreateTBN(p.normal); + FfxFloat32x3 proj = FfxFloat32x3( + dot(dir, TBN[0]), + dot(dir, TBN[1]), + dot(dir, TBN[2])); + return proj; +} +FfxBoolean FfxBrixelizerGIProbeSpawnInfoIsValid(in FfxBrixelizerGIProbeSpawnInfo p) +{ + return all(FFX_NOT_EQUAL(p.seed_pixel, FFX_BROADCAST_UINT32X2(0xffffu))); +} + +FfxFloat32 FfxBrixelizerGIWeight(FfxFloat32x3 center_normal, FfxFloat32x3 center_world_position, FfxFloat32x3 test_normal, FfxFloat32x3 test_world_position, FfxFloat32 eps_size, FfxFloat32 power, FfxFloat32 normal_power) +{ + return ffxPow(ffxPow(ffxSaturate(dot(center_normal, test_normal)), normal_power) * ffxSaturate(FfxFloat32(1.0) - length(center_world_position - test_world_position) / eps_size), power); +} + +FFX_MIN16_F FfxBrixelizerGIWeightMin16(FFX_MIN16_F3 center_normal, FfxFloat32x3 center_world_position, FFX_MIN16_F3 test_normal, FfxFloat32x3 test_world_position, FFX_MIN16_F eps_size, FFX_MIN16_F power) +{ + return ffxPow(ffxSaturate(dot(center_normal, test_normal)) * ffxSaturate(FFX_MIN16_F(1.0) - FFX_MIN16_F(length(center_world_position - test_world_position)) / eps_size), power); +} + +FfxUInt32 FfxBrixelizerGIScreenProbes_FindClosestProbe(FfxUInt32x2 tid, FfxInt32x2 offset) +{ + FfxInt32x2 pos = FfxInt32x2(tid) + offset; + + if (any(FFX_LESS_THAN(pos, FFX_BROADCAST_UINT32X2(0))) || any(FFX_GREATER_THAN_EQUAL(pos, GetTileBufferDimensions()))) + return FFX_BRIXELIZER_GI_INVALID_ID; + + FfxUInt32 probe_idx = pos.x + pos.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadTempProbeInfo(probe_idx)); + + if (!FfxBrixelizerGIProbeSpawnInfoIsValid(pinfo)) + return FFX_BRIXELIZER_GI_INVALID_ID; + + return pos.x | (pos.y << 16u); +} + +FfxFloat32 FfxBrixelizerGIGetFrameWeight(FfxUInt32 num_frames) +{ + return FfxFloat32(1.0) - FfxFloat32(1.0) / FfxFloat32(num_frames); +} + +// Src: Hacker's Delight, Henry S. Warren, 2001 +FfxFloat32 FfxBrixelizerGIRadicalInverse_VdC(FfxUInt32 bits) +{ + bits = (bits << 16u) | (bits >> 16u); + bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u); + bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u); + bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u); + bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u); + return FfxFloat32(bits) * FfxFloat32(2.3283064365386963e-10); // / 0x100000000 +} + +FfxFloat32x2 FfxBrixelizerGIHammersley(FfxUInt32 i, FfxUInt32 N) +{ + return FfxFloat32x2(FfxFloat32(i) / FfxFloat32(N), FfxBrixelizerGIRadicalInverse_VdC(i)); +} + +// Copyright (c) 2018 Eric Heitz (the Authors). +// +// 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. +FfxFloat32x3 FfxBrixelizerGISampleGGXVNDF(FfxFloat32x3 Ve, FfxFloat32 alpha_x, FfxFloat32 alpha_y, FfxFloat32 U1, FfxFloat32 U2) +{ + // Input Ve: view direction + // Input alpha_x, alpha_y: roughness parameters + // Input U1, U2: uniform random numbers + // Output Ne: normal sampled with PDF D_Ve(Ne) = G1(Ve) * ffxMax(0, dot(Ve, Ne)) * D(Ne) / Ve.z + // + // + // Section 3.2: transforming the view direction to the hemisphere configuration + FfxFloat32x3 Vh = normalize(FfxFloat32x3(alpha_x * Ve.x, alpha_y * Ve.y, Ve.z)); + // Section 4.1: orthonormal basis (with special case if cross product is zero) + FfxFloat32 lensq = Vh.x * Vh.x + Vh.y * Vh.y; + FfxFloat32x3 T1 = lensq > 0 ? FfxFloat32x3(-Vh.y, Vh.x, 0) * ffxRsqrt(lensq) : FfxFloat32x3(1, 0, 0); + FfxFloat32x3 T2 = cross(Vh, T1); + // Section 4.2: parameterization of the projected area + FfxFloat32 r = ffxSqrt(U1); + FfxFloat32 phi = 2.0 * 3.14159265358979f * U2; + FfxFloat32 t1 = r * cos(phi); + FfxFloat32 t2 = r * sin(phi); + FfxFloat32 s = 0.5 * (1.0 + Vh.z); + t2 = (1.0 - s) * ffxSqrt(1.0 - t1 * t1) + s * t2; + // Section 4.3: reprojection onto hemisphere + FfxFloat32x3 Nh = t1 * T1 + t2 * T2 + ffxSqrt(ffxMax(0.0, 1.0 - t1 * t1 - t2 * t2)) * Vh; + // Section 3.4: transforming the normal back to the ellipsoid configuration + FfxFloat32x3 Ne = normalize(FfxFloat32x3(alpha_x * Nh.x, alpha_y * Nh.y, ffxMax(0.0, Nh.z))); + return Ne; +} + +FfxFloat32x3 FfxBrixelizerGISample_GGX_VNDF_Ellipsoid(FfxFloat32x3 Ve, FfxFloat32 alpha_x, FfxFloat32 alpha_y, FfxFloat32 U1, FfxFloat32 U2) +{ + return FfxBrixelizerGISampleGGXVNDF(Ve, alpha_x, alpha_y, U1, U2); +} + +FfxFloat32x3 FfxBrixelizerGISample_GGX_VNDF_Hemisphere(FfxFloat32x3 Ve, FfxFloat32 alpha, FfxFloat32 U1, FfxFloat32 U2) +{ + return FfxBrixelizerGISample_GGX_VNDF_Ellipsoid(Ve, alpha, alpha, U1, U2); +} + +FfxFloat32x3 FfxBrixelizerGISampleReflectionVector(FfxFloat32x3 view_direction, FfxFloat32x3 normal, FfxFloat32 roughness, FfxInt32x2 dispatch_thread_id, FfxUInt32x2 noise_coord) +{ + if (roughness < FfxFloat32(1.0e-3)) { + return reflect(view_direction, normal); + } + + FfxFloat32x3x3 tbn_transform = FfxBrixelizerGICreateTBN(normal); + FfxFloat32x3x3 inv_tbn_transform = transpose(tbn_transform); + FfxFloat32x3 view_direction_tbn = FfxBrixelizerGITransform(inv_tbn_transform, -view_direction); + + FfxFloat32x2 u = SampleBlueNoise(noise_coord, GetFrameIndex()); + + FfxFloat32x3 sampled_normal_tbn = FfxBrixelizerGISample_GGX_VNDF_Hemisphere(view_direction_tbn, roughness, u.x, u.y); + FfxFloat32x3 reflected_direction_tbn = reflect(-view_direction_tbn, sampled_normal_tbn); + // Transform reflected_direction back to the initial space. + + return FfxBrixelizerGITransform(tbn_transform, reflected_direction_tbn); +} + +FfxRay FfxBrixelizerGIGenReflectionRay(FfxUInt32x2 pixel_coordinate, FfxUInt32x2 noise_coord) +{ + FfxFloat32x2 uv = FfxBrixelizerGIGetUV(pixel_coordinate); + FfxFloat32 z = LoadDepth(pixel_coordinate); + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, z); + FfxFloat32x3 view_space_ray = ffxScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 view_space_ray_direction = normalize(view_space_ray); + FfxFloat32x3 world_space_view_direction = FFX_MATRIX_MULTIPLY(GetInverseViewMatrix(), FfxFloat32x4(view_space_ray_direction, FfxFloat32(0.0))).xyz; + FfxFloat32x3 world_space_normal = LoadWorldNormal(pixel_coordinate); + FfxFloat32x3 world_space_origin = FFX_MATRIX_MULTIPLY(GetInverseViewMatrix(), FfxFloat32x4(view_space_ray, FfxFloat32(1.0))).xyz; + FfxFloat32x3 view_space_surface_normal = FFX_MATRIX_MULTIPLY(GetViewMatrix(), FfxFloat32x4(normalize(world_space_normal), 0)).xyz; + FfxFloat32 roughness = LoadRoughness(pixel_coordinate); + FfxFloat32x3 view_space_reflected_direction = FfxBrixelizerGISampleReflectionVector(view_space_ray_direction, view_space_surface_normal, roughness, FfxInt32x2(pixel_coordinate), noise_coord); + + FfxFloat32x3 world_space_ray_direction = FFX_MATRIX_MULTIPLY(GetInverseViewMatrix(), FfxFloat32x4(view_space_reflected_direction, FfxFloat32(0.0))).xyz; + + FfxRay ray; + + ray.roughness = roughness; + ray.valid = !ffxIsBackground(z); + ray.normal = world_space_normal; + ray.origin = world_space_origin; + ray.direction = normalize(world_space_ray_direction); + ray.major_direction = normalize(FFX_MATRIX_MULTIPLY(GetInverseViewMatrix(), FfxFloat32x4(reflect(view_space_ray_direction, view_space_surface_normal), FfxFloat32(0.0))).xyz); + ray.camera_pos = ffxViewSpaceToWorldSpace(FfxFloat32x4(0.0, 0.0, 0.0, 1.0)); + + return ray; +} + +FfxBoolean FfxBrixelizerGIIsCheckerboard(FfxUInt32x2 tid) +{ + FfxUInt32x2 qid = (tid / 8) % 4; + qid = ffxWaveReadLaneFirstU2(qid); // scalar + FfxUInt32 qidx = qid.x + qid.y * 4; + FfxUInt32 seed = LoadTempRandomSeed(tid / FfxUInt32(8)); + FfxUInt32 shift = seed % FfxUInt32(16); + return qidx == shift; +} + +//////////////////////////// +// Interface functions ///// +//////////////////////////// +void FfxBrixelizerGIClearCounters() +{ + StoreRaySwapIndirectArgs(0, 0); +} + +FfxFloat32 FfxBrixelizerGIGetEps(FfxFloat32x3 position) +{ + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(GetTracingConstantsStartCascade()); + return GetTracingConstantsRayPushoff() * CINFO.voxel_size * ffxMax(FfxFloat32(1.0e-3), length(position - GetCameraPosition())); +} + +void FfxBrixelizerGISpawnScreenProbes(FfxUInt32x2 tid) +{ + if (any(FFX_GREATER_THAN_EQUAL(tid, GetTileBufferDimensions()))) + return; + + FfxUInt32x2 probe_screen_offset = tid * FfxUInt32(8); + FfxUInt32x2 probe_coord = tid; + FfxUInt32 probe_idx = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + const FfxUInt32 max_num_points = FfxUInt32(64); + FfxUInt32x2 seed_pixel = FFX_BROADCAST_UINT32X2(-1); + FfxFloat32 depth = FfxBrixelizerGIFrontendConstants_BackgroundDepth; + const FfxUInt32 max_attempts = FfxUInt32(8); + + { + FfxUInt32 seed = FfxBrixelizerGIpcg(GetFrameIndex() + FfxBrixelizerGIpcg(probe_screen_offset.x + FfxBrixelizerGIpcg(probe_screen_offset.y))); + StoreTempRandomSeed(tid, seed & FfxUInt32(0xff)); + } + + for (FfxUInt32 i = 0; i < max_attempts; i++) + { + FfxFloat32x2 seed_jitter = FfxBrixelizerGIHammersley( + ( // + FfxBrixelizerGIpcg(GetFrameIndex()) + FfxBrixelizerGIpcg(probe_screen_offset.x + FfxBrixelizerGIpcg(probe_screen_offset.y + FfxBrixelizerGIpcg(i))) // + ) // + & (max_num_points - FfxUInt32(1)), + max_num_points); + FfxUInt32x2 try_seed_pixel = probe_screen_offset + FfxUInt32x2(floor(FfxFloat32(8.0) * seed_jitter)); + FfxFloat32 try_depth = LoadDepth(try_seed_pixel); + if (ffxIsBackground(try_depth)) + continue; + depth = try_depth; + seed_pixel = try_seed_pixel; + + break; + } + + if (seed_pixel.x == FfxUInt32(-1)) + { + StoreTempProbeInfo(probe_idx, FfxBrixelizerGIProbeSpawnInfoInvalidPack()); + return; + } + + FfxFloat32x3 normal = LoadWorldNormal(seed_pixel); + FfxBoolean is_sky_pixel = ffxIsBackground(depth); + + if (is_sky_pixel) + { + StoreTempProbeInfo(probe_idx, FfxBrixelizerGIProbeSpawnInfoInvalidPack()); + return; + } + + FfxBrixelizerGIProbeSpawnInfo pinfo; + + pinfo.seed_pixel = seed_pixel; + pinfo.normal = normal; + pinfo.depth = depth; + FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade(); + FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + FfxFloat32 ray_pushoff = GetTracingConstantsRayPushoff(); + FfxFloat32 xi = FfxFloat32((FfxBrixelizerGIpcg(GetFrameIndex()) + FfxBrixelizerGIpcg(tid.x + FfxBrixelizerGIpcg(tid.y))) & 0xff) / FfxFloat32(255.0); + pinfo.pushoff = ray_pushoff * FfxBrixelizerGIGetVoxelSize(FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo), g_starting_cascade, g_end_cascade, xi); + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(g_starting_cascade); + pinfo.eps = FfxBrixelizerGIGetEps(FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo)); + StoreTempProbeInfo(probe_idx, FfxBrixelizerGIProbeSpawnInfoPack(pinfo)); +} + +FFX_GROUPSHARED FfxUInt32 lds_reprojected_probe_score; +FFX_GROUPSHARED FfxFloat32 lds_tile_weights[3 * 3]; +FFX_GROUPSHARED FfxUInt32 lds_reprojected_reprojected_cnt; +FFX_GROUPSHARED FfxUInt32 lds_reprojected_probe_x[8u * 8u]; +FFX_GROUPSHARED FfxUInt32 lds_reprojected_probe_y[8u * 8u]; +FFX_GROUPSHARED FfxUInt32 lds_reprojected_probe_z[8u * 8u]; +FFX_GROUPSHARED FfxUInt32 lds_reprojected_probe_w[8u * 8u]; +FFX_GROUPSHARED FfxUInt32 lds_reprojected_probe_num_samples[8u * 8u]; +FFX_GROUPSHARED FfxUInt32 lds_reprojected_probe_coords[8u * 8u]; + +void FfxBrixelizerGILDS_StoreRadiance(FfxInt32x2 c, FfxFloat32x4 r) +{ + FfxInt32 cell_idx = c.x + c.y * 8; + lds_reprojected_probe_x[cell_idx] = ffxPackF32(r.xy); + lds_reprojected_probe_y[cell_idx] = ffxPackF32(r.zw); +} + +FfxFloat32x4 FfxBrixelizerGILDS_LoadRadiance(FfxInt32x2 c) +{ + FfxInt32 cell_idx = c.x + c.y * 8; + return FfxFloat32x4(ffxUnpackF32(lds_reprojected_probe_x[cell_idx]), ffxUnpackF32(lds_reprojected_probe_y[cell_idx])); +} + +#define FFX_BRIXELIZER_GI_RADIANCE_QUANTIZE_K FfxFloat32(1.0e4) +FfxUInt32x4 FfxBrixelizerGIQuantizeRadiance(FfxFloat32x4 radiance) +{ + return FfxUInt32x4(floor(FFX_BRIXELIZER_GI_RADIANCE_QUANTIZE_K * radiance)); +} + +FfxFloat32x4 FfxBrixelizerGIRecoverRadiance(FfxUInt32x4 quantized_radiance) +{ + return FfxFloat32x4(quantized_radiance) / FFX_BRIXELIZER_GI_RADIANCE_QUANTIZE_K; +} + +FfxBoolean FfxBrixelizerGISampleWorldSDF(FfxFloat32x3 world_pos, inout FfxFloat32 voxel_size, inout FfxFloat32 sdf, inout FfxFloat32x3 grad) +{ + const FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade(); + const FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + + for (FfxUInt32 cascade_id = g_starting_cascade; cascade_id <= g_end_cascade; cascade_id++) + { + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(cascade_id); + FfxFloat32 size = CINFO.grid_max.x - CINFO.grid_min.x; + + if (all(FFX_GREATER_THAN(world_pos, CINFO.grid_min)) && all(FFX_LESS_THAN(world_pos, CINFO.grid_max))) + { + FfxFloat32x3 rel_pos = world_pos - CINFO.grid_min; + FfxInt32x3 voxel_offset = FfxInt32x3(rel_pos / CINFO.voxel_size); + FfxFloat32x3 uvw = (rel_pos - FfxFloat32x3(voxel_offset) * CINFO.voxel_size) / CINFO.voxel_size; + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(CINFO.clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, FfxUInt32x3(voxel_offset)), FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMapArrayUniform(cascade_id, voxel_idx); + + if (FfxBrixelizerIsValidID(brick_id)) + { + FfxFloat32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxFloat32x3 uvw_min = (brick_offset + FFX_BROADCAST_FLOAT32X3(0.5)) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE); + FfxFloat32x3 uvw_max = uvw_min + FFX_BROADCAST_FLOAT32X3(7.0) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE); + FfxFloat32x3 atlas_uvw = ffxLerp(uvw_min, uvw_max, uvw); + sdf = SampleSDFAtlas(atlas_uvw); + grad = FfxBrixelizerGetBrixelGrad(uvw_min, uvw_max, uvw); + voxel_size = CINFO.voxel_size; + return true; + } + } + } + return false; +} + +FfxFloat32x2 FfxBrixelizerGIFindClosestMotionVector(FfxUInt32x2 tid) +{ + FfxFloat32x2 motion_vector; + FfxFloat32 closest_depth = FfxBrixelizerGIFrontendConstants_BackgroundDepth; + + for (FfxInt32 y = -1; y <= 1; ++y) + { + for (FfxInt32 x = -1; x <= 1; ++x) + { + FfxInt32x2 coord = FfxInt32x2(tid) + FfxInt32x2(x, y); + + if (any(FFX_LESS_THAN(coord, FFX_BROADCAST_INT32X2(0))) || any(FFX_GREATER_THAN_EQUAL(coord, GetBufferDimensions()))) + continue; + + FfxFloat32 depth = LoadDepth(coord); + + if (FfxBrixelizerGIIsDepthACloserThanB(/* A */ depth, /* B */ closest_depth)) + { + motion_vector = LoadMotionVector(coord); + closest_depth = depth; + } + } + } + + return motion_vector; +} + +// 8x8 group +// This function reprojects the screen probes from the previous frame and does irradiance sharing iteration +void FfxBrixelizerGIReprojectScreenProbes(FfxUInt32x2 tid, FfxUInt32x2 gid) +{ + FfxUInt32x2 probe_screen_offset = FfxBrixelizerGIRoundDown(tid, 8u); + FfxUInt32x2 probe_coord = tid / 8u; + probe_coord = ffxWaveReadLaneFirstU2(probe_coord); // scalar + + FfxUInt32 probe_idx = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + FfxUInt32 sh_index = gid.x + gid.y * 8u; + FfxUInt32 cell_idx = gid.x + gid.y * 8u; + FfxUInt32 qidx = (gid.x % 2) + (gid.y % 2) * 2; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadTempProbeInfo(probe_idx)); + + if (!FfxBrixelizerGIProbeSpawnInfoIsValid(pinfo)) // scalar + { + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X2(0)))) + { + StoreTempSpawnMask(probe_coord, 0); + StoreStaticScreenProbesStat(probe_coord, FFX_BROADCAST_FLOAT32X4(0.0)); + } + StoreStaticScreenProbes(tid, FFX_BROADCAST_FLOAT32X4(0.0)); + return; + } + + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X2(0)))) + { + lds_reprojected_probe_score = 0xffffffff;//(FfxUInt32)-1; + lds_reprojected_reprojected_cnt = 0; + } + + lds_reprojected_probe_x[cell_idx] = FfxUInt32(0); + lds_reprojected_probe_y[cell_idx] = FfxUInt32(0); + lds_reprojected_probe_z[cell_idx] = FfxUInt32(0); + lds_reprojected_probe_w[cell_idx] = FfxUInt32(0); + lds_reprojected_probe_num_samples[cell_idx] = 0; + FFX_GROUP_MEMORY_BARRIER; + + FfxFloat32x3 pixel_normal = LoadWorldNormal(tid); + FfxFloat32 pixel_depth = LoadDepth(tid); + FfxFloat32x2 pixel_uv = FfxBrixelizerGIGetUV(tid); + FfxFloat32x3 pixel_world_pos = ffxGetWorldPosition(pixel_uv, pixel_depth); + + FfxFloat32x3 probe_pos = FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo); + FfxFloat32 eps_size = pinfo.eps * FfxFloat32(4.0); // ffxPow(FfxFloat32(2.0), pinfo.eps) / FfxFloat32(2.0); + FfxFloat32x2 history_uv = FfxBrixelizerGIGetUV(tid) + FfxBrixelizerGIFindClosestMotionVector(tid); + + if (any(FFX_LESS_THAN(history_uv, FFX_BROADCAST_FLOAT32X2(0.0))) || any(FFX_GREATER_THAN(history_uv, FFX_BROADCAST_FLOAT32X2(1.0)))) + { + } + else + { + FfxUInt32x2 sample_pixel_coord = FfxUInt32x2(floor(history_uv * GetBufferDimensionsF32())); + FfxUInt32x2 sample_probe_coord = sample_pixel_coord / 8u; + FfxUInt32 sample_probe_idx = sample_probe_coord.x + sample_probe_coord.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo sample_pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadStaticProbeInfo(sample_probe_idx)); + + if (FfxBrixelizerGIProbeSpawnInfoIsValid(sample_pinfo)) + { + FfxFloat32x3 sample_normal = sample_pinfo.normal; + FfxFloat32x3 sample_world_position = FfxBrixelizerGIProbeSpawnInfoGetPrevSpawnPosition(sample_pinfo); + FfxFloat32 weight = FfxBrixelizerGIWeight( // + pinfo.normal, // + sample_world_position, // + pinfo.normal, // + probe_pos, // + eps_size, // + FfxFloat32(4.0), // + FfxFloat32(1.0) + ); + if (weight > FfxFloat32(0.1)) + { + FfxUInt32 pack = FfxBrixelizerGIPackUnorm16(weight) << 16u; + + pack |= cell_idx; + lds_reprojected_probe_coords[cell_idx] = sample_probe_coord.x | (sample_probe_coord.y << 16); + FFX_ATOMIC_MIN(lds_reprojected_probe_score, pack); + } + } + } + + FFX_GROUP_MEMORY_BARRIER; + + FfxUInt32x2 cell = gid; + + if ((lds_reprojected_probe_score >> 16u) == 0xffffu) // fail; scalar + { + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X2(0)))) + { + StoreTempSpawnMask(probe_coord, 0); + StoreStaticScreenProbesStat(probe_coord, FFX_BROADCAST_FLOAT32X4(0.0)); + } + StoreStaticScreenProbes(tid, FFX_BROADCAST_FLOAT32X4(0.0)); + } + else + { + FfxUInt32 pack = lds_reprojected_probe_score; + FfxUInt32 pack_probe_coords = lds_reprojected_probe_coords[pack & 0xffffu]; + FfxUInt32x2 base_sample_probe_coord = FfxUInt32x2(pack_probe_coords & 0xffffu, (pack_probe_coords >> 16u) & 0xffffu); + FfxInt32 radius = 1; + FfxFloat32x4 sh_acc = FFX_BROADCAST_FLOAT32X4(0.0); + FfxFloat32 weight_acc = FfxFloat32(0.0); + //////////////////////// + // Irradiance sharing // + //////////////////////// + if (all(FFX_LESS_THAN(gid, FFX_BROADCAST_UINT32X2(3)))) + { + FfxInt32 x = FfxInt32(gid.x) - 1; + FfxInt32 y = FfxInt32(gid.y) - 1; + FfxInt32x2 sample_probe_coord = FfxInt32x2(base_sample_probe_coord) + FfxInt32x2(x, y); + + if (any(FFX_LESS_THAN(sample_probe_coord, FFX_BROADCAST_INT32X2(0))) || any(FFX_GREATER_THAN_EQUAL(sample_probe_coord, GetTileBufferDimensions()))) + { + lds_tile_weights[gid.x + gid.y * 3] = FfxFloat32(0.0); + } + else + { + FfxUInt32 sample_probe_idx = sample_probe_coord.x + sample_probe_coord.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo sample_pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadStaticProbeInfo(sample_probe_idx)); + + if (FfxBrixelizerGIProbeSpawnInfoIsValid(sample_pinfo)) + { + FfxFloat32x3 sample_normal = sample_pinfo.normal; + FfxFloat32x3 sample_world_position = FfxBrixelizerGIProbeSpawnInfoGetPrevSpawnPosition(sample_pinfo); + FfxFloat32 weight = FfxBrixelizerGIWeight(pinfo.normal, // + sample_world_position, // + pinfo.normal, // + probe_pos, // + eps_size * FfxFloat32(2.0), // + FfxFloat32(16.0), // + FfxFloat32(16.0) // + ); + lds_tile_weights[gid.x + gid.y * 3] = weight; + } + else + lds_tile_weights[gid.x + gid.y * 3] = FfxFloat32(0.0); + } + } + FFX_GROUP_MEMORY_BARRIER; + + for (FfxInt32 y = -radius; y <= radius; y++) // scalar + { + for (FfxInt32 x = -radius; x <= radius; x++) // scalar + { + FfxFloat32 weight = lds_tile_weights[(x + 1) + (y + 1) * 3]; + if (weight < FfxFloat32(0.1)) + continue; // scalar + + FfxInt32x2 sample_probe_coord = FfxInt32x2(base_sample_probe_coord) + FfxInt32x2(x, y); + if (any(FFX_LESS_THAN(sample_probe_coord, FFX_BROADCAST_INT32X2(0))) || any(FFX_GREATER_THAN_EQUAL(sample_probe_coord, GetTileBufferDimensions()))) + continue; // scalar + + FfxUInt32 sample_probe_idx = sample_probe_coord.x + sample_probe_coord.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo sample_pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadStaticProbeInfo(sample_probe_idx)); + + FFX_ATOMIC_ADD(lds_reprojected_reprojected_cnt, 1u); + weight_acc += weight; + + // Parallax corrected reprojection + FfxFloat32x3 sample_world_position = FfxBrixelizerGIProbeSpawnInfoGetPrevSpawnPosition(sample_pinfo); + FfxFloat32x3 sample_ray_direction = FfxBrixelizerGIProbeSpawnInfoGetRayUnjitteredDirection(sample_pinfo, cell); + FfxFloat32x4 probe_radiance = LoadStaticScreenProbesSRV(sample_probe_coord * 8u + cell); + FfxFloat32x3 hit_point = sample_world_position + sample_ray_direction * probe_radiance.w; + FfxFloat32x3 reprojected_dir = hit_point - probe_pos; + FfxFloat32x3 hemisphere_transformed_dir = FfxBrixelizerGIProbeSpawnInfoProjectOnHemisphere(pinfo, normalize(reprojected_dir)); + + if (hemisphere_transformed_dir.z > FfxFloat32(0.0)) + { + FfxFloat32x2 uv = FfxBrixelizerGIHemioctToUV(hemisphere_transformed_dir); + uv = clamp(uv, 0.0f, 0.99f); + FfxUInt32x2 sample_cell_coord = FfxUInt32x2(floor(uv * FfxFloat32(8.0))); + FfxFloat32 quantized_weight = FfxFloat32(FfxUInt32(FfxFloat32(weight) * FfxFloat32(1.0e6))) * FfxFloat32(1.0e-6); + FfxUInt32x4 quantized_radiance = FfxBrixelizerGIQuantizeRadiance(quantized_weight * FfxFloat32x4(probe_radiance.xyz, length(reprojected_dir))); + FfxUInt32 sample_cell_idx = sample_cell_coord.x + sample_cell_coord.y * 8u; + FFX_ATOMIC_ADD(lds_reprojected_probe_x[sample_cell_idx], quantized_radiance.x); + FFX_ATOMIC_ADD(lds_reprojected_probe_y[sample_cell_idx], quantized_radiance.y); + FFX_ATOMIC_ADD(lds_reprojected_probe_z[sample_cell_idx], quantized_radiance.z); + FFX_ATOMIC_ADD(lds_reprojected_probe_w[sample_cell_idx], quantized_radiance.w); + FFX_ATOMIC_ADD(lds_reprojected_probe_num_samples[sample_cell_idx], FfxUInt32(FfxFloat32(quantized_weight) * 1.0e6)); + } + if (sh_index < 9) + sh_acc += weight * ffxUnpackF32x2(LoadStaticProbeSHBuffer(9 * sample_probe_idx + sh_index)); + } + } + + FFX_GROUP_MEMORY_BARRIER; + + FfxBoolean any_reproj = lds_reprojected_reprojected_cnt != 0; + + if (any_reproj) // scalar + { + if (sh_index < 9) + StoreTempProbeSHBuffer(9 * probe_idx + sh_index, ffxPackF32x2(sh_acc / ffxMax(weight_acc, FfxFloat32(1.0e-3)))); + + FfxFloat32x4 resolved_history = FfxBrixelizerGIRecoverRadiance(FfxUInt32x4( + lds_reprojected_probe_x[cell_idx], + lds_reprojected_probe_y[cell_idx], + lds_reprojected_probe_z[cell_idx], + lds_reprojected_probe_w[cell_idx])) + / ffxMax(FfxFloat32(1.0e-6), FfxFloat32(lds_reprojected_probe_num_samples[cell_idx]) * FfxFloat32(1.0e-6)); + FFX_GROUP_MEMORY_BARRIER; + + FfxBrixelizerGILDS_StoreRadiance(FfxInt32x2(gid.xy), FfxFloat32x4(resolved_history.xyz, resolved_history.w < FfxFloat32(1.0e-3) ? FfxFloat32(0.0f) : FfxFloat32(1.0f))); + + FFX_GROUP_MEMORY_BARRIER; + + for (FfxInt32 i = FfxInt32(2); i <= FfxInt32(8); i = i * 2) + { + FfxInt32 ox = FfxInt32(gid.x) * i; + FfxInt32 oy = FfxInt32(gid.y) * i; + FfxInt32 ix = FfxInt32(gid.x) * i + i / FfxInt32(2); + FfxInt32 iy = FfxInt32(gid.y) * i + i / FfxInt32(2); + + if (ix < 8 && iy < 8) + { + FfxFloat32x4 rad_weight00 = FfxBrixelizerGILDS_LoadRadiance(FfxInt32x2(ox, oy)); + FfxFloat32x4 rad_weight10 = FfxBrixelizerGILDS_LoadRadiance(FfxInt32x2(ox, iy)); + FfxFloat32x4 rad_weight01 = FfxBrixelizerGILDS_LoadRadiance(FfxInt32x2(ix, oy)); + FfxFloat32x4 rad_weight11 = FfxBrixelizerGILDS_LoadRadiance(FfxInt32x2(ix, iy)); + FfxFloat32x4 sum = rad_weight00 + rad_weight01 + rad_weight10 + rad_weight11; + FfxBrixelizerGILDS_StoreRadiance(FfxInt32x2(ox, oy), sum.xyzw); + } + + FFX_GROUP_MEMORY_BARRIER; + } + + FfxFloat32x4 stat = FfxBrixelizerGILDS_LoadRadiance(FfxInt32x2(0, 0)); + + if (resolved_history.w < FfxFloat32(1.0e-1)) + resolved_history = stat.xyzw / ffxMax(FfxFloat32(1.0e-3), stat.w); + + StoreStaticScreenProbes(tid, resolved_history); + + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X2(0)))) + { + StoreStaticScreenProbesStat(probe_coord, stat.xyzw / ffxMax(FfxFloat32(1.0e-3), stat.w)); + StoreTempSpawnMask(probe_coord, 1); + } + } + else + { + if (all(FFX_EQUAL(gid, FFX_BROADCAST_UINT32X2(0)))) + { + StoreStaticScreenProbesStat(probe_coord, FFX_BROADCAST_FLOAT32X4(0)); + StoreTempSpawnMask(probe_coord, 0); + } + StoreStaticScreenProbes(tid, FFX_BROADCAST_FLOAT32X4(0.0)); + } + } +} + +struct RaySetup +{ + FfxUInt32x2 target_pixel_coord; + FfxFloat32x3 ray_direction; + FfxFloat32x3 ray_origin; + FfxFloat32x3 normal; + FfxBoolean valid; +}; + +RaySetup FfxBrixelizerGIGetRaySetup(FfxUInt32x2 tid) +{ + FfxUInt32x2 cell = tid % 8; + FfxUInt32x2 target_pixel_coord = tid; + FfxUInt32x2 probe_screen_offset = FfxBrixelizerGIRoundDown(target_pixel_coord, 8u); + FfxUInt32x2 probe_coord = target_pixel_coord / 8u; + FfxUInt32 probe_idx = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + probe_idx = ffxWaveReadLaneFirstU1(probe_idx); + FfxUInt32x4 probe_pack = LoadTempProbeInfo(probe_idx); + + if (all(FFX_EQUAL(cell, FFX_BROADCAST_UINT32X2(0)))) + StoreStaticProbeInfo(probe_idx, probe_pack); + + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(probe_pack); + + FfxFloat32x3 ray_direction = FfxBrixelizerGIProbeSpawnInfoGetRayDirection(pinfo, probe_coord, cell); + FfxFloat32x3 world_pos = FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo); + + RaySetup rs; + rs.ray_direction = ray_direction; + rs.ray_origin = world_pos; + rs.target_pixel_coord = target_pixel_coord; + rs.normal = pinfo.normal; + rs.valid = FfxBrixelizerGIProbeSpawnInfoIsValid(pinfo); + + return rs; +} + +// 8x8 group or 2x32 waves +void FfxBrixelizerGIFillScreenProbes(FfxUInt32x2 tid) +{ + FfxUInt32x2 gid = tid % 8; + RaySetup rs = FfxBrixelizerGIGetRaySetup(tid); + FfxUInt32x2 pixel_coord = rs.target_pixel_coord; + FfxUInt32x2 probe_coord = pixel_coord / 8u; + probe_coord = ffxWaveReadLaneFirstU2(probe_coord); // scalar + FfxUInt32 probe_idx = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadStaticProbeInfo(probe_idx)); + + if (!FfxBrixelizerGIProbeSpawnInfoIsValid(pinfo)) // scalar + return; + + FfxFloat32x4 history = LoadStaticScreenProbesSRV(rs.target_pixel_coord); + + FfxBoolean successfull_reproj = LoadTempSpawnMask(probe_coord) == 1; + FfxBoolean skip = ffxWaveReadLaneFirstB1(!FfxBrixelizerGIIsCheckerboard(tid) && successfull_reproj); + + if (skip) // Scalar early out if reprojection was successful + { + StoreStaticScreenProbes(rs.target_pixel_coord, history); + return; + } + + FfxBrixelizerHitRaw hit; + + FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade(); + FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + FfxFloat32 total_pushoff = pinfo.pushoff; + + FfxUInt32 start_cascade_idx = g_starting_cascade; + + FfxBrixelizerRayDesc ray; + ray.start_cascade_id = start_cascade_idx; + ray.end_cascade_id = g_end_cascade; + ray.t_min = GetTracingConstantsTMin(); + ray.t_max = GetTracingConstantsTMax(); + ray.origin = rs.ray_origin + (rs.normal * total_pushoff); + ray.direction = rs.ray_direction; + + FfxFloat32x3 cursor = ray.origin; + + FfxFloat32 origin_distance = length(ray.origin - GetCameraPosition()); + // leak check + FfxFloat32x3 ray_origin_uvz = ffxProjectPosition(ray.origin, GetViewProjectionMatrix()); + ray_origin_uvz.xy = ffxSaturate(ray_origin_uvz.xy); // clamp to border + FfxFloat32 depth = SampleDepth(ray_origin_uvz.xy); + + FfxFloat32x3 screen_world_pos = ffxGetWorldPosition(ray_origin_uvz.xy, depth); + FfxFloat32 screen_ray_length = length(screen_world_pos - GetCameraPosition()); + + s_sdf_solve_eps = GetTracingConstantsSDFSolveEpsilon() / FfxFloat32(8.0); + + FfxBoolean ray_hit = FfxBrixelizerTraverseRaw(ray, hit); + FfxFloat32x4 radiance = FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0)); + FfxUInt32x2 pack = FfxUInt32x2(hit.brick_id, hit.uvwc); + FfxUInt32 brick_id = pack.x; + + { + // XXX -- the following should be if (!ray_hit) { ... } else { ... } + // but has been changed to if (!ray_hit) { ... } if (ray_hit) { ... } + // to avoid a compiler bug resulting in a TDR on certain driver versions + + if (!ray_hit) + radiance = FfxFloat32x4(SampleEnvironmentMap(rs.ray_direction), FfxFloat32(128.0)); + + if (ray_hit) + { + FfxFloat32x3 uvw = FfxFloat32x3( // + FfxBrixelizerUnpackUnsigned8Bits((pack.y >> 0) & 0xff), // + FfxBrixelizerUnpackUnsigned8Bits((pack.y >> 8) & 0xff), // + FfxBrixelizerUnpackUnsigned8Bits((pack.y >> 16) & 0xff) // + ); + uvw += FFX_BROADCAST_FLOAT32X3(1.0 / 512.0); + FfxUInt32 voxel_id = LoadBricksVoxelMap(FfxBrixelizerBrickGetIndex(brick_id)); + FfxUInt32 cascade_id = FfxBrixelizerGetVoxelCascade(voxel_id); + FfxBrixelizerCascadeInfo cinfo = GetCascadeInfo(cascade_id); + FfxUInt32 voxel_offset = FfxBrixelizerVoxelGetIndex(voxel_id); + FfxUInt32x3 voxel_coord = FfxBrixelizerUnflattenPOT(voxel_offset, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxFloat32x3 voxel_min = FfxFloat32x3(voxel_coord) * cinfo.voxel_size + cinfo.grid_min; + FfxFloat32x3 hit_world_offset = voxel_min + uvw * cinfo.voxel_size; + FfxBxAtlasBounds atlas_bounds = FfxBrixelizerGetAtlasBounds(brick_id); + + radiance.xyz = FfxBrixelizerGISampleRadianceCacheSH(brick_id, rs.ray_direction); + + radiance = FfxFloat32x4(radiance.xyz, length(hit_world_offset - rs.ray_origin)); + } + } + + FfxFloat32 temporal_blend = FfxFloat32(1.0 / 4.0); // UPDATED! + + if (ffxAsUInt32(history.w) == FfxUInt32(0)) + temporal_blend = FfxFloat32(1.0); + + radiance.xyzw = ffxLerp(history.xyzw, radiance.xyzw, temporal_blend); + + FfxFloat32x4 stat = LoadStaticScreenProbesStat(probe_coord); + + if (any(FFX_NOT_EQUAL(ffxAsUInt32(stat), FFX_BROADCAST_UINT32X4(0)))) + radiance.xyz = FfxBrixelizerGIClipAABB(radiance.xyz, stat.xyz, FfxFloat32(0.3)); // crude firefly removal + + StoreStaticScreenProbes(rs.target_pixel_coord, radiance); +} + +// Transform 8x8 octahedral encoding into spherical harmonics +void FfxBrixelizerGIReprojectGI(FfxUInt32x2 tid) +{ + if (all(FFX_LESS_THAN(tid, GetBufferDimensions()))) + { + + FfxFloat32x2 mv = FfxBrixelizerGIFindClosestMotionVector(tid); + FfxFloat32x2 history_uv = FfxBrixelizerGIGetUV(tid) + mv; + + if (any(FFX_LESS_THAN(history_uv, FFX_BROADCAST_FLOAT32X2(0.0))) || any(FFX_GREATER_THAN(history_uv, FFX_BROADCAST_FLOAT32X2(1.0)))) + { + StoreStaticGITarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + StoreSpecularTarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); +#endif + return; + } + + FfxFloat32x2 history_uv_scaled = history_uv * GetBufferDimensionsF32(); + + FfxFloat32x3 pixel_normal = LoadWorldNormal(tid); + FfxFloat32 pixel_depth = LoadDepth(tid); + + if (ffxIsBackground(pixel_depth)) + { + StoreStaticGITarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + StoreSpecularTarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); +#endif + return; + } + + FfxFloat32x2 pixel_uv = FfxBrixelizerGIGetUV(tid); + FfxFloat32x3 pixel_world_pos = ffxGetWorldPosition(pixel_uv, pixel_depth); + + FfxBoolean disoccluded = LoadDisocclusionMask(tid) > 0; + + if (disoccluded) + { + StoreStaticGITarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + StoreSpecularTarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); +#endif + } + else + { + StoreStaticGITarget(tid, SampleStaticGITargetSRV(history_uv)); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + StoreSpecularTarget(tid, SampleSpecularTargetSRV(history_uv)); +#endif + } + } +} + +FFX_GROUPSHARED FfxUInt32x2 lds_probe_sh_buffer[9 * 8 * 8]; // (1, 3, 5) coefficients for 3 bands of SH + +// 8x8 group +FfxUInt32 FfxBrixelizerGIGetSHIndex(FfxUInt32x2 xy) +{ + return xy.x + xy.y * 8; +} + +FfxUInt32 FfxBrixelizerGIGetSHLDSIndex(FfxUInt32x2 xy, FfxUInt32 sh_index) +{ + return 9 * FfxBrixelizerGIGetSHIndex(xy) + sh_index; +} + +// Transform 8x8 octahedral encoding into spherical harmonics +// void FfxBrixelizerGIProjectScreenProbes(FfxUInt32 group_idx, FfxUInt32x2 gid) +void FfxBrixelizerGIProjectScreenProbes(FfxUInt32x2 tid, FfxUInt32x2 gid) +{ + FfxUInt32x2 probe_screen_offset = FfxBrixelizerGIRoundDown(tid, 8u); + FfxUInt32x2 probe_coord = tid / 8u; + FfxUInt32 probe_idx = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadTempProbeInfo(probe_idx)); + + if (!FfxBrixelizerGIProbeSpawnInfoIsValid(pinfo)) // scalar + return; + + FfxFloat32x3 ray_direction = FfxBrixelizerGIProbeSpawnInfoGetRayDirection(pinfo, probe_coord, gid); + FfxFloat32x3 world_pos = FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo); + FfxFloat32x4 radiance = LoadStaticScreenProbesSRV(tid); + + FfxFloat32x4 stat = LoadStaticScreenProbesStat(probe_coord); + + if (all(FFX_EQUAL(ffxAsUInt32(radiance), FFX_BROADCAST_UINT32X4(0)))) + radiance = stat; + + FfxFloat32 direction_sh[9]; + FfxBrixelizerGISHGetCoefficients(ray_direction, direction_sh); + + FfxFloat32 c = dot(ray_direction, pinfo.normal); + + for (FfxUInt32 j = 0; j < 9; j++) + lds_probe_sh_buffer[FfxBrixelizerGIGetSHLDSIndex(gid, j)] = ffxPackF32x2(FfxFloat32x4(direction_sh[j] * radiance.xyz * c, FfxFloat32(1.0))); + + FFX_GROUP_MEMORY_BARRIER; + + FfxUInt32 sh_offset = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + + for (FfxInt32 sh_index = 0; sh_index < 9; sh_index++) + { + for (FfxInt32 i = 0; i < 3; i++) + { + FfxUInt32 stride = 1 << (i + 1); // 2 4 8 + + if (all(FFX_LESS_THAN(gid, FFX_BROADCAST_UINT32X2(8 / stride)))) // 4 2 1 + { + FFX_MIN16_F4 a00 = FFX_MIN16_F4(ffxUnpackF32x2(lds_probe_sh_buffer[FfxBrixelizerGIGetSHLDSIndex(gid.xy * stride + FfxUInt32x2(0, 0), sh_index)])); + FFX_MIN16_F4 a10 = FFX_MIN16_F4(ffxUnpackF32x2(lds_probe_sh_buffer[FfxBrixelizerGIGetSHLDSIndex(gid.xy * stride + FfxUInt32x2(stride / 2, 0), sh_index)])); + FFX_MIN16_F4 a01 = FFX_MIN16_F4(ffxUnpackF32x2(lds_probe_sh_buffer[FfxBrixelizerGIGetSHLDSIndex(gid.xy * stride + FfxUInt32x2(0, stride / 2), sh_index)])); + FFX_MIN16_F4 a11 = FFX_MIN16_F4(ffxUnpackF32x2(lds_probe_sh_buffer[FfxBrixelizerGIGetSHLDSIndex(gid.xy * stride + FfxUInt32x2(stride / 2, stride / 2), sh_index)])); + lds_probe_sh_buffer[FfxBrixelizerGIGetSHLDSIndex(gid.xy * stride, sh_index)] = ffxPackF32x2(FfxFloat32x4(a00 + a01 + a10 + a11)); + } + } + } + FFX_GROUP_MEMORY_BARRIER; + + FfxUInt32 thread_sh_index = gid.x + gid.y * 8; + + if (thread_sh_index < 9) + { + FfxFloat32x4 irradiance_history = ffxUnpackF32x2(LoadTempProbeSHBuffer(9 * sh_offset + thread_sh_index)); + FfxFloat32x4 irradiance_sh = ffxUnpackF32x2(lds_probe_sh_buffer[FfxBrixelizerGIGetSHLDSIndex(FfxUInt32x2(0, 0), thread_sh_index)]); + + irradiance_sh.w = FfxFloat32(1.0); + + StoreTempProbeSHBuffer(9 * sh_offset + thread_sh_index, ffxPackF32x2(irradiance_sh)); + } +} + +void FfxBrixelizerGIEmitIrradianceCache(FfxUInt32x2 tid) +{ + FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade(); + FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + FfxUInt32x2 probe_coord = tid; + FfxUInt32 probe_idx = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadTempProbeInfo(probe_idx)); + + if (!FfxBrixelizerGIProbeSpawnInfoIsValid(pinfo)) // scalar + return; + + FfxFloat32x3 world_pos = FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo); + FfxFloat32x3 ray = normalize(world_pos - GetCameraPosition()); + FfxFloat32 xi = FfxFloat32(FfxBrixelizerGIpcg(tid.x + FfxBrixelizerGIpcg(tid.y + FfxBrixelizerGIpcg(GetFrameIndex()))) & 0xffu) / FfxFloat32(255.0); + FfxUInt32 sh_offset = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + + FfxFloat32x4 input_sh[9]; + + for (FfxInt32 i = 0; i < 9; i++) + input_sh[i] = ffxUnpackF32x2(LoadTempProbeSHBuffer(9 * sh_offset + i)); + + FfxBrixelizerGIEmitIrradiance(world_pos, pinfo.normal, normalize(-ray + pinfo.normal), input_sh, xi, g_starting_cascade, g_end_cascade); + + for (FfxUInt32 i = 0; i < 9; i++) + StoreStaticProbeSHBuffer(9 * sh_offset + i, ffxPackF32x2(input_sh[i])); +} + +void FfxBrixelizerGIBlendSH(FfxUInt32x2 tid) +{ + if (any(FFX_GREATER_THAN_EQUAL(tid, GetTileBufferDimensions()))) + return; + + FfxInt32 radius = 0; + FfxFloat32x4 acc[9]; + + for (FfxUInt32 i = 0; i < 9; i++) + acc[i] = FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0)); + + FfxFloat32 weight_sum = FfxFloat32(0.0); + + for (FfxInt32 y = -radius; y <= radius; y++) + { + for (FfxInt32 x = -radius; x <= radius; x++) + { + FfxInt32x2 sample_coord = FfxInt32x2(tid) + FfxInt32x2(x, y); + + if (any(FFX_LESS_THAN(sample_coord, FFX_BROADCAST_INT32X2(0))) || any(FFX_GREATER_THAN(sample_coord, GetTileBufferDimensions()))) + continue; + + FfxUInt32 sh_offset = sample_coord.x + sample_coord.y * GetTileBufferDimensions().x; + FfxFloat32 weight = FfxFloat32(1.0) / (1.0 + FfxFloat32(x * x) + FfxFloat32(y * y)); + + for (FfxUInt32 i = 0; i < 9; i++) + acc[i] += weight * ffxUnpackF32x2(LoadTempProbeSHBuffer(9 * sh_offset + i)); + + weight_sum += weight; + } + } + + FfxUInt32 sh_offset = tid.x + tid.y * GetTileBufferDimensions().x; + + for (FfxUInt32 i = 0; i < 9; i++) + { + acc[i] /= ffxMax(FfxFloat32(1.0e-3), weight_sum); + acc[i].w = FfxFloat32(1.0); + + StoreStaticProbeSHBuffer(9 * sh_offset + i, ffxPackF32x2(acc[i])); + } +} + +#define FfxBrixelizerGIMAX_SAMPLES FfxFloat32(64.0) +#define FfxBrixelizerGIMAX_SPECULAR_SAMPLES FfxFloat32(32.0) + +FfxFloat32 FfxBrixelizerGIComputeTemporalVariance(FfxFloat32x3 history_radiance, FfxFloat32x3 radiance) +{ + FfxFloat32 history_luminance = FfxBrixelizerGIGetLuminance(history_radiance); + FfxFloat32 luminance = FfxBrixelizerGIGetLuminance(radiance); + FfxFloat32 diff = abs(history_luminance - luminance) / ffxMax(ffxMax(history_luminance, luminance), FfxFloat32(0.5)); + return diff * diff; +} + +void FfxBrixelizerGISpecularPreTrace(FfxUInt32x2 quarter_res_tid) +{ + FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade(); + FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + const FfxUInt32 max_num_points = 64; + FfxUInt32x2 full_res_tid = quarter_res_tid * 4 + FfxUInt32x2(FfxBrixelizerGIHammersley( // + (FfxBrixelizerGIpcg(GetFrameIndex()) + FfxBrixelizerGIpcg(quarter_res_tid.x + FfxBrixelizerGIpcg(quarter_res_tid.y))) & (max_num_points - 1), + max_num_points) + * FfxFloat32(4.0)); + + FfxRay base_ray = FfxBrixelizerGIGenReflectionRay(full_res_tid, quarter_res_tid); + FfxFloat32 ray_pushoff = GetTracingConstantsSpecularRayPushoff(); + FfxFloat32 total_pushoff = ray_pushoff * FfxBrixelizerGIGetVoxelSize(base_ray.origin, g_starting_cascade, g_end_cascade, FfxFloat32(0.0)); + + if (base_ray.valid) + { + FfxBrixelizerRayDesc ray; + ray.start_cascade_id = g_starting_cascade; + ray.end_cascade_id = g_end_cascade; + ray.t_min = GetTracingConstantsTMin(); + ray.t_max = GetTracingConstantsTMax(); + ray.direction = base_ray.direction; + ray.origin = base_ray.origin + (base_ray.normal) * total_pushoff; // + aoray.direction + s_sdf_solve_eps = GetTracingConstantsSpecularSDFSolveEpsilon() / FfxFloat32(8.0); + + FfxBrixelizerHitRaw hit; + hit.brick_id = FFX_BRIXELIZER_INVALID_ID; + hit.uvwc = 0; + + FfxBoolean out_of_budget = !FfxBrixelizerTraverseRaw(ray, hit); + + if (FfxBrixelizerIsValidID(hit.brick_id)) + StoreTempSpecularPretraceTarget(quarter_res_tid * FfxUInt32x2(1, 1), FfxUInt32x4((1 << 24u) | hit.brick_id, 0, 0, 0)); + else + StoreTempSpecularPretraceTarget(quarter_res_tid * FfxUInt32x2(1, 1), FFX_BROADCAST_UINT32X4(out_of_budget ? 0xffffffffu : 0)); + + } + else + StoreTempSpecularPretraceTarget(quarter_res_tid * FfxUInt32x2(1, 1), FFX_BROADCAST_UINT32X4(0)); +} + +void PushSpecularRay(FfxUInt32x2 tid) +{ + FfxUInt32 pack = tid.x | (tid.y << 16u); + FfxUInt32 offset; + IncrementRaySwapIndirectArgs(0, 1, offset); + StoreTempSpecularRaySwap(offset, pack); +} + +FfxUInt32x2 LoadSpecularRay(FfxUInt32 tid) +{ + FfxUInt32 pack = LoadTempSpecularRaySwap(tid); + return FfxUInt32x2(pack & 0xffffu, (pack >> 16u) & 0xffffu); +} + +void FfxBrixelizerGISpecularTrace(FfxUInt32x2 tid) +{ + FfxFloat32 xi = FfxFloat32((FfxBrixelizerGIpcg(GetFrameIndex()) + FfxBrixelizerGIpcg(tid.x + FfxBrixelizerGIpcg(tid.y))) & 0xff) / FfxFloat32(255.0); + + FfxRay base_ray = FfxBrixelizerGIGenReflectionRay(tid, tid); + FfxFloat32 ray_pushoff = GetTracingConstantsSpecularRayPushoff(); + FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade() + 2; + FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + FfxFloat32 total_pushoff = ray_pushoff * FfxBrixelizerGIGetVoxelSize(base_ray.origin, g_starting_cascade, g_end_cascade, FfxFloat32(0.0)); + + s_sdf_solve_eps = GetTracingConstantsSpecularSDFSolveEpsilon() / FfxFloat32(8.0); + + FfxFloat32x3 ray_direction = base_ray.direction; + FfxFloat32x3 ray_origin = base_ray.origin + (base_ray.normal) * total_pushoff; + FfxFloat32x3 ray_idirection = FfxFloat32(1.0) / ray_direction; + const FfxInt32 NUM_TAP_COORDS = 5; + + FfxInt32x2 coords[NUM_TAP_COORDS] = { + FfxInt32x2(0, 0), // + FfxInt32x2(1, 0), // + FfxInt32x2(-1, 0), // + FfxInt32x2(0, 1), // + FfxInt32x2(0, -1), // + }; + const FfxUInt32 MAX_TAPS = 5; + + FfxUInt32x2 packs[MAX_TAPS]; + FfxUInt32 num_samples = 0; + + FfxInt32x2 xy = FfxInt32x2(tid / 4); + FfxUInt32x4 pretrace = LoadTempSpecularPretraceTarget(xy * FfxUInt32x2(1, 1)); + + if (pretrace.x != 0 && pretrace.x != 0xffffffffu) + { + FfxUInt32 brick_id = pretrace.x & 0x00ffffffu; + FfxUInt32 voxel_id = LoadBricksVoxelMap(FfxBrixelizerBrickGetIndex(brick_id)); + FfxUInt32 cascade_id = FfxBrixelizerGetVoxelCascade(voxel_id); + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfoNonUniform(cascade_id); + FfxUInt32 voxel_offset = FfxBrixelizerVoxelGetIndex(voxel_id); + FfxUInt32x3 voxel_coord = FfxBrixelizerUnflattenPOT(voxel_offset, FFX_BRIXELIZER_CASCADE_DEGREE); + FfxFloat32x3 voxel_min = FfxFloat32x3(voxel_coord) * CINFO.voxel_size + CINFO.grid_min; + FfxUInt32 brick_aabb_pack = LoadBricksAABB(FfxBrixelizerBrickGetIndex(brick_id)); + FfxUInt32x3 brick_aabb_umin = FfxBrixelizerUnflattenPOT(brick_aabb_pack & ((1 << 9) - 1), 3); + FfxUInt32x3 brick_aabb_umax = FfxBrixelizerUnflattenPOT((brick_aabb_pack >> 9) & ((1 << 9) - 1), 3) + FFX_BROADCAST_UINT32X3(1); + FfxFloat32x3 brick_aabb_min = voxel_min - FFX_BROADCAST_FLOAT32X3(CINFO.voxel_size / FfxFloat32(2.0 * 7.0)) + FfxFloat32x3(brick_aabb_umin) * (CINFO.voxel_size / FfxFloat32(7.0)); + FfxFloat32x3 brick_aabb_max = voxel_min - FFX_BROADCAST_FLOAT32X3(CINFO.voxel_size / FfxFloat32(2.0 * 7.0)) + FfxFloat32x3(brick_aabb_umax) * (CINFO.voxel_size / FfxFloat32(7.0)); + + brick_aabb_min = clamp(brick_aabb_min, voxel_min, voxel_min + FFX_BROADCAST_FLOAT32X3(CINFO.voxel_size)); + brick_aabb_max = clamp(brick_aabb_max, voxel_min, voxel_min + FFX_BROADCAST_FLOAT32X3(CINFO.voxel_size)); + FfxFloat32 brick_hit_min = FfxFloat32(0.0); + FfxFloat32 brick_hit_max = FfxFloat32(0.0); + + if (FfxBrixelizerIntersectAABB(ray_origin, ray_idirection, brick_aabb_min, brick_aabb_max, + /* out */ brick_hit_min, + /* out */ brick_hit_max)) + { + FfxFloat32x3 ray_cursor = ray_origin + ray_direction * (brick_hit_min); + FfxFloat32x3 uvw = (ray_cursor - voxel_min) * CINFO.ivoxel_size; + FfxFloat32 dist = FfxFloat32(1.0); + FfxFloat32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxFloat32x3 uvw_min = (brick_offset + FFX_BROADCAST_FLOAT32X3(FfxFloat32(0.5))) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE); + FfxFloat32x3 uvw_max = uvw_min + FFX_BROADCAST_FLOAT32X3(FfxFloat32(7.0)) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE); + + for (FfxUInt32 i = 0; i < 8; i++) + { + dist = FfxBrixelizerSampleBrixelDistance(uvw_min, uvw_max, uvw) - FFX_BRIXELIZER_TRAVERSAL_EPS; + + if (dist < FFX_BRIXELIZER_TRAVERSAL_EPS) + { + StoreSpecularTarget(tid, FfxFloat32x4(FfxBrixelizerGISampleRadianceCache(brick_id, uvw), FfxFloat32(1.0))); + return; + } + + uvw += ray_direction * dist; + + if (any(FFX_GREATER_THAN(abs(uvw - FFX_BROADCAST_FLOAT32X3(0.5)), FFX_BROADCAST_FLOAT32X3(0.501)))) + break; + } + } + else + StoreSpecularTarget(tid, FfxFloat32x4(0.0, 0.0, 0.0, 0.0)); + } + else + StoreSpecularTarget(tid, FfxFloat32x4(0.0, 0.0, 0.0, 0.0)); +} + +void FfxBrixelizerGISpecularLoadNeighborhood( + FfxInt32x2 pixel_coordinate, + out FFX_MIN16_F4 radiance, + out FFX_MIN16_F3 normal, + out FfxFloat32 depth, + FfxUInt32x2 screen_size) +{ + radiance = FFX_MIN16_F4(LoadSpecularTarget(pixel_coordinate)); + normal = FFX_MIN16_F3(LoadWorldNormal(pixel_coordinate)); + FfxFloat32x2 uv = (pixel_coordinate.xy + (0.5).xx) / FfxFloat32x2(screen_size.xy); + depth = LoadDepth(pixel_coordinate); +} + +FFX_GROUPSHARED FfxUInt32x4 g_ffx_dnsr_shared[16][16]; +FFX_GROUPSHARED FfxFloat32 g_ffx_dnsr_shared_depth[16][16]; + +struct FfxBrixelizerGISpecularNeighborhoodSample +{ + FFX_MIN16_F4 radiance; + FFX_MIN16_F3 normal; + FfxFloat32 depth; +}; + +FfxFloat32x3 SpecularNeighborhoodSampleGetWorldPos(in FfxBrixelizerGISpecularNeighborhoodSample s, FfxFloat32x2 uv) +{ + return ffxGetWorldPosition(uv, s.depth); +} + +FfxBrixelizerGISpecularNeighborhoodSample FfxBrixelizerGISpecularLoadFromGroupSharedMemory(FfxInt32x2 idx) +{ + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared[idx.y][idx.x].x, g_ffx_dnsr_shared[idx.y][idx.x].y); + FFX_MIN16_F4 unpacked_radiance = FFX_MIN16_F4(ffxUnpackF32x2(packed_radiance)); + FfxUInt32x2 packed_normal_variance = FfxUInt32x2(g_ffx_dnsr_shared[idx.y][idx.x].z, g_ffx_dnsr_shared[idx.y][idx.x].w); + FFX_MIN16_F4 unpacked_normal_variance = FFX_MIN16_F4(ffxUnpackF32x2(packed_normal_variance)); + + FfxBrixelizerGISpecularNeighborhoodSample specSample; + specSample.radiance = unpacked_radiance.xyzw; + specSample.normal = unpacked_normal_variance.xyz; + specSample.depth = g_ffx_dnsr_shared_depth[idx.y][idx.x]; + return specSample; +} + +void FfxBrixelizerGISpecularStoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FFX_MIN16_F4 radiance, FFX_MIN16_F3 normal, FfxFloat32 depth) +{ + g_ffx_dnsr_shared[group_thread_id.y][group_thread_id.x].x = ffxPackF32(FfxFloat32x2(radiance.xy)); + g_ffx_dnsr_shared[group_thread_id.y][group_thread_id.x].y = ffxPackF32(FfxFloat32x2(radiance.zw)); + g_ffx_dnsr_shared[group_thread_id.y][group_thread_id.x].z = ffxPackF32(FfxFloat32x2(normal.xy)); + g_ffx_dnsr_shared[group_thread_id.y][group_thread_id.x].w = ffxPackF32(FfxFloat32x2(normal.z, FFX_MIN16_F(0.0))); + g_ffx_dnsr_shared_depth[group_thread_id.y][group_thread_id.x] = depth; +} + +void FfxBrixelizerGISpecularInitializeGroupSharedMemory(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxInt32x2 screen_size) +{ + // Load 16x16 region into shared memory using 4 8x8 blocks. + FfxInt32x2 offset[4] = { FfxInt32x2(0, 0), FfxInt32x2(8, 0), FfxInt32x2(0, 8), FfxInt32x2(8, 8) }; + + // Intermediate storage registers to cache the result of all loads + FFX_MIN16_F4 radiance[4]; + FFX_MIN16_F3 normal[4]; + FfxFloat32 depth[4]; + + // Start in the upper left corner of the 16x16 region. + dispatch_thread_id -= 4; + + // First store all loads in registers + for (FfxInt32 i = 0; i < 4; ++i) + FfxBrixelizerGISpecularLoadNeighborhood(dispatch_thread_id + offset[i], radiance[i], normal[i], depth[i], screen_size); + + // Then move all registers to FFX_GROUPSHARED memory + for (FfxInt32 j = 0; j < 4; ++j) + FfxBrixelizerGISpecularStoreInGroupSharedMemory(group_thread_id + offset[j], radiance[j], normal[j], depth[j]); // X +} + +FFX_MIN16_F3 FfxBrixelizerGISampleWorldGI(FfxFloat32x3 world_pos, FfxFloat32 xi, FFX_MIN16_F cosine_sh[9]) +{ + FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade(); + FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + + FFX_MIN16_F4 probe_sh[9]; + + if (FfxBrixelizerGIInterpolateBrickSH(world_pos, g_starting_cascade, g_end_cascade, xi, /* inout */ probe_sh)) + { + FFX_MIN16_F3 cur_irradiance = FFX_BROADCAST_MIN_FLOAT16X3(0.0); + + for (FfxUInt32 i = 0; i < 9; i++) + cur_irradiance += cosine_sh[i] * probe_sh[i].xyz; + + return cur_irradiance / FFX_MIN16_F(FFX_BRIXELIZER_GI_PI * FfxFloat32(2.0)); + } + + return FFX_BROADCAST_MIN_FLOAT16X3(FFX_MIN16_F(0.0)); +} + +// 8x8 group +// Project 2x2 closest SH probes onto GBuffer normals, use irradiance ambient cache when projection fails +void FfxBrixelizerGIInterpolateScreenProbes(FfxUInt32x2 tid, FfxUInt32x2 gid) +{ + FfxUInt32x2 probe_screen_offset = FfxBrixelizerGIRoundDown(tid, 8u); + FfxUInt32x2 probe_coord = tid / 8u; + FfxUInt32 probe_idx = probe_coord.x + probe_coord.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadTempProbeInfo(probe_idx)); + + FfxFloat32x3 pixel_normal = LoadWorldNormal(tid); + FfxFloat32 pixel_depth = LoadDepth(tid); + FfxFloat32x2 pixel_uv = FfxBrixelizerGIGetUV(tid); + FfxFloat32x3 world_pos = ffxGetWorldPosition(pixel_uv, pixel_depth); + FfxFloat32x3 view = normalize(world_pos - GetCameraPosition()); + FfxFloat32 eps_size = FfxBrixelizerGIGetEps(world_pos); + FfxBoolean is_sky_pixel = ffxIsBackground(pixel_depth); + FfxUInt32 g_starting_cascade = GetTracingConstantsStartCascade(); + FfxUInt32 g_end_cascade = GetTracingConstantsEndCascade(); + FfxFloat32 xi = FfxFloat32(FfxBrixelizerGIpcg(tid.x + FfxBrixelizerGIpcg(tid.y + FfxBrixelizerGIpcg(GetFrameIndex()))) & 0xffu) / FfxFloat32(255.0); + + if (is_sky_pixel) + { + StoreStaticGITarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); + StoreSpecularTarget(tid, FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0))); + return; + } + + FfxFloat32x4 w = FFX_BROADCAST_FLOAT32X4(0.0); + FfxUInt32x4 probes = FFX_BROADCAST_UINT32X4(FFX_BRIXELIZER_GI_INVALID_ID); + + FfxInt32x2 offset = FfxInt32x2(tid.x < pinfo.seed_pixel.x ? -1 : 1, tid.y < pinfo.seed_pixel.y ? -1 : 1); + probes.x = FfxBrixelizerGIScreenProbes_FindClosestProbe(probe_coord, FfxInt32x2(0, 0)); + probes.y = FfxBrixelizerGIScreenProbes_FindClosestProbe(probe_coord, FfxInt32x2(offset.x, 0)); + probes.z = FfxBrixelizerGIScreenProbes_FindClosestProbe(probe_coord, FfxInt32x2(0, offset.y)); + probes.w = FfxBrixelizerGIScreenProbes_FindClosestProbe(probe_coord, offset); + + if (probes.y == probes.x) + probes.y = FFX_BRIXELIZER_GI_INVALID_ID; + if (probes.z == probes.y || probes.z == probes.x) + probes.z = FFX_BRIXELIZER_GI_INVALID_ID; + if (probes.w == probes.z || probes.w == probes.y || probes.w == probes.x) + probes.w = FFX_BRIXELIZER_GI_INVALID_ID; + + for (FfxUInt32 i = 0; i < 4; i++) + { + if (probes[i] != FFX_BRIXELIZER_GI_INVALID_ID) + { + FfxUInt32x2 pos = FfxUInt32x2(probes[i] & 0xffffu, (probes[i] >> 16u) & 0xffffu); + FfxUInt32 probe_idx = pos.x + pos.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadTempProbeInfo(probe_idx)); + FfxFloat32x3 probe_spawn_position = FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo); + FfxFloat32 dist = length(probe_spawn_position - world_pos); + + if (abs(dot(probe_spawn_position - world_pos, pixel_normal)) > eps_size) + w[i] = FfxFloat32(0.0); + else + w[i] = ffxPow(ffxSaturate(dot(pixel_normal, pinfo.normal)) * ffxSaturate(FfxFloat32(1.0) - dist / eps_size), FfxFloat32(8.0)); + } + } + + FfxRay base_ray = FfxBrixelizerGIGenReflectionRay(tid, tid); + FFX_MIN16_F cosine_sh[9]; + FFX_MIN16_F reflection_sh[9]; + + FfxFloat32 roughness = LoadRoughness(tid); + FfxBrixelizerGISHGetCoefficients_ClampedCosine16(pixel_normal, cosine_sh); + FfxBrixelizerGISHGetCoefficients_ClampedCosine16(base_ray.major_direction, reflection_sh); + + FfxFloat32x3 irradiance = FFX_BROADCAST_FLOAT32X3(0.0); + FfxFloat32x3 specular_irradiance = FFX_BROADCAST_FLOAT32X3(0.0); + FfxFloat32 num_diffuse_samples = 0; + +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_DENOISER == 0 + FfxFloat32x4 reprojected = LoadStaticGITargetSRV(tid); + num_diffuse_samples = ffxMin(FfxBrixelizerGIMAX_SAMPLES - FfxFloat32(1.0), reprojected.w); + FfxFloat32 temporal_weight = FfxFloat32(1.0) / (FfxFloat32(1.0) + num_diffuse_samples); // sample count weight, purely temporal +#endif + + FfxFloat32 weight_sum = FfxFloat32(0.0); + + for (FfxUInt32 j = 0; j < 4; j++) + { + if (probes[j] != FFX_BRIXELIZER_GI_INVALID_ID) + { + FfxUInt32x2 pos = FfxUInt32x2(probes[j] & 0xffffu, (probes[j] >> 16u) & 0xffffu); + FfxUInt32 probe_idx = pos.x + pos.y * GetTileBufferDimensions().x; + FfxBrixelizerGIProbeSpawnInfo pinfo = FfxBrixelizerGIProbeSpawnInfoUnpack(LoadTempProbeInfo(probe_idx)); + FfxFloat32x3 cur_irradiance = FFX_BROADCAST_FLOAT32X3(0.0); + + FfxFloat32x4 probe_sh[9]; + for (FfxUInt32 i = 0; i < 9; i++) + probe_sh[i] = ffxUnpackF32x2(LoadStaticProbeSHBuffer(9 * probe_idx + i)).xyzw; + + for (FfxUInt32 i = 0; i < 9; i++) + cur_irradiance += FfxFloat32(cosine_sh[i]) * probe_sh[i].xyz; + + FfxFloat32 weight = FfxFloat32(1.0); + FfxFloat32x3 probe_spawn_position = FfxBrixelizerGIProbeSpawnInfoGetSpawnPosition(pinfo); + + irradiance += w[j] * cur_irradiance * weight; + weight_sum += w[j] * weight; + } + } + + const FfxFloat32 EPS = FfxFloat32(1.0e-2); + irradiance /= (ffxMax(weight_sum, EPS) * FFX_BRIXELIZER_GI_PI * FfxFloat32(2.0)); + FfxFloat32 size_weight = ffxSaturate(eps_size / (GetContextInfo().cascades[0].voxel_size * FfxFloat32(64.0))); + FfxFloat32 total_sh_cache_weight = ffxSaturate(ffxLerp(FfxFloat32(1.0), FfxFloat32(0.0), size_weight) - ffxSaturate(FfxFloat32(1.0) - dot(pixel_normal, -view))); + + FFX_MIN16_F4 probe_sh[9]; + StoreDebugTarget(tid, FfxFloat32x4(0.0, 0.0, 0.0, 1.0)); + + FfxBoolean has_world_probe = FfxBrixelizerGIInterpolateBrickSH(world_pos, g_starting_cascade, g_end_cascade, xi, /* inout */ probe_sh); + + if (has_world_probe) + { + // if (probe_sh[0].w > FfxFloat32(4.0)) + { + if (weight_sum < FfxFloat32(1.0e-3)) + total_sh_cache_weight = FfxFloat32(0.0); + + FfxFloat32x3 cur_irradiance = FFX_BROADCAST_FLOAT32X3(0.0); + FfxFloat32x3 cur_specular_irradiance = FFX_BROADCAST_FLOAT32X3(0.0); + + for (FfxUInt32 i = 0; i < 9; i++) + { + cur_irradiance += cosine_sh[i] * probe_sh[i].xyz; + cur_specular_irradiance += reflection_sh[i] * probe_sh[i].xyz; + } + + irradiance = cur_irradiance / (FFX_BRIXELIZER_GI_PI * FfxFloat32(2.0)); + specular_irradiance = cur_specular_irradiance / (FFX_BRIXELIZER_GI_PI * FfxFloat32(2.0)); + } + } + if (!has_world_probe && weight_sum < FfxFloat32(1.0e-3)) + { + StoreStaticGITarget(tid, FFX_BROADCAST_FLOAT32X4(0.0)); + StoreDebugTarget(tid, FfxFloat32x4(1.0, 0.0, 0.0, 1.0)); + } + else + { + irradiance = ffxMax(irradiance, FFX_BROADCAST_FLOAT32X3(0.0)); + +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_DENOISER == 0 + reprojected.xyz = FfxBrixelizerGIClipAABB(reprojected.xyz, irradiance.xyz, FfxFloat32(0.2)); + + irradiance = ffxLerp(reprojected.xyz, irradiance, temporal_weight); +#endif + + FfxFloat32x4 result = FfxFloat32x4(irradiance, num_diffuse_samples + FfxFloat32(1.0)); + + if (any(isnan(result))) + result = FFX_BROADCAST_FLOAT32X4(0.0); + + StoreStaticGITarget(tid, result); + } + +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + // Specular part + { + FfxFloat32 num_specular_samples = 0; + FfxFloat32x4 specular_output = LoadSpecularTarget(tid); + +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_DENOISER == 0 + FfxFloat32x4 specular_history = LoadSpecularTargetSRV(tid.xy); + num_specular_samples = specular_history.w; +#endif + + FfxFloat32 roughness = LoadRoughness(tid); + FfxFloat32 max_samples = ffxLerp(FfxFloat32(8.0), FfxFloat32(64.0), ffxSqrt(roughness)); + num_specular_samples = ffxMin(num_specular_samples, max_samples); + FfxFloat32 weight = FfxFloat32(1.0) / (FfxFloat32(1.0) + num_specular_samples); + + if (specular_output.w < FfxFloat32(1.0)) + { + if (any(isnan(specular_irradiance))) + specular_irradiance = FFX_BROADCAST_FLOAT32X3(0.0); + + specular_output.xyz = ffxLerp(specular_irradiance.xyz, specular_output.xyz, specular_output.w); + specular_output.xyz = FfxBrixelizerGIClipAABB(specular_output.xyz, specular_irradiance.xyz, FfxFloat32(0.1)); + specular_output.w = FfxFloat32(1.0); + } + +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_DENOISER == 0 + if (specular_output.w > FfxFloat32(1.0e-3)) + specular_history.xyz = FfxBrixelizerGIClipAABB(specular_history.xyz, specular_output.xyz, FfxFloat32(0.5f)); + + specular_output.xyz = ffxLerp(specular_history.xyz, specular_output.xyz, ffxSaturate(weight * specular_output.w)); +#endif + + StoreSpecularTarget(tid.xy, FfxFloat32x4(specular_output.xyz, num_specular_samples + FfxFloat32(1.0))); + } +#endif +} + +void FfxBrixelizerGISpecularSpatialFilter(FfxUInt32x2 tid, FfxUInt32x2 gid) +{ + FfxBrixelizerGISpecularInitializeGroupSharedMemory(FfxInt32x2(tid), FfxInt32x2(gid), FfxInt32x2(GetBufferDimensions())); + FFX_GROUP_MEMORY_BARRIER; + + gid += 4; // Center threads in FFX_GROUPSHARED memory + + const FfxUInt32 sample_count = 0; + // +---+---+---+---+---+---+---+ + // | X | | | | | | | + // +---+---+---+---+---+---+---+ + // | | | | X | X | | | + // +---+---+---+---+---+---+---+ + // | | X | | X | | X | | + // +---+---+---+---+---+---+---+ + // | X | | | X | X | | X | + // +---+---+---+---+---+---+---+ + // | | | X | | | | X | + // +---+---+---+---+---+---+---+ + // | | X | X | | | | | + // +---+---+---+---+---+---+---+ + // | | | | X | | X | | + // +---+---+---+---+---+---+---+ + const FfxInt32x2 sample_offsets[] = { // + FfxInt32x2(0, 1), // + FfxInt32x2(-2, 1), // + FfxInt32x2(2, -3), // + FfxInt32x2(-3, 0), // + FfxInt32x2(1, 2), // + FfxInt32x2(-1, -2), // + FfxInt32x2(3, 0), // + FfxInt32x2(-3, 3), // + FfxInt32x2(0, -3), // + FfxInt32x2(-1, -1), // + FfxInt32x2(2, 1), // + FfxInt32x2(-2, -2), // + FfxInt32x2(1, 0), // + FfxInt32x2(0, 2), // + FfxInt32x2(3, -1) + }; + + FfxFloat32x2 uv = FfxBrixelizerGIGetUV(tid); + FfxBrixelizerGISpecularNeighborhoodSample center = FfxBrixelizerGISpecularLoadFromGroupSharedMemory(FfxInt32x2(gid)); + FFX_MIN16_F eps_size = FFX_MIN16_F(4.0) * FFX_MIN16_F(length(SpecularNeighborhoodSampleGetWorldPos(center, uv) - GetCameraPosition())); + FFX_MIN16_F4 signal_sum = FFX_BROADCAST_MIN_FLOAT16X4(FFX_MIN16_F(0.0)); + FFX_MIN16_F weight_sum = FFX_MIN16_F(0.0); + + if (ffxAsUInt32(FfxFloat32(center.radiance.w)) != 0) + { + signal_sum = center.radiance; + weight_sum = FFX_MIN16_F(1.0); + } + + for (FfxUInt32 i = 0; i < sample_count; i++) + { + FfxInt32x2 coord = FfxInt32x2(gid) + sample_offsets[i]; + + if ((GetFrameIndex() & FfxUInt32(1)) == FfxUInt32(1)) + coord = FfxInt32x2(gid) + sample_offsets[i].yx; + + FfxBrixelizerGISpecularNeighborhoodSample specSample = FfxBrixelizerGISpecularLoadFromGroupSharedMemory(coord); + + if (ffxIsBackground(specSample.depth) || ffxAsUInt32(specSample.depth) == 0) + continue; + + if (ffxAsUInt32(FfxFloat32(specSample.radiance.w)) == 0) + continue; + + FFX_MIN16_F weight = FfxBrixelizerGIWeightMin16( + specSample.normal, // + SpecularNeighborhoodSampleGetWorldPos(specSample, uv), // + center.normal, // + SpecularNeighborhoodSampleGetWorldPos(center, uv), // + eps_size, // + FFX_MIN16_F(8.0)); + + weight *= FFX_MIN16_F(FfxBrixelizerGIGetLuminanceWeight(FfxFloat32x3(specSample.radiance.xyz), FfxFloat32(2.0))); // + { + signal_sum += specSample.radiance * weight; + weight_sum += weight; + } + } + + StoreSpecularTarget(tid, signal_sum / ffxMax(FFX_MIN16_F(1.0e-3), weight_sum)); +} + +void FfxBrixelizerGIBlurGI(FfxUInt32x2 tid, FfxUInt32x2 gid) +{ + FfxFloat32 num_samples = ffxMin(LoadStaticGITargetSRV(tid).w, LoadSpecularTargetSRV(tid).w); + + FfxInt32 radius = FfxInt32(floor(FfxFloat32(8.0) * ffxSaturate(FfxFloat32(1.0) - ffxPow(num_samples / FfxBrixelizerGIMAX_SAMPLES, FfxFloat32(4.0))))); + + if (radius == 0) + { + FfxFloat32x4 diffuse = LoadStaticGITargetSRV(tid); + FfxFloat32x4 specular = LoadSpecularTargetSRV(tid); + + StoreStaticGITarget(tid, diffuse); + StoreSpecularTarget(tid, specular); + return; + } + +#if defined(FfxBrixelizerGIBlurGI_PASS_0) + FfxInt32x2 dir = FfxInt32x2(1, 0); +#else // !#if defined(FfxBrixelizerGIBlurGI_PASS_0) + FfxInt32x2 dir = FfxInt32x2(0, 1); +#endif // !#if defined(FfxBrixelizerGIBlurGI_PASS_0) + + FfxFloat32x4 acc = FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0)); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + FfxFloat32x4 specular_acc = FFX_BROADCAST_FLOAT32X4(FfxFloat32(0.0)); +#endif + FfxFloat32 weight_acc = FfxFloat32(0.0); + FfxFloat32 specular_weight_acc = FfxFloat32(0.0); + FfxFloat32x3 pixel_normal = LoadWorldNormal(tid); + FfxFloat32 pixel_depth = LoadDepth(tid); + + if (ffxIsBackground(pixel_depth)) + { + StoreStaticGITarget(tid, FFX_BROADCAST_FLOAT32X4(0.0)); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + StoreSpecularTarget(tid, FFX_BROADCAST_FLOAT32X4(0.0)); +#endif + return; + } + + FfxFloat32x2 pixel_uv = FfxBrixelizerGIGetUV(tid); + FfxFloat32x3 pixel_world_pos = ffxGetWorldPosition(pixel_uv, pixel_depth); + FfxFloat32 eps_size = FfxFloat32(1.0) * length(pixel_world_pos - GetCameraPosition()); + + for (FfxInt32 c = -radius; c <= radius; c++) + { + FfxInt32x2 coord = FfxInt32x2(tid) + dir * c; + + if (any(FFX_LESS_THAN(coord, FFX_BROADCAST_INT32X2(0))) || any(FFX_GREATER_THAN_EQUAL(coord, GetBufferDimensions()))) + continue; + + FfxFloat32x3 sample_normal = LoadWorldNormal(coord); + FfxFloat32 sample_depth = LoadDepth(coord); + + if (ffxIsBackground(sample_depth)) + continue; + + FfxFloat32x2 sample_uv = FfxBrixelizerGIGetUV(coord); + FfxFloat32x3 sample_world_pos = ffxGetWorldPosition(sample_uv, sample_depth); + FfxFloat32 weight = FfxBrixelizerGIWeight( + pixel_normal, // + pixel_world_pos, // + sample_normal, // + sample_world_pos, // + eps_size, // + FfxFloat32(16.0), // + FfxFloat32(16.0) // + ); // + + FfxFloat32x4 diffuse_gi_sample = LoadStaticGITargetSRV(coord); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + FfxFloat32x4 specular_gi_sample = LoadSpecularTargetSRV(coord); +#endif + + if (any(FFX_GREATER_THAN(diffuse_gi_sample, FFX_BROADCAST_FLOAT32X4(1.0e-6)))) + { + FfxFloat32 diff_weight = weight * FfxBrixelizerGIGetLuminanceWeight(diffuse_gi_sample.xyz, FfxFloat32(2.5)); + weight_acc += diff_weight; + acc += diffuse_gi_sample * diff_weight; + } + +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + if (specular_gi_sample.w > FfxFloat32(1.0e-6)) + { + FfxFloat32 spec_weight = weight * FfxFloat32(0.1) / FfxFloat32(1 + c * c) * FfxBrixelizerGIGetLuminanceWeight(specular_gi_sample.xyz, FfxFloat32(2.5)); + specular_acc += specular_gi_sample * spec_weight; + specular_weight_acc += spec_weight; + } +#endif + } + acc /= ffxMax(FfxFloat32(1.0e-6), weight_acc); + +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + specular_acc /= ffxMax(FfxFloat32(1.0e-6), specular_weight_acc); +#endif + + if (any(isnan(acc))) + { + acc = FFX_BROADCAST_FLOAT32X4(0.0); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + specular_acc = FFX_BROADCAST_FLOAT32X4(0.0); +#endif + } + + StoreStaticGITarget(tid, acc); +#if FFX_BRIXELIZER_GI_OPTION_DISABLE_SPECULAR == 0 + StoreSpecularTarget(tid, specular_acc); +#endif +} + +void FfxBrixelizerGIDebugVisualization(FfxUInt32x2 tid) +{ + FfxFloat32x2 uv = (FfxFloat32x2(tid.xy) + FFX_BROADCAST_FLOAT32X2(0.5).xx) / FfxFloat32x2(GetGIConstants().target_width, GetGIConstants().target_height); + FfxFloat32 z = LoadDepth(tid.xy); + + if (ffxIsBackground(z)) + { + StoreDebugVisualization(tid, FfxFloat32x4(0.0f, 0.0f, 0.0f, 0.0f)); + return; + } + + FfxUInt32 g_starting_cascade = GetGIConstants().tracing_constants.start_cascade; + FfxUInt32 g_end_cascade = GetGIConstants().tracing_constants.end_cascade; + FfxFloat32x3 world_pos = ffxGetWorldPosition(uv, z); + FfxFloat32x3 world_normal = LoadWorldNormal(tid); + + if (GetGIConstants().debug_type == 0) + { + FfxFloat32x3 radiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + FfxBrixelizerGISampleRadianceCache(world_pos, world_normal, FFX_BROADCAST_FLOAT32X3(0.0f), g_starting_cascade, g_end_cascade, radiance); + + StoreDebugVisualization(tid, FfxFloat32x4(radiance, 1.0f)); + } + else + { + FfxFloat32 xi = FfxFloat32(FfxBrixelizerGIpcg(tid.x + FfxBrixelizerGIpcg(tid.y + FfxBrixelizerGIpcg(GetFrameIndex()))) & 0xffu) / FfxFloat32(255.0); + + FFX_MIN16_F cosine_sh[9]; + FfxBrixelizerGISHGetCoefficients_ClampedCosine16(world_normal, cosine_sh); + + FFX_MIN16_F4 probe_sh[9]; + FfxBoolean has_world_probe = FfxBrixelizerGIInterpolateBrickSH(world_pos, g_starting_cascade, g_end_cascade, xi, /* inout */ probe_sh); + + FfxFloat32x3 irradiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + if (has_world_probe) + { + for (FfxUInt32 i = 0; i < 9; i++) + irradiance += cosine_sh[i] * probe_sh[i].xyz; + } + + StoreDebugVisualization(tid, FfxFloat32x4(irradiance, 1.0f)); + } +} + +#define FFX_DISOCCLUSION_THRESHOLD 0.9 +FFX_MIN16_F FfxBrixelizerGIGetDisocclusionFactor(FFX_MIN16_F3 normal, FfxFloat32 linear_depth, FfxFloat32x3 world_position, FFX_MIN16_F3 history_normal, FfxFloat32x3 history_world_position) +{ + FFX_MIN16_F factor = FFX_MIN16_F(FfxFloat32(1.0) // + * exp(-abs(FfxFloat32(1.0) - ffxMax(0.0, dot(normal, history_normal))) * FfxFloat32(1.4)) // + * exp(-length(world_position - history_world_position) / linear_depth * FfxFloat32(1.0))); + return factor; +} + +void FfxBrixelizerGIGenerateDisocclusionMask(FfxUInt32x2 tid) +{ + FfxUInt32x2 screen_size = FfxUInt32x2(GetGIConstants().target_width, GetGIConstants().target_height); + + if (all(FFX_LESS_THAN(tid, screen_size))) + { + FfxFloat32x2 uv = (FfxFloat32x2(tid.xy) + FfxFloat32(0.5).xx) / FfxFloat32x2(screen_size.xy); + FFX_MIN16_F3 normal = FFX_MIN16_F3(LoadWorldNormal(tid)); + FfxFloat32 depth = LoadDepth(tid.xy); + FfxFloat32 linear_depth = ffxGetLinearDepth(uv, depth); + FfxFloat32x2 history_uv = uv + LoadMotionVector(tid.xy); + FFX_MIN16_F3 history_normal = FFX_MIN16_F3(SamplePrevWorldNormal(history_uv)); + FfxFloat32 depth_history = SamplePrevDepth(history_uv); + FfxFloat32 history_linear_depth = ffxGetLinearDepth(history_uv, depth_history); + + FfxFloat32x3 world_position = ffxGetWorldPosition(uv, depth); + FfxFloat32x3 prev_world_position = ffxGetWorldPosition(history_uv, depth_history); + + if (any(FFX_LESS_THAN(history_uv, FFX_BROADCAST_FLOAT32X2(0.0))) || any(FFX_GREATER_THAN(history_uv, FFX_BROADCAST_FLOAT32X2(1.0))) || FfxBrixelizerGIGetDisocclusionFactor(normal, linear_depth, world_position, history_normal, prev_world_position) < FFX_DISOCCLUSION_THRESHOLD) + StoreDisocclusionMask(tid.xy, FfxFloat32(1.0)); + else + StoreDisocclusionMask(tid.xy, FfxFloat32(0.0)); + } +} + +void FfxBrixelizerGIDownsample(FfxUInt32x2 tid) +{ + FfxUInt32x2 screen_size = GetScalingConstants().downsampledSize; + + if (all(FFX_LESS_THAN(tid, screen_size))) + { + FfxFloat32x2 uv = (FfxFloat32x2(tid.xy) + float(0.5).xx) / FfxFloat32x2(screen_size.xy); + + const FfxFloat32x4 depthGather = GatherSourceDepth(uv); + const FfxFloat32x4 depthGatherPrev = GatherSourcePrevDepth(uv); + + StoreDownsampledDepth(tid, FfxBrixelizerGIDepthCloserOp(FfxBrixelizerGIDepthCloserOp(depthGather.x, depthGather.y), FfxBrixelizerGIDepthCloserOp(depthGather.z, depthGather.w))); + StoreDownsampledPrevDepth(tid, FfxBrixelizerGIDepthCloserOp(FfxBrixelizerGIDepthCloserOp(depthGatherPrev.x, depthGatherPrev.y), FfxBrixelizerGIDepthCloserOp(depthGatherPrev.z, depthGatherPrev.w))); + StoreDownsampledNormal(tid, SampleSourceNormal(uv)); + StoreDownsampledPrevNormal(tid, SampleSourcePrevNormal(uv)); + StoreDownsampledRoughness(tid, SampleSourceRoughness(uv)); + StoreDownsampledMotionVector(tid, SampleSourceMotionVector(uv)); + StoreDownsampledPrevLitOutput(tid, SampleSourcePrevLitOutput(uv)); + } +} + +float FfxBrixelizerGINormalEdgeStoppingWeight(FfxFloat32x3 center_normal, FfxFloat32x3 sample_normal, float power) +{ + return pow(clamp(dot(center_normal, sample_normal), 0.0f, 1.0f), power); +} + +float FfxBrixelizerGIDepthEdgeStoppingWeight(float center_depth, float sample_depth, float phi) +{ + return exp(-abs(center_depth - sample_depth) / phi); +} + +float FfxBrixelizerGIComputeEdgeStoppingWeight( + float center_depth, + float sample_depth, + float phi_z, + FfxFloat32x3 center_normal, + FfxFloat32x3 sample_normal, + float phi_normal) +{ + const float wZ = FfxBrixelizerGIDepthEdgeStoppingWeight(center_depth, sample_depth, phi_z); + const float wNormal = FfxBrixelizerGINormalEdgeStoppingWeight(center_normal, sample_normal, phi_normal); + const float wL = 1.0f; + + const float w = exp(0.0 - max(wL, 0.0) - max(wZ, 0.0)) * wNormal; + + return w; +} + +void FfxBrixelizerGIUpsample(FfxUInt32x2 tid) +{ + FfxUInt32x2 low_res_screen_size = FfxUInt32x2(GetScalingConstants().downsampledSize); + FfxFloat32x2 low_res_texel_size = 1.0f / FfxFloat32x2(low_res_screen_size); + + FfxUInt32x2 hi_res_screen_size = FfxUInt32x2(GetScalingConstants().sourceSize); + FfxFloat32x2 uv = (FfxFloat32x2(tid.xy) + float(0.5).xx) / FfxFloat32x2(hi_res_screen_size.xy); + + if (all(FFX_LESS_THAN(tid, hi_res_screen_size))) + { + FfxFloat32 hi_res_depth = LoadSourceDepth(tid); + + if (ffxIsBackground(hi_res_depth)) + { + StoreUpsampledDiffuseGI(tid, FfxFloat32x3(0.0f, 0.0f, 0.0f)); + StoreUpsampledSpecularGI(tid, FfxFloat32x3(0.0f, 0.0f, 0.0f)); + return; + } + + FfxFloat32x3 hi_res_normal = LoadSourceNormal(tid); + + FfxFloat32x3 upsampled_diffuse = FFX_BROADCAST_FLOAT32X3(0.0f); + FfxFloat32x3 upsampled_specular = FFX_BROADCAST_FLOAT32X3(0.0f); + FfxFloat32 total_w = 0.0f; + + const FfxFloat32 FLT_EPS = 0.00000001; + + const FfxFloat32x2 g_kernel[4] = { + FfxFloat32x2(0.0f, 1.0f), + FfxFloat32x2(1.0f, 0.0f), + FfxFloat32x2(-1.0f, 0.0f), + FfxFloat32x2(0.0, -1.0f) + }; + + for (FfxUInt32 i = 0; i < 4; i++) + { + FfxFloat32x2 coarse_tex_coord = uv + g_kernel[i] * low_res_texel_size; + FfxFloat32 coarse_depth = SampleDepth(coarse_tex_coord); + + // If depth belongs to skybox, skip + if (ffxIsBackground(coarse_depth)) + continue; + + FfxFloat32x3 coarse_normal = SampleWorldNormal(coarse_tex_coord); + + FfxFloat32 w = FfxBrixelizerGIComputeEdgeStoppingWeight(hi_res_depth, + coarse_depth, + 1.0f, + hi_res_normal, + coarse_normal, + 32.0f); + + upsampled_diffuse += SampleDownsampledDiffuseGI(coarse_tex_coord) * w; + upsampled_specular += SampleDownsampledSpecularGI(coarse_tex_coord) * w; + total_w += w; + } + + upsampled_diffuse = upsampled_diffuse / max(total_w, FLT_EPS); + upsampled_specular = upsampled_specular / max(total_w, FLT_EPS); + + // Store + StoreUpsampledDiffuseGI(tid, upsampled_diffuse); + StoreUpsampledSpecularGI(tid, upsampled_specular); + } +} + +#endif // FFX_BRIXELIZER_GI_MAIN_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_probe_shading.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_probe_shading.h new file mode 100644 index 00000000..17e58809 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_probe_shading.h @@ -0,0 +1,604 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_PROBE_SHADING_H +#define FFX_BRIXELIZER_GI_PROBE_SHADING_H + +#include "../ffx_core.h" + +FfxFloat32 FfxBrixelizerGIGetLuminance(FfxFloat32x3 color) +{ + return dot(color, FfxFloat32x3(FfxFloat32(0.299), FfxFloat32(0.587), FfxFloat32(0.114))); +} + +#define FFX_BRIXELIZER_GI_LUMINANCE_WEIGHT FfxFloat32(0.2) +FfxFloat32 FfxBrixelizerGIGetLuminanceWeight(FfxFloat32x3 radiance, FfxFloat32 weight_k) +{ + return exp(-weight_k * FfxBrixelizerGIGetLuminance(radiance)); +} + +#define FFX_BRIXELIZER_GI_PI FfxFloat32(3.141592653589793238463) +// Reference: +// https://en.wikipedia.org/wiki/Table_of_spherical_harmonics#Real_spherical_harmonics with |r| == 1 +// https://cseweb.ucsd.edu/~ravir/papers/envmap/envmap.pdf +#define FFX_BRIXELIZER_GI_SH_C0 FfxFloat32(0.2820947917738781) // 0.5 * math.sqrt(1.0 / math.pi) +#define FFX_BRIXELIZER_GI_SH_C1 FfxFloat32(0.4886025119029199) // 0.5 * math.sqrt(3.0 / math.pi) +#define FFX_BRIXELIZER_GI_SH_2_PI_3 ((FfxFloat32(2.0) * FFX_BRIXELIZER_GI_PI) / FfxFloat32(3.0)) +#define FFX_BRIXELIZER_GI_SH_PI_4 (FFX_BRIXELIZER_GI_PI / FfxFloat32(4.0)) +#define FFX_BRIXELIZER_GI_SH_C4 FfxFloat32(1.0925484305920792) // 0.5 * math.sqrt(15.0 / math.pi) +#define FFX_BRIXELIZER_GI_SH_C5 FfxFloat32(0.31539156525252005) // 0.25 * math.sqrt(5.0 / math.pi)) +#define FFX_BRIXELIZER_GI_SH_C6 FfxFloat32(0.5462742152960396) // 0.25 * math.sqrt(15.0 / math.pi) +#define FFX_BRIXELIZER_GI_SH_C7 FfxFloat32(0.24770795610037571) // math.pi / 4.0 * 0.25 * math.sqrt(5.0 / (math.pi)) +#define FFX_BRIXELIZER_GI_SH_C8 FfxFloat32(1.023326707946489) // math.sqrt(math.pi / 3) +#define FFX_BRIXELIZER_GI_SH_C9 FfxFloat32(0.8862269254527579) // math.sqrt(math.pi / 3) +#define FFX_BRIXELIZER_GI_SH_C10 FfxFloat32(0.8580855308097834) // math.sqrt(math.pi * 15.0 / (16.0 * 4.0)) +#define FFX_BRIXELIZER_GI_SH_C11 FfxFloat32(0.4290427654048917) // math.sqrt(3.0 * 2.0 * math.pi) / math.sqrt(64.0 * 8.0 / 5.0) + +// We use 3 bands(9 coefficients) +void FfxBrixelizerGISHGetCoefficients(FfxFloat32x3 direction, out FfxFloat32 coefficients[9]) +{ + coefficients[0] = FfxFloat32(1.0); + + coefficients[1] = direction.y; + coefficients[2] = direction.z; + coefficients[3] = direction.x; + + coefficients[4] = direction.x * direction.y; + coefficients[5] = direction.y * direction.z; + coefficients[6] = FfxFloat32(3.0) * direction.z * direction.z - FfxFloat32(1.0); + coefficients[7] = direction.x * direction.z; + coefficients[8] = direction.x * direction.x - direction.y * direction.y; + + // + + coefficients[0] = coefficients[0] * FFX_BRIXELIZER_GI_SH_C0; + + coefficients[1] = coefficients[1] * FFX_BRIXELIZER_GI_SH_C1; + coefficients[2] = coefficients[2] * FFX_BRIXELIZER_GI_SH_C1; + coefficients[3] = coefficients[3] * FFX_BRIXELIZER_GI_SH_C1; + + coefficients[4] = coefficients[4] * FFX_BRIXELIZER_GI_SH_C4; + coefficients[5] = coefficients[5] * FFX_BRIXELIZER_GI_SH_C4; + coefficients[6] = coefficients[6] * FFX_BRIXELIZER_GI_SH_C5; + coefficients[7] = coefficients[7] * FFX_BRIXELIZER_GI_SH_C4; + coefficients[8] = coefficients[8] * FFX_BRIXELIZER_GI_SH_C6; +} + +void FfxBrixelizerGISHGetCoefficients16(FfxFloat32x3 direction, out FFX_MIN16_F coefficients[9]) +{ + coefficients[0] = FFX_MIN16_F(1.0); + + coefficients[1] = FFX_MIN16_F(direction.y); + coefficients[2] = FFX_MIN16_F(direction.z); + coefficients[3] = FFX_MIN16_F(direction.x); + + coefficients[4] = FFX_MIN16_F(direction.x * direction.y); + coefficients[5] = FFX_MIN16_F(direction.y * direction.z); + coefficients[6] = FFX_MIN16_F(3.0) * FFX_MIN16_F(direction.z * direction.z) - FFX_MIN16_F(1.0); + coefficients[7] = FFX_MIN16_F(direction.x * direction.z); + coefficients[8] = FFX_MIN16_F(direction.x * direction.x - direction.y * direction.y); + + // + + coefficients[0] = coefficients[0] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C0); + + coefficients[1] = coefficients[1] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C1); + coefficients[2] = coefficients[2] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C1); + coefficients[3] = coefficients[3] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C1); + + coefficients[4] = coefficients[4] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C4); + coefficients[5] = coefficients[5] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C4); + coefficients[6] = coefficients[6] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C5); + coefficients[7] = coefficients[7] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C4); + coefficients[8] = coefficients[8] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_C6); +} + +void FfxBrixelizerGISHGetCoefficients_ClampedCosine(FfxFloat32x3 cosine_lobe_dir, out FfxFloat32 coefficients[9]) +{ + FfxBrixelizerGISHGetCoefficients(cosine_lobe_dir, /* out */ coefficients); + coefficients[0] = coefficients[0] * FFX_BRIXELIZER_GI_PI; + + coefficients[1] = coefficients[1] * FFX_BRIXELIZER_GI_SH_2_PI_3; + coefficients[2] = coefficients[2] * FFX_BRIXELIZER_GI_SH_2_PI_3; + coefficients[3] = coefficients[3] * FFX_BRIXELIZER_GI_SH_2_PI_3; + + coefficients[4] = coefficients[4] * FFX_BRIXELIZER_GI_SH_PI_4; + coefficients[5] = coefficients[5] * FFX_BRIXELIZER_GI_SH_PI_4; + coefficients[6] = coefficients[6] * FFX_BRIXELIZER_GI_SH_PI_4; + coefficients[7] = coefficients[7] * FFX_BRIXELIZER_GI_SH_PI_4; + coefficients[8] = coefficients[8] * FFX_BRIXELIZER_GI_SH_PI_4; +} + +void FfxBrixelizerGISHGetCoefficients_ClampedCosine16(FfxFloat32x3 cosine_lobe_dir, out FFX_MIN16_F coefficients[9]) +{ + FfxBrixelizerGISHGetCoefficients16(cosine_lobe_dir, /* out */ coefficients); + coefficients[0] = coefficients[0] * FFX_MIN16_F(FFX_BRIXELIZER_GI_PI); + + coefficients[1] = coefficients[1] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_2_PI_3); + coefficients[2] = coefficients[2] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_2_PI_3); + coefficients[3] = coefficients[3] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_2_PI_3); + + coefficients[4] = coefficients[4] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_PI_4); + coefficients[5] = coefficients[5] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_PI_4); + coefficients[6] = coefficients[6] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_PI_4); + coefficients[7] = coefficients[7] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_PI_4); + coefficients[8] = coefficients[8] * FFX_MIN16_F(FFX_BRIXELIZER_GI_SH_PI_4); +} + +void FfxBrixelizerGILoadBrickSH(FfxUInt32 brick_id, inout FfxFloat32x4 input_sh[9]) +{ + for (FfxInt32 i = 0; i < 9; i++) { + input_sh[i] = ffxUnpackF32x2(LoadBricksSH(FfxBrixelizerBrickGetIndex(brick_id) * 9 + i)); + } +} + +void FfxBrixelizerGILoadBrickSH16(FfxUInt32 brick_id, inout FFX_MIN16_F4 input_sh[9]) +{ + for (FfxInt32 i = 0; i < 9; i++) { + input_sh[i] = FFX_MIN16_F4(ffxUnpackF32x2(LoadBricksSH(FfxBrixelizerBrickGetIndex(brick_id) * 9 + i))); + } +} + +void FfxBrixelizerGIStoreBrickSH(FfxUInt32 brick_id, FfxFloat32x4 input_sh[9]) +{ + for (FfxInt32 i = 0; i < 9; i++) { + StoreBricksSH(FfxBrixelizerBrickGetIndex(brick_id) * 9 + i, ffxFloat16x4ToUint32x2(FFX_MIN16_F4(input_sh[i]))); + } +} + +void FfxBrixelizerGILoadBrickDirectSH(FfxUInt32 brick_id, inout FfxFloat32x4 input_sh[9]) +{ + for (FfxInt32 i = 0; i < 9; i++) { + input_sh[i] = ffxUnpackF32x2(LoadBricksDirectSH(FfxBrixelizerBrickGetIndex(brick_id) * 9 + i)); + } +} + +void FfxBrixelizerGILoadBrickDirectSH16(FfxUInt32 brick_id, inout FFX_MIN16_F4 input_sh[9]) +{ + for (FfxInt32 i = 0; i < 9; i++) { + input_sh[i] = FFX_MIN16_F4(ffxUnpackF32x2(LoadBricksDirectSH(FfxBrixelizerBrickGetIndex(brick_id) * 9 + i))); + } +} + +void FfxBrixelizerGIStoreBrickDirectSH(FfxUInt32 brick_id, FfxFloat32x4 input_sh[9]) +{ + for (FfxInt32 i = 0; i < 9; i++) { + StoreBricksDirectSH(FfxBrixelizerBrickGetIndex(brick_id) * 9 + i, ffxFloat16x4ToUint32x2(FFX_MIN16_F4(input_sh[i]))); + } +} + +// Pick the current voxel size for pushoff +FfxFloat32 FfxBrixelizerGIGetVoxelSize(FfxFloat32x3 world_pos, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade, FfxFloat32 xi) +{ + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(g_starting_cascade); + FfxFloat32 size = CINFO.grid_max.x - CINFO.grid_min.x; + FfxFloat32 r = length(world_pos - CINFO.grid_mid) / (size * FfxFloat32(0.25)); // FfxFloat32(0.288675134594812)); + FfxFloat32 x = log2(ffxMax(r, FfxFloat32(1.0))); + return CINFO.voxel_size * ffxMax(FfxFloat32(1.0), r); +} + +FfxFloat32x3 FfxBrixelizerGISampleRadianceCache(FfxUInt32 brick_id, FfxFloat32x3 uvw) +{ + FfxUInt32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxFloat32x3 uvw_min = (FfxFloat32x3(brick_offset / 2) + FFX_BROADCAST_FLOAT32X3(FfxFloat32(0.5))) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE / 2); + FfxFloat32x3 uvw_max = (FfxFloat32x3(brick_offset / 2) + FFX_BROADCAST_FLOAT32X3(FfxFloat32(3.5))) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE / 2); + FfxFloat32x3 sample_uvw = ffxLerp(uvw_min, uvw_max, ffxSaturate(uvw)); + FfxFloat32x3 radiance = SampleRadianceCacheSRV(sample_uvw); + + if (any(isnan(radiance))) + radiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + return radiance; +} + +FfxFloat32x3 FfxBrixelizerGISampleRadianceCacheSH(FfxUInt32 brick_id, FfxFloat32x3 ray_direction) +{ + FFX_MIN16_F cosine_sh[9]; + FfxBrixelizerGISHGetCoefficients_ClampedCosine16(-ray_direction, cosine_sh); + + FFX_MIN16_F4 shs[9]; + FfxBrixelizerGILoadBrickDirectSH16(brick_id, shs); + + FfxFloat32x3 radiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + for (FfxUInt32 i = 0; i < 9; i++) + radiance += cosine_sh[i] * shs[i].xyz; + + if (any(isnan(radiance))) + radiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + return radiance; +} + +FfxFloat32x3 FfxBrixelizerGISampleRadianceCache(FfxUInt32 cascade_id, FfxFloat32x3 dir, FfxBrixelizerCascadeInfo sdfCINFO, FfxFloat32x3 world_pos) +{ + FfxFloat32x3 rel_pos = world_pos - sdfCINFO.grid_min; + FfxInt32x3 voxel_offset = FfxInt32x3(rel_pos / sdfCINFO.voxel_size); + FfxFloat32x3 uvw = (rel_pos - FfxFloat32x3(voxel_offset) * sdfCINFO.voxel_size) / sdfCINFO.voxel_size; + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(sdfCINFO.clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, FfxUInt32x3(voxel_offset)), FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMapArrayUniform(cascade_id, voxel_idx); + + if (FfxBrixelizerIsValidID(brick_id)) + { + FfxUInt32x4 sample_sh_state = LoadBricksSHState(FfxBrixelizerBrickGetIndex(brick_id)); + FFX_MIN16_F4 sample_dir_w = FFX_MIN16_F4(ffxUnpackF32x2(sample_sh_state.xy)); + + FfxUInt32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id); + FfxFloat32x3 uvw_min = (FfxFloat32x3(brick_offset / 2) + FFX_BROADCAST_FLOAT32X3(FfxFloat32(0.5))) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE / 2); + FfxFloat32x3 uvw_max = (FfxFloat32x3(brick_offset / 2) + FFX_BROADCAST_FLOAT32X3(FfxFloat32(3.5))) / FfxFloat32(FFX_BRIXELIZER_STATIC_CONFIG_SDF_ATLAS_SIZE / 2); + uvw = ffxLerp(uvw_min, uvw_max, ffxSaturate(uvw)); + FfxFloat32x3 radiance = SampleRadianceCacheSRV(uvw); + + if (any(isnan(radiance))) + radiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + return radiance; + } + + return FFX_BROADCAST_FLOAT32X3(0.0); +} +FfxFloat32x3 FfxBrixelizerGISampleRadianceCacheSH(FfxUInt32 cascade_id, FfxFloat32x3 world_normal, FfxBrixelizerCascadeInfo sdfCINFO, FfxFloat32x3 world_pos) +{ + FfxFloat32x3 rel_pos = world_pos - sdfCINFO.grid_min; + FfxInt32x3 voxel_offset = FfxInt32x3(rel_pos / sdfCINFO.voxel_size); + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(sdfCINFO.clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, FfxUInt32x3(voxel_offset)), FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMapArrayUniform(cascade_id, voxel_idx); + + if (FfxBrixelizerIsValidID(brick_id)) + { + FFX_MIN16_F cosine_sh[9]; + FfxBrixelizerGISHGetCoefficients_ClampedCosine16(world_normal, cosine_sh); + + FFX_MIN16_F4 shs[9]; + FfxBrixelizerGILoadBrickDirectSH16(brick_id, shs); + + FfxFloat32x3 radiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + for (uint i = 0; i < 9; i++) + radiance += cosine_sh[i] * shs[i].xyz; + + if (any(isnan(radiance))) + radiance = FFX_BROADCAST_FLOAT32X3(0.0f); + + return radiance; + } + + return FFX_BROADCAST_FLOAT32X3(0.0); +} + +FfxBoolean FfxBrixelizerGISampleRadianceCache(FfxFloat32x3 world_offset, FfxFloat32x3 dir, FfxFloat32x3 grad, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade, inout FfxFloat32x3 cache, FfxFloat32 depth_eps) +{ + FfxFloat32x3 world_pos = world_offset; + for (FfxUInt32 cascade_id = g_starting_cascade; cascade_id <= g_end_cascade; cascade_id++) + { + FfxBrixelizerCascadeInfo sdfCINFO = GetCascadeInfo(cascade_id); + + if (sdfCINFO.is_enabled == 1 && all(FFX_GREATER_THAN(world_pos, sdfCINFO.grid_min)) && all(FFX_LESS_THAN(world_pos, sdfCINFO.grid_max))) + { + FfxFloat32x3 brick_sample = FfxBrixelizerGISampleRadianceCache(cascade_id, dir, sdfCINFO, world_pos); + const FfxFloat32 EPS = FfxFloat32(1.0e-3); + // Causes light leaks if the brick_sample is fully unlit. + //if (dot(brick_sample, brick_sample) > EPS * EPS) + { + cache = brick_sample; + return true; + } + } + } + cache = FFX_BROADCAST_FLOAT32X3(0.0f); + return false; +} +FfxBoolean FfxBrixelizerGISampleRadianceCache(FfxFloat32x3 world_offset, FfxFloat32x3 dir, FfxFloat32x3 grad, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade, inout FfxFloat32x3 cache) +{ + return FfxBrixelizerGISampleRadianceCache(world_offset, dir, grad, g_starting_cascade, g_end_cascade, cache, FfxFloat32(1.0 / 8.0)); +} +FfxBoolean FfxBrixelizerGISampleRadianceCacheSH(FfxFloat32x3 world_pos, FfxFloat32x3 world_normal, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade, inout FfxFloat32x3 cache) +{ + + for (FfxUInt32 cascade_id = g_starting_cascade; cascade_id <= g_end_cascade; cascade_id++) + { + FfxBrixelizerCascadeInfo sdfCINFO = GetCascadeInfo(cascade_id); + + if (sdfCINFO.is_enabled == 1 && all(FFX_GREATER_THAN(world_pos, sdfCINFO.grid_min)) && all(FFX_LESS_THAN(world_pos, sdfCINFO.grid_max))) + { + FfxFloat32x3 brick_sample = FfxBrixelizerGISampleRadianceCacheSH(cascade_id, world_normal, sdfCINFO, world_pos); + + cache = brick_sample; + return true; + } + } + cache = FFX_BROADCAST_FLOAT32X3(0.0f); + return false; +} +FfxBoolean FfxBrixelizerGILoadBrickSH(FfxFloat32x3 world_pos, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade, inout FfxFloat32x4 input_sh[9]) +{ + for (FfxUInt32 cascade_id = g_starting_cascade; cascade_id <= g_end_cascade; cascade_id++) + { + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(cascade_id); + FfxFloat32x3 rel_pos = world_pos - CINFO.grid_min; + FfxFloat32 size = CINFO.grid_max.x - CINFO.grid_min.x; + + if (CINFO.is_enabled == 1 && all(FFX_GREATER_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(0.0))) && all(FFX_LESS_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(size)))) + { + FfxInt32x3 voxel_offset = FfxInt32x3(rel_pos * CINFO.ivoxel_size); + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(CINFO.clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, FfxUInt32x3(voxel_offset)), FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMapArrayUniform(cascade_id, voxel_idx); + + if (FfxBrixelizerIsValidID(brick_id)) + { + FfxBrixelizerGILoadBrickSH(brick_id, /* inout */ input_sh); + return true; + } + } + } + return false; +} + +#define FfxBrixelizerGIGOLDEN_RATIO FfxFloat32(1.61803398875) +FfxBoolean FfxBrixelizerGIInterpolateBrickSH(FfxFloat32x3 world_pos, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade, FfxFloat32 xi, inout FFX_MIN16_F4 input_sh[9]) +{ + FfxUInt32 bricks[8] = { + FFX_BRIXELIZER_UNINITIALIZED_ID, // + FFX_BRIXELIZER_UNINITIALIZED_ID, // + FFX_BRIXELIZER_UNINITIALIZED_ID, // + FFX_BRIXELIZER_UNINITIALIZED_ID, // + FFX_BRIXELIZER_UNINITIALIZED_ID, // + FFX_BRIXELIZER_UNINITIALIZED_ID, // + FFX_BRIXELIZER_UNINITIALIZED_ID, // + FFX_BRIXELIZER_UNINITIALIZED_ID, // + }; + + FFX_MIN16_F3 uvw; + + for (FfxUInt32 cascade_id = g_starting_cascade; cascade_id <= g_end_cascade; cascade_id++) + { + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(cascade_id); + FfxFloat32x3 rel_pos = world_pos - CINFO.grid_min; + FfxFloat32 size = CINFO.grid_max.x - CINFO.grid_min.x; + FfxFloat32 falloff = length(world_pos - CINFO.grid_mid) / (size / FfxFloat32(2.0)); + FfxBoolean skip = falloff > (FfxFloat32(1.0) - (xi * FfxFloat32(8.0) + FfxFloat32(0.0)) / FfxFloat32(FFX_BRIXELIZER_CASCADE_RESOLUTION)); + + if (CINFO.is_enabled == 1 && !skip && all(FFX_GREATER_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(0.0))) && all(FFX_LESS_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(size)))) + { + FfxFloat32x3 scaled_pos = rel_pos * CINFO.ivoxel_size - FFX_BROADCAST_FLOAT32X3(0.5); + uvw = FFX_MIN16_F3(ffxFract(scaled_pos)); + FfxInt32x3 base_coord = FfxInt32x3(floor(scaled_pos)); + FfxInt32x3 coords[8] = { + FfxInt32x3(scaled_pos) + FfxInt32x3(0, 0, 0), // + FfxInt32x3(scaled_pos) + FfxInt32x3(1, 0, 0), // + FfxInt32x3(scaled_pos) + FfxInt32x3(0, 1, 0), // + FfxInt32x3(scaled_pos) + FfxInt32x3(1, 1, 0), // + FfxInt32x3(scaled_pos) + FfxInt32x3(0, 0, 1), // + FfxInt32x3(scaled_pos) + FfxInt32x3(1, 0, 1), // + FfxInt32x3(scaled_pos) + FfxInt32x3(0, 1, 1), // + FfxInt32x3(scaled_pos) + FfxInt32x3(1, 1, 1), // + }; + + for (FfxInt32 i = 0; i < 8; i++) + { + if (any(FFX_LESS_THAN(coords[i], FFX_BROADCAST_INT32X3(0))) && any(FFX_GREATER_THAN_EQUAL(coords[i], FFX_BROADCAST_INT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION)))) + continue; + + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(CINFO.clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, FfxUInt32x3(coords[i])), FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMapArrayNonUniform(cascade_id, voxel_idx); + + if (FfxBrixelizerIsValidID(brick_id)) + bricks[i] = brick_id; + } + break; + } + xi = ffxFract(xi + FfxFloat32(cascade_id) * FfxBrixelizerGIGOLDEN_RATIO); + } + + FFX_MIN16_F weights[8] = { + (FFX_MIN16_F(1.0) - uvw.x) * (FFX_MIN16_F(1.0) - uvw.y) * (FFX_MIN16_F(1.0) - uvw.z), // + uvw.x * (FFX_MIN16_F(1.0) - uvw.y) * (FFX_MIN16_F(1.0) - uvw.z), // + (FFX_MIN16_F(1.0) - uvw.x) * uvw.y * (FFX_MIN16_F(1.0) - uvw.z), // + uvw.x * uvw.y * (FFX_MIN16_F(1.0) - uvw.z), // + (FFX_MIN16_F(1.0) - uvw.x) * (FFX_MIN16_F(1.0) - uvw.y) * uvw.z, // + uvw.x * (FFX_MIN16_F(1.0) - uvw.y) * uvw.z, // + (FFX_MIN16_F(1.0) - uvw.x) * uvw.y * uvw.z, // + uvw.x * uvw.y * uvw.z, // + }; + + FFX_MIN16_F weight_sum = FFX_MIN16_F(0.0); + + for (FfxInt32 j = 0; j < 9; j++) + input_sh[j] = FFX_BROADCAST_MIN_FLOAT16X4(FFX_MIN16_F(0.0)); + + for (FfxInt32 i = 0; i < 8; i++) + { + if (bricks[i] == FFX_BRIXELIZER_UNINITIALIZED_ID) + continue; + + FFX_MIN16_F4 shs[9]; + FfxBrixelizerGILoadBrickSH16(bricks[i], /* inout */ shs); + + if (shs[0].w < FfxFloat32(1.0)) + continue; // skip if less than 16 samples of data as too noisy + + for (FfxInt32 j = 0; j < 9; j++) + input_sh[j] += shs[j] * weights[i]; + + weight_sum += weights[i]; + } + for (FfxInt32 j = 0; j < 9; j++) + input_sh[j] /= ffxMax(weight_sum, FFX_MIN16_F(1.0e-6)); + + return ffxAsUInt32(FfxFloat32(weight_sum)) != 0; +} + +void FfxBrixelizerGIEmitIrradiance(FfxFloat32x3 world_pos, FfxFloat32x3 probe_direction, FfxFloat32x3 ray_direction, FfxFloat32x4 input_sh[9], FfxFloat32 xi, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade) +{ + FfxFloat32 DoV = ffxSaturate(dot(-ray_direction, probe_direction)); + FfxFloat32 jk = ffxLerp(FfxFloat32(1.0), FfxFloat32(1.0 / 8.0), DoV); + xi = ffxLerp(-jk, jk, xi); // voxel jitter + + for (FfxUInt32 cascade_id = g_starting_cascade; cascade_id <= g_end_cascade; cascade_id++) + { + FfxFloat32 max_num_samples = FfxFloat32(64.0) * ffxPow(FfxFloat32(1.3), FfxFloat32(cascade_id - g_starting_cascade)); + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(cascade_id); + FfxFloat32x3 rel_pos = world_pos - (CINFO.voxel_size) * ray_direction * xi - CINFO.grid_min; + FfxFloat32 size = CINFO.grid_max.x - CINFO.grid_min.x; + + if (CINFO.is_enabled == 1 && all(FFX_GREATER_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(0.0))) && all(FFX_LESS_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(size)))) + { + FfxInt32x3 voxel_offset = FfxInt32x3(rel_pos * CINFO.ivoxel_size); + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(CINFO.clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, FfxUInt32x3(voxel_offset)), FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMapArrayUniform(cascade_id, voxel_idx); + + if (FfxBrixelizerIsValidID(brick_id)) + { + FfxFloat32x4 src_sh[9]; + FfxBrixelizerGILoadBrickSH(brick_id, /* inout */ src_sh); + FfxFloat32 num_samples = ffxMin(max_num_samples, src_sh[0].w); + + FfxUInt32x4 sh_state = LoadBricksSHState(FfxBrixelizerBrickGetIndex(brick_id)); + FFX_MIN16_F4 dir_w = FFX_MIN16_F4(ffxUnpackF32x2(sh_state.xy)); + if (any(isinf(dir_w)) || any(isnan(dir_w))) + dir_w = FFX_BROADCAST_MIN_FLOAT16X4(FFX_MIN16_F(0.0)); + + FfxFloat32 weight = FfxFloat32(1.0) - FfxFloat32(1.0) / (FfxFloat32(1.0) + num_samples); + + FfxFloat32x4 shs[9]; + for (FfxInt32 i = 0; i < 9; i++) + { + FfxFloat32x4 src = src_sh[i]; + const FfxFloat32 EPS = FfxFloat32(1.0e-4); + FfxFloat32x4 new_value = ffxLerp(input_sh[i], src, weight); + new_value.w = num_samples + FfxFloat32(1.0); + + if (any(isnan(new_value))) + new_value = FFX_BROADCAST_FLOAT32X4(0.0); + + shs[i] = new_value; + } + + dir_w.xyz = normalize(ffxLerp(FFX_MIN16_F3(probe_direction), dir_w.xyz, FFX_MIN16_F(weight))); + + sh_state.xy = ffxFloat16x4ToUint32x2(dir_w); + StoreBricksSHState(FfxBrixelizerBrickGetIndex(brick_id), sh_state); + + FfxBrixelizerGIStoreBrickSH(brick_id, shs); + } + } + } +} + +FfxInt32x3 FfxBrixelizerGIPickMajorDir(FfxFloat32x3 r) +{ + if (abs(r.x) > abs(r.y)) + { + if (abs(r.x) > abs(r.z)) + return FfxInt32x3(r.x > FfxFloat32(0.0) ? 1 : -1, 0, 0); + else + return FfxInt32x3(0, 0, r.z > FfxFloat32(0.0) ? 1 : -1); + } + else + { + if (abs(r.y) > abs(r.z)) + return FfxInt32x3(0, r.y > FfxFloat32(0.0) ? 1 : -1, 0); + else + return FfxInt32x3(0, 0, r.z > FfxFloat32(0.0) ? 1 : -1); + } +} + +void FfxBrixelizerGIEmitRadiance(FfxUInt32 brick_id, FfxFloat32x3 uvw, FfxFloat32x3 direction, FfxFloat32x3 radiance, FfxFloat32 weight) +{ + FfxUInt32x3 brick_offset = FfxBrixelizerGetSDFAtlasOffset(brick_id) / 2; + FfxInt32x3 coord = FfxInt32x3(ffxSaturate(uvw) * FfxFloat32(4.0)); + FfxFloat32x3 src = LoadRadianceCache(brick_offset + coord); + const FfxFloat32 EPS = FfxFloat32(1.0e-6); + + if (dot(src, src) < EPS * EPS) + weight = FfxFloat32(0.0); + + FfxFloat32x3 new_value = ffxLerp(radiance, src, weight); + + if (any(isnan(new_value))) + new_value = FFX_BROADCAST_FLOAT32X3(0.0); + + StoreRadianceCache(brick_offset + coord, new_value); + + { + FfxFloat32x4 src_sh[9]; + FfxBrixelizerGILoadBrickDirectSH(brick_id, /* inout */ src_sh); + + FfxFloat32 direction_sh[9]; + FfxBrixelizerGISHGetCoefficients(direction, direction_sh); + + for (FfxUInt32 j = 0; j < 9; j++) + { + src_sh[j].xyz = ffxLerp(direction_sh[j] * radiance.xyz, src_sh[j].xyz, weight); + src_sh[j].w += FfxFloat32(1.0); + } + + FfxBrixelizerGIStoreBrickDirectSH(brick_id, src_sh); + } + + // g_rw_pctx_volume_cache[brick_offset + coord] = ffxLerp(color, src, FfxFloat32(0.95)); + // break; // early out and let the rest for Propagate pass +} + +// xi - random [0, 1] +void FfxBrixelizerGIEmitRadiance(FfxFloat32x3 world_pos, FfxFloat32x3 world_normal, FfxFloat32x3 ray_direction, FfxFloat32x3 radiance, FfxFloat32 xi, FfxUInt32 g_starting_cascade, FfxUInt32 g_end_cascade) +{ + radiance = clamp(radiance, FFX_BROADCAST_FLOAT32X3(0.0), FFX_BROADCAST_FLOAT32X3(8.0)); // Some clamping has to be here for specular highlights + FfxFloat32 DoV = ffxSaturate(dot(-ray_direction, world_normal)); + FfxFloat32 jk = ffxLerp(FfxFloat32(4.0), FfxFloat32(1.0 / 8.0), DoV); // TODO: Make this tunable + + for (FfxUInt32 cascade_id = g_starting_cascade; cascade_id <= g_end_cascade; cascade_id++) + { + FfxBrixelizerCascadeInfo sdfCINFO = GetCascadeInfoNonUniform(cascade_id); + FfxFloat32 random_jitter = ffxLerp(-jk, jk, xi) * GetCascadeInfoNonUniform(g_starting_cascade).voxel_size; // voxel jitter + + // Jitter along the camera primary ray to inject into neighbor voxels + FfxFloat32x3 rel_pos = world_pos - ray_direction * random_jitter - sdfCINFO.grid_min; + FfxFloat32 size = sdfCINFO.grid_max.x - sdfCINFO.grid_min.x; + + // Check if relative position is within the cascade grid extents + if (sdfCINFO.is_enabled == 1 && all(FFX_GREATER_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(0.0))) && all(FFX_LESS_THAN(rel_pos, FFX_BROADCAST_FLOAT32X3(size)))) + { + + // Convert the relative voxel position into a voxel grid coordinate + FfxInt32x3 voxel_offset = FfxInt32x3(rel_pos / sdfCINFO.voxel_size); + + // Generate a 3D texture coordinate from + FfxFloat32x3 uvw = (rel_pos - FfxFloat32x3(voxel_offset) * sdfCINFO.voxel_size) / sdfCINFO.voxel_size; + uvw = ffxSaturate(uvw); + FfxFloat32x3 uvw_c = uvw - FFX_BROADCAST_FLOAT32X3(0.5); + FfxInt32x3 md = FfxBrixelizerGIPickMajorDir(uvw_c); + + FfxUInt32 voxel_idx = FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(FfxInt32x3(sdfCINFO.clipmap_offset), FFX_BRIXELIZER_CASCADE_WRAP_MASK, FfxUInt32x3(voxel_offset)), FFX_BRIXELIZER_CASCADE_DEGREE); + FfxUInt32 brick_id = LoadCascadeBrickMapArrayNonUniform(cascade_id, voxel_idx); + + if (FfxBrixelizerIsValidID(brick_id)) + { + FfxFloat32 weight = FfxFloat32(1.0) - FfxFloat32(1.0 / (FfxFloat32(8.0) * ffxPow(FfxFloat32(2.0), FfxFloat32(cascade_id - g_starting_cascade)))); + FfxBrixelizerGIEmitRadiance(brick_id, uvw, world_normal, radiance, weight); + } + } + xi = ffxFract(xi + FfxBrixelizerGIGOLDEN_RATIO); + } +} + +#endif // FFX_BRIXELIZER_GI_PROBE_SHADING_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_radiance_cache_update.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_radiance_cache_update.h new file mode 100644 index 00000000..dc9f6e1f --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_radiance_cache_update.h @@ -0,0 +1,176 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_RADIANCE_CACHE_H +#define FFX_BRIXELIZER_GI_RADIANCE_CACHE_H + +#include "../ffx_core.h" + +#include "ffx_brixelizer_brick_common_private.h" +#include "ffx_brixelizergi_common.h" +#include "ffx_brixelizergi_probe_shading.h" + +FfxFloat32x3 GetWorldPosition(FfxUInt32x2 pixel_coordinate) +{ + FfxFloat32x2 uv = (FfxFloat32x2(pixel_coordinate.xy) + (0.5).xx) / FfxFloat32x2(GetGIConstants().target_width, GetGIConstants().target_height); + FfxFloat32 z = LoadDepth(pixel_coordinate); + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, z); + FfxFloat32x3 view_space_position = ffxScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 world_space_origin = ffxViewSpaceToWorldSpace(FfxFloat32x4(view_space_position, FfxFloat32(1.0))).xyz; + return world_space_origin; +} + +// https://www.pcg-random.org/ +FfxUInt32 FFX_pcg(FfxUInt32 v) +{ + FfxUInt32 state = v * 747796405u + 2891336453u; + FfxUInt32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ word; +} + +void FfxBrixelizerGIEmitPrimaryRayRadiance(FfxUInt32x2 _tid) +{ + FfxUInt32x2 qid = FfxUInt32x2(GetGIConstants().frame_index & 3, (GetGIConstants().frame_index >> 2) & 3); + FfxUInt32x2 tid = _tid * 4 + qid; + + if (any(FFX_GREATER_THAN_EQUAL(tid, FfxUInt32x2(GetGIConstants().target_width, GetGIConstants().target_height)))) + return; + + FfxFloat32x2 uv = (FfxFloat32x2(tid.xy) + FFX_BROADCAST_FLOAT32X2(0.5).xx) / FfxFloat32x2(GetGIConstants().target_width, GetGIConstants().target_height); + FfxFloat32 z = LoadDepth(tid.xy); + + if (ffxIsBackground(z)) + return; + + FfxFloat32x2 prev_uv = uv + SampleMotionVector(uv); + + if (any(FFX_GREATER_THAN(prev_uv, FFX_BROADCAST_FLOAT32X2(1.0))) || any(FFX_LESS_THAN(prev_uv, FFX_BROADCAST_FLOAT32X2(0.0)))) + return; + + FfxFloat32x3 ray_origin = GetWorldPosition(tid.xy); + FfxFloat32x3 primary_radiance = SamplePrevLitOutput(prev_uv); + FfxFloat32 xi = FfxFloat32(FFX_pcg(tid.x + FFX_pcg(tid.y + FFX_pcg(GetGIConstants().frame_index))) & 0xffffu) / FfxFloat32(256 * 256 - 1); + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, FfxFloat32(0.5)); + FfxFloat32x3 view_space_ray = ffxScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 view_space_ray_direction = normalize(view_space_ray); + FfxFloat32x3 ray_direction = -normalize(ffxViewSpaceToWorldSpace(FfxFloat32x4(view_space_ray_direction, FfxFloat32(0.0)))); + FfxBoolean disoccluded = LoadDisocclusionMask(tid.xy) > 0; + + if (disoccluded) + return; + + FfxUInt32 g_starting_cascade = GetGIConstants().tracing_constants.start_cascade; + FfxUInt32 g_end_cascade = GetGIConstants().tracing_constants.end_cascade; + FfxFloat32x3 world_normal = LoadWorldNormal(tid); + FfxBrixelizerGIEmitRadiance(ray_origin, world_normal, ray_direction, primary_radiance, xi, g_starting_cascade, g_end_cascade); +} + +void FfxBrixelizerGIPrepareClearCache(FfxUInt32x3 tid) +{ + FfxUInt32 cnt = LoadContextCounter(FFX_BRIXELIZER_CONTEXT_COUNTER_CLEAR_BRICKS); + StoreRaySwapIndirectArgs(0, cnt); + StoreRaySwapIndirectArgs(1, 1); + StoreRaySwapIndirectArgs(2, 1); +} + +void FfxBrixelizerGIClearCache(FfxUInt32x3 tid) +{ + FfxUInt32 brick_offset = tid.x / 64; + FfxUInt32 brick_id = LoadBricksClearList(brick_offset); + FfxUInt32x3 local_coord = FfxBrixelizerUnflattenPOT(tid.x % 64, 2); + + if ((tid.x % 64) == 0) { // clear SH + FfxFloat32x4 shs[9]; + for (FfxInt32 j = 0; j < 9; j++) + shs[j] = FFX_BROADCAST_FLOAT32X4(0.0); + FfxBrixelizerGIStoreBrickSH(brick_id, shs); + FfxBrixelizerGIStoreBrickDirectSH(brick_id, shs); + StoreBricksSHState(FfxBrixelizerBrickGetIndex(brick_id), FFX_BROADCAST_UINT32X4(0)); + } + StoreRadianceCache(FfxBrixelizerGetSDFAtlasOffset(brick_id) / 2 + local_coord, FfxFloat32x3(0.0, 0.0, 0.0)); +} + +void FfxBrixelizerGIPropagateSH(FfxUInt32x3 tid) +{ + if (tid.x >= FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION * FFX_BRIXELIZER_CASCADE_RESOLUTION) + return; + + FfxInt32x3 voxel = FfxInt32x3(FfxBrixelizerUnflattenPOT(tid.x, FFX_BRIXELIZER_CASCADE_DEGREE)); + FfxBrixelizerCascadeInfo CINFO = GetCascadeInfo(GetPassConstantsCascadeIndex()); + FfxUInt32 base_brick_id = LoadCascadeBrickMapArrayUniform(GetPassConstantsCascadeIndex(), WrapFlatCoords(CINFO, tid.x)); + if (!FfxBrixelizerIsValidID(base_brick_id)) + return; + FfxFloat32x4 base_sh[9]; + FfxBrixelizerGILoadBrickSH(base_brick_id, /* inout */ base_sh); + FfxFloat32 weight_acc = FfxFloat32(base_sh[0].w * base_sh[0].w); + for (FfxInt32 j = 0; j < 9; j++) + base_sh[j] *= weight_acc; + FfxInt32 next_cascade_idx = -1; + + FfxUInt32x4 sh_state = LoadBricksSHState(FfxBrixelizerBrickGetIndex(base_brick_id)); + FFX_MIN16_F4 dir_w = FFX_MIN16_F4(ffxUnpackF32x2(sh_state.xy)); + + if (next_cascade_idx == -1) + { + for (FfxInt32 z = -1; z <= 1; z++) + { + for (FfxInt32 y = -1; y <= 1; y++) + { + for (FfxInt32 x = -1; x <= 1; x++) + { + if (x == 0 && y == 0 && z == 0) + continue; + + FfxInt32x3 sample_voxel = voxel + FfxInt32x3(x, y, z); + + if (any(FFX_LESS_THAN(sample_voxel, FFX_BROADCAST_INT32X3(0))) || any(FFX_GREATER_THAN_EQUAL(sample_voxel, FFX_BROADCAST_INT32X3(FFX_BRIXELIZER_CASCADE_RESOLUTION)))) + continue; + + FfxUInt32 sample_brick_id = LoadCascadeBrickMapArrayUniform(GetPassConstantsCascadeIndex(), FfxBrixelizerFlattenPOT(FfxBrixelizerWrapCoords(CINFO, sample_voxel), FFX_BRIXELIZER_CASCADE_DEGREE)); + + if (FfxBrixelizerIsInvalidID(sample_brick_id)) + continue; + + FfxUInt32x4 sample_sh_state = LoadBricksSHState(FfxBrixelizerBrickGetIndex(sample_brick_id)); + FFX_MIN16_F4 sample_dir_w = FFX_MIN16_F4(ffxUnpackF32x2(sample_sh_state.xy)); + + if (dot(sample_dir_w.xyz, dir_w.xyz) < FFX_MIN16_F(0.0)) + continue; + + FfxFloat32x4 shs[9]; + FfxBrixelizerGILoadBrickSH(sample_brick_id, /* inout */ shs); + FfxFloat32 weight = FfxFloat32(1.0) / FfxFloat32(x * x + y * y + z * z); + for (FfxInt32 j = 0; j < 9; j++) + base_sh[j] += shs[j] * weight; + weight_acc += weight; + } + } + } + } + for (FfxInt32 j = 0; j < 9; j++) + base_sh[j] *= FfxFloat32(1.0) / ffxMax(weight_acc, FfxFloat32(1.0e-6)); + for (FfxInt32 j = 0; j < 9; j++) + base_sh[j].w *= GetPassConstantsEnergyDecayK(); + FfxBrixelizerGIStoreBrickSH(base_brick_id, base_sh); +} + +#endif // FFX_BRIXELIZER_GI_RADIANCE_CACHE_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_resources.h new file mode 100644 index 00000000..3a58629b --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/brixelizergi/ffx_brixelizergi_resources.h @@ -0,0 +1,117 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_BRIXELIZER_GI_RESOURCES_H +#define FFX_BRIXELIZER_GI_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_GI_TARGET_0 1 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_GI_TARGET_1 2 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_SCREEN_PROBES_0 3 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_SCREEN_PROBES_1 4 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SPECULAR_TARGET_0 5 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SPECULAR_TARGET_1 6 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_RADIANCE_CACHE 7 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_PUSHOFF_MAP 8 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DEBUG_TARGET 9 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_SCREEN_PROBES_STAT 10 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_PROBE_INFO 11 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_STATIC_PROBE_SH 12 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_RAY_SWAP_INDIRECT_ARGS 13 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_BRICKS_DIRECT_SH 14 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_BRICKS_SH 15 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_BRICKS_SH_STATE 16 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DISOCCLUSION_MASK 17 + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_TEMP_SPAWN_MASK 18 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_TEMP_RAND_SEED 19 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_TEMP_SPECULAR_PRETRACE_TARGET 20 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_TEMP_BLUR_MASK 21 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_TEMP_PROBE_INFO 22 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_TEMP_PROBE_SH 23 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_TEMP_SPECULAR_RAY_SWAP 24 + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_DEPTH 25 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_HISTORY_DEPTH 26 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_NORMAL 27 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_HISTORY_NORMAL 28 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_ROUGHNESS 29 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_MOTION_VECTORS 30 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_LIT_OUTPUT 31 + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_DIFFUSE_GI 32 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_DOWNSAMPLED_SPECULAR_GI 33 + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_COUNT_INTERNAL 34 + +// Resource IDs for aliasing purposes +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SOURCE_DEPTH 34 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SOURCE_HISTORY_DEPTH 35 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SOURCE_NORMAL 36 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SOURCE_HISTORY_NORMAL 37 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SOURCE_ROUGHNESS 38 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SOURCE_MOTION_VECTORS 39 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_SOURCE_LIT_OUTPUT 40 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_UPSAMPLED_DIFFUSE_GI 41 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_UPSAMPLED_SPECULAR_GI 42 + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_OUTPUT_DIFFUSE_GI 43 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_OUTPUT_SPECULAR_GI 44 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_OUTPUT_DEBUG_VISUALIZATION 45 + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_ENVIRONMENT_MAP 46 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_PREV_LIT_OUTPUT 47 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_DEPTH 48 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_HISTORY_DEPTH 49 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_NORMAL 50 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_HISTORY_NORMAL 51 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_ROUGHNESS 52 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS 53 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_BLUE_NOISE 54 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_SDF_ATLAS 55 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_CONTEXT_BRICKS_AABB 56 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_CONTEXT_BRICKS_VOXEL_MAP 57 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_CONTEXT_COUNTERS 58 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_BRICKS_CLEAR_LIST 59 +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_CASCADE_AABB_TREES 60 // 24 elements +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_INPUT_CASCADE_BRICK_MAPS 84 // 24 elements + +#define FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_STATIC_GI_TARGET_READ 108 +#define FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_STATIC_SCREEN_PROBES_READ 109 +#define FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_STATIC_SPECULAR_TARGET_READ 110 +#define FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_STATIC_SCREEN_PROBES_WRITE 111 +#define FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_STATIC_GI_TARGET_WRITE 112 +#define FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_STATIC_SPECULAR_TARGET_WRITE 113 +#define FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_COUNT (113 - FFX_BRIXELIZER_GI_PING_PONG_RESOURCE_STATIC_GI_TARGET_READ) + +#define FFX_BRIXELIZER_GI_RESOURCE_IDENTIFIER_COUNT 114 + +#define FFX_BRIXELIZER_GI_CONSTANTBUFFER_IDENTIFIER_GI_CONSTANTS 0 +#define FFX_BRIXELIZER_GI_CONSTANTBUFFER_IDENTIFIER_PASS_CONSTANTS 1 +#define FFX_BRIXELIZER_GI_CONSTANTBUFFER_IDENTIFIER_SCALING_CONSTANTS 2 +#define FFX_BRIXELIZER_GI_CONSTANTBUFFER_IDENTIFIER_CONTEXT_INFO 3 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif //FFX_BRIXELIZER_GI_RESOURCES_H \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cacao/CMakeCompileCACAOShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cacao/CMakeCompileCACAOShaders.txt new file mode 100644 index 00000000..6fa4c50b --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cacao/CMakeCompileCACAOShaders.txt @@ -0,0 +1,77 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(CACAO_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(CACAO_PERMUTATION_ARGS + -DFFX_CACAO_OPTION_APPLY_SMART={0,1} +) + +set(CACAO_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/cacao") + +if (NOT CACAO_SHADER_EXT) + set(CACAO_SHADER_EXT *) +endif() + +file(GLOB CACAO_SHADERS + "shaders/cacao/ffx_cacao_apply_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_apply_non_smart_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_apply_non_smart_half_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_clear_load_counter_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_1_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_2_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_3_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_4_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_5_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_6_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_7_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_edge_sensitive_blur_8_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_importance_map_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_importance_map_a_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_importance_map_b_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_q0_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_q1_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_q2_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_q3_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_generate_q3_base_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_downsampled_depths_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_downsampled_depths_and_mips_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_downsampled_depths_half_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_downsampled_normals_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_downsampled_normals_from_input_normals_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_native_depths_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_native_depths_and_mips_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_native_depths_half_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_native_normals_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_prepare_native_normals_from_input_normals_pass.${CACAO_SHADER_EXT}" + "shaders/cacao/ffx_cacao_upscale_bilateral_5x5_pass.${CACAO_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${CACAO_BASE_ARGS}" "${CACAO_API_BASE_ARGS}" + "${CACAO_PERMUTATION_ARGS}" "${CACAO_INCLUDE_ARGS}" + "${CACAO_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" CACAO_PERMUTATION_OUTPUTS) + +add_shader_output("${CACAO_PERMUTATION_OUTPUTS}") \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cacao/ffx_cacao_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cacao/ffx_cacao_callbacks_glsl.h new file mode 100644 index 00000000..96a106fe --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cacao/ffx_cacao_callbacks_glsl.h @@ -0,0 +1,774 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_cacao_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(CACAO_BIND_CB_CACAO) + struct FFX_CACAO_Constants + { + FfxFloat32x2 DepthUnpackConsts; + FfxFloat32x2 CameraTanHalfFOV; + + FfxFloat32x2 NDCToViewMul; + FfxFloat32x2 NDCToViewAdd; + + FfxFloat32x2 DepthBufferUVToViewMul; + FfxFloat32x2 DepthBufferUVToViewAdd; + + FfxFloat32 EffectRadius; // world (viewspace) maximum size of the shadow + FfxFloat32 EffectShadowStrength; // global strength of the effect (0 - 5) + FfxFloat32 EffectShadowPow; + FfxFloat32 EffectShadowClamp; + + FfxFloat32 EffectFadeOutMul; // effect fade out from distance (ex. 25) + FfxFloat32 EffectFadeOutAdd; // effect fade out to distance (ex. 100) + FfxFloat32 EffectHorizonAngleThreshold; // limit errors on slopes and caused by insufficient geometry tessellation (0.05 to 0.5) + FfxFloat32 EffectSamplingRadiusNearLimitRec; // if viewspace pixel closer than this, don't enlarge shadow sampling radius anymore (makes no sense to grow beyond some distance, not enough samples to cover everything, so just limit the shadow growth; could be SSAOSettingsFadeOutFrom * 0.1 or less) + + FfxFloat32 DepthPrecisionOffsetMod; + FfxFloat32 NegRecEffectRadius; // -1.0 / EffectRadius + FfxFloat32 LoadCounterAvgDiv; // 1.0 / ( halfDepthMip[SSAO_DEPTH_MIP_LEVELS-1].sizeX * halfDepthMip[SSAO_DEPTH_MIP_LEVELS-1].sizeY ) + FfxFloat32 AdaptiveSampleCountLimit; + + FfxFloat32 InvSharpness; + FfxInt32 BlurNumPasses; + FfxFloat32 BilateralSigmaSquared; + FfxFloat32 BilateralSimilarityDistanceSigma; + + FfxFloat32x4 PatternRotScaleMatrices[4][5]; + + FfxFloat32 NormalsUnpackMul; + FfxFloat32 NormalsUnpackAdd; + FfxFloat32 DetailAOStrength; + FfxFloat32 Dummy0; + + FfxFloat32x2 SSAOBufferDimensions; + FfxFloat32x2 SSAOBufferInverseDimensions; + + FfxFloat32x2 DepthBufferDimensions; + FfxFloat32x2 DepthBufferInverseDimensions; + + FfxInt32x2 DepthBufferOffset; + FfxFloat32x4 PerPassFullResUVOffset[4]; + + FfxFloat32x2 OutputBufferDimensions; + FfxFloat32x2 OutputBufferInverseDimensions; + + FfxFloat32x2 ImportanceMapDimensions; + FfxFloat32x2 ImportanceMapInverseDimensions; + + FfxFloat32x2 DeinterleavedDepthBufferDimensions; + FfxFloat32x2 DeinterleavedDepthBufferInverseDimensions; + + FfxFloat32x2 DeinterleavedDepthBufferOffset; + FfxFloat32x2 DeinterleavedDepthBufferNormalisedOffset; + + mat4 NormalsWorldToViewspaceMatrix; + }; + + layout (set=0, binding = CACAO_BIND_CB_CACAO) uniform SSAOConstantsBuffer_t + { + FFX_CACAO_Constants g_FFX_CACAO_Consts; + }; + + #define FFX_CACAO_CONSTANT_BUFFER_1_SIZE 172 // Number of 32-bit values. This must be kept in sync with max( cbRCAS , cbSPD) size. +#endif + +FfxFloat32x2 DepthUnpackConsts(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DepthUnpackConsts; +#else + return 0; +#endif +} +FfxFloat32x2 CameraTanHalfFOV(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.CameraTanHalfFOV; +#else + return 0; +#endif +} + +FfxFloat32x2 NDCToViewMul(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.NDCToViewMul; +#else + return 0; +#endif +} +FfxFloat32x2 NDCToViewAdd(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.NDCToViewAdd; +#else + return 0; +#endif +} + +FfxFloat32x2 DepthBufferUVToViewMul(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DepthBufferUVToViewMul; +#else + return 0; +#endif +} +FfxFloat32x2 DepthBufferUVToViewAdd(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DepthBufferUVToViewAdd; +#else + return 0; +#endif +} + +FfxFloat32 EffectRadius(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectRadius; +#else + return 0; +#endif +} +FfxFloat32 EffectShadowStrength(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectShadowStrength; +#else + return 0; +#endif +} +FfxFloat32 EffectShadowPow(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectShadowPow; +#else + return 0; +#endif +} +FfxFloat32 EffectShadowClamp(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectShadowClamp; +#else + return 0; +#endif +} + +FfxFloat32 EffectFadeOutMul(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectFadeOutMul; +#else + return 0; +#endif +} +FfxFloat32 EffectFadeOutAdd(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectFadeOutAdd; +#else + return 0; +#endif +} +FfxFloat32 EffectHorizonAngleThreshold(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectHorizonAngleThreshold; +#else + return 0; +#endif +} +FfxFloat32 EffectSamplingRadiusNearLimitRec(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.EffectSamplingRadiusNearLimitRec; +#else + return 0; +#endif +} + +FfxFloat32 DepthPrecisionOffsetMod(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DepthPrecisionOffsetMod; +#else + return 0; +#endif +} +FfxFloat32 NegRecEffectRadius(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.NegRecEffectRadius; +#else + return 0; +#endif +} +FfxFloat32 LoadCounterAvgDiv(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.LoadCounterAvgDiv; +#else + return 0; +#endif +} +FfxFloat32 AdaptiveSampleCountLimit(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.AdaptiveSampleCountLimit; +#else + return 0; +#endif +} + +FfxFloat32 InvSharpness(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.InvSharpness; +#else + return 0; +#endif +} +FfxInt32 BlurNumPasses(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.BlurNumPasses; +#else + return 0; +#endif +} +FfxFloat32 BilateralSigmaSquared(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.BilateralSigmaSquared; +#else + return 0; +#endif +} +FfxFloat32 BilateralSimilarityDistanceSigma(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.BilateralSimilarityDistanceSigma; +#else + return 0; +#endif +} + +FfxFloat32x4 PatternRotScaleMatrices(uint i, uint j){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.PatternRotScaleMatrices[i][j]; +#else + return 0; +#endif +} + +FfxFloat32 NormalsUnpackMul(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.NormalsUnpackMul; +#else + return 0; +#endif +} +FfxFloat32 NormalsUnpackAdd(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.NormalsUnpackAdd; +#else + return 0; +#endif +} +FfxFloat32 DetailAOStrength(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DetailAOStrength; +#else + return 0; +#endif +} +FfxFloat32 Dummy0(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.Dummy0; +#else + return 0; +#endif +} + +FfxFloat32x2 SSAOBufferDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.SSAOBufferDimensions; +#else + return 0; +#endif +} +FfxFloat32x2 SSAOBufferInverseDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.SSAOBufferInverseDimensions; +#else + return 0; +#endif +} + +FfxFloat32x2 DepthBufferDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DepthBufferDimensions; +#else + return 0; +#endif +} +FfxFloat32x2 DepthBufferInverseDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DepthBufferInverseDimensions; +#else + return 0; +#endif +} + +FfxInt32x2 DepthBufferOffset(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DepthBufferOffset; +#else + return 0; +#endif +} +FfxFloat32x4 PerPassFullResUVOffset(uint i){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.PerPassFullResUVOffset[i]; +#else + return 0; +#endif +} + +FfxFloat32x2 OutputBufferDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.OutputBufferDimensions; +#else + return 0; +#endif +} +FfxFloat32x2 OutputBufferInverseDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.OutputBufferInverseDimensions; +#else + return 0; +#endif +} + +FfxFloat32x2 ImportanceMapDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.ImportanceMapDimensions; +#else + return 0; +#endif +} +FfxFloat32x2 ImportanceMapInverseDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.ImportanceMapInverseDimensions; +#else + return 0; +#endif +} + +FfxFloat32x2 DeinterleavedDepthBufferDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DeinterleavedDepthBufferDimensions; +#else + return 0; +#endif +} +FfxFloat32x2 DeinterleavedDepthBufferInverseDimensions(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DeinterleavedDepthBufferInverseDimensions; +#else + return 0; +#endif +} + +FfxFloat32x2 DeinterleavedDepthBufferOffset(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DeinterleavedDepthBufferOffset; +#else + return 0; +#endif +} +FfxFloat32x2 DeinterleavedDepthBufferNormalisedOffset(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.DeinterleavedDepthBufferNormalisedOffset; +#else + return 0; +#endif +} + +mat4 NormalsWorldToViewspaceMatrix(){ +#if defined(CACAO_BIND_CB_CACAO) + return g_FFX_CACAO_Consts.NormalsWorldToViewspaceMatrix; +#else + return 0; +#endif +} + +layout (set=0, binding = 1000) uniform sampler g_PointClampSampler; +layout (set=0, binding = 1001) uniform sampler g_PointMirrorSampler; +layout (set=0, binding = 1002) uniform sampler g_LinearClampSampler; +layout (set=0, binding = 1003) uniform sampler g_ViewspaceDepthTapSampler; +layout (set=0, binding = 1004) uniform sampler g_RealPointClampSampler; + + +#if defined CACAO_BIND_SRV_DEPTH_IN + layout (set=0, binding = CACAO_BIND_SRV_DEPTH_IN) uniform texture2D g_DepthIn; +#endif +#if defined CACAO_BIND_SRV_NORMAL_IN + layout (set=0, binding = CACAO_BIND_SRV_NORMAL_IN) uniform texture2D g_NormalIn; +#endif +#if defined CACAO_BIND_SRV_LOAD_COUNTER + layout (set=0, binding = CACAO_BIND_SRV_LOAD_COUNTER) uniform utexture1D g_LoadCounter; +#endif +#if defined CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS + layout (set=0, binding = CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS) uniform texture2DArray g_DeinterleavedDepth; +#endif +#if defined CACAO_BIND_SRV_DEINTERLEAVED_NORMALS + layout (set=0, binding = CACAO_BIND_SRV_DEINTERLEAVED_NORMALS) uniform texture2DArray g_DeinterleavedNormals; +#endif +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PING + layout (set=0, binding = CACAO_BIND_SRV_SSAO_BUFFER_PING) uniform texture2DArray g_SsaoBufferPing; +#endif +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PONG + layout (set=0, binding = CACAO_BIND_SRV_SSAO_BUFFER_PONG) uniform texture2DArray g_SsaoBufferPong; +#endif +#if defined CACAO_BIND_SRV_IMPORTANCE_MAP + layout (set=0, binding = CACAO_BIND_SRV_IMPORTANCE_MAP) uniform texture2D g_ImportanceMap; +#endif +#if defined CACAO_BIND_SRV_IMPORTANCE_MAP_PONG + layout (set=0, binding = CACAO_BIND_SRV_IMPORTANCE_MAP_PONG) uniform texture2D g_ImportanceMapPong; +#endif + +#if defined CACAO_BIND_UAV_LOAD_COUNTER + layout (set=0, binding = CACAO_BIND_UAV_LOAD_COUNTER, r32ui) uniform uimage1D g_RwLoadCounter; +#endif +#if defined CACAO_BIND_UAV_DEINTERLEAVED_DEPTHS + layout (set=0, binding = CACAO_BIND_UAV_DEINTERLEAVED_DEPTHS, r32f) uniform image2DArray g_RwDeinterleavedDepth; +#endif +#if defined CACAO_BIND_UAV_DEINTERLEAVED_NORMALS + layout (set=0, binding = CACAO_BIND_UAV_DEINTERLEAVED_NORMALS, rgba32f) uniform image2DArray g_RwDeinterleavedNormals; +#endif +#if defined CACAO_BIND_UAV_SSAO_BUFFER_PING + layout (set=0, binding = CACAO_BIND_UAV_SSAO_BUFFER_PING, rg32f) uniform image2DArray g_RwSsaoBufferPing; +#endif +#if defined CACAO_BIND_UAV_SSAO_BUFFER_PONG + layout (set=0, binding = CACAO_BIND_UAV_SSAO_BUFFER_PONG, rg32f) uniform image2DArray g_RwSsaoBufferPong; +#endif +#if defined CACAO_BIND_UAV_IMPORTANCE_MAP + layout (set = 0, binding = CACAO_BIND_UAV_IMPORTANCE_MAP, r32f) uniform image2D g_RwImportanceMap; +#endif +#if defined CACAO_BIND_UAV_IMPORTANCE_MAP_PONG + layout (set = 0, binding = CACAO_BIND_UAV_IMPORTANCE_MAP_PONG, r32f) uniform image2D g_RwImportanceMapPong; +#endif +#if defined CACAO_BIND_UAV_OUTPUT + layout (set = 0, binding = CACAO_BIND_UAV_OUTPUT, rgba16f) uniform image2D g_RwOutput; +#endif +#if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS + layout (set = 0, binding = CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS, r32f) uniform image2DArray g_RwDepthMips[4]; +#endif + +// ============================================================================= +// Clear Load Counter +#if defined CACAO_BIND_UAV_LOAD_COUNTER +void FFX_CACAO_ClearLoadCounter_SetLoadCounter(FfxUInt32 val) +{ + imageStore(g_RwLoadCounter, 0, FfxUInt32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_LOAD_COUNTER + +// ============================================================================= +// Edge Sensitive Blur +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PING +FfxFloat32x2 FFX_CACAO_EdgeSensitiveBlur_SampleInput(FfxFloat32x2 uv, FfxUInt32 layerId) +{ + return textureLod(sampler2DArray(g_SsaoBufferPing, g_PointMirrorSampler), FfxFloat32x3(uv, FfxFloat32(layerId)), 0.0f).xy; +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PING + +#if defined CACAO_BIND_UAV_SSAO_BUFFER_PONG +void FFX_CACAO_EdgeSensitiveBlur_StoreOutput(FfxUInt32x2 coord, FfxFloat32x2 value, FfxUInt32 layerId) +{ + imageStore(g_RwSsaoBufferPong, FfxInt32x3(coord, layerId), FfxFloat32x4(value, 0, 0)); +} +#endif // #if defined CACAO_BIND_UAV_SSAO_BUFFER_PONG + +// ============================================================================= +// SSAO Generation +#if defined CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS +FfxFloat32 FFX_CACAO_SSAOGeneration_SampleViewspaceDepthMip(FfxFloat32x2 uv, FfxFloat32 mip, FfxUInt32 layerId) +{ + return textureLod(sampler2DArray(g_DeinterleavedDepth, g_ViewspaceDepthTapSampler), FfxFloat32x3(uv, FfxFloat32(layerId)), mip).x; +} +#endif // #if defined CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS + +#if defined CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS +FfxFloat32x4 FFX_CACAO_SSAOGeneration_GatherViewspaceDepthOffset(FfxFloat32x2 uv, FfxInt32x2 offset, FfxUInt32 layerId) +{ + return textureGatherOffset(sampler2DArray(g_DeinterleavedDepth, g_PointMirrorSampler), FfxFloat32x3(uv, FfxFloat32(layerId)), offset, 0); +} +#endif // #if defined CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS + +#if defined CACAO_BIND_SRV_LOAD_COUNTER +FfxUInt32 FFX_CACAO_SSAOGeneration_GetLoadCounter() +{ + return FfxUInt32(texelFetch(g_LoadCounter, 0, 0).x); +} +#endif // #if defined CACAO_BIND_SRV_LOAD_COUNTER + +#if defined CACAO_BIND_SRV_IMPORTANCE_MAP +FfxFloat32 FFX_CACAO_SSAOGeneration_SampleImportance(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_ImportanceMap, g_LinearClampSampler), uv, 0.0f).x; +} +#endif // #if defined CACAO_BIND_SRV_IMPORTANCE_MAP + +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PONG +FfxFloat32x2 FFX_CACAO_SSAOGeneration_LoadBasePassSSAOPass(FfxUInt32x2 coord, FfxUInt32 pass) +{ + return texelFetch(g_SsaoBufferPong, FfxInt32x3(coord, pass), 0).xy; +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PONG + +#if defined CACAO_BIND_SRV_DEINTERLEAVED_NORMALS +FfxFloat32x3 FFX_CACAO_SSAOGeneration_GetNormalPass(FfxUInt32x2 coord, FfxUInt32 pass) +{ + return texelFetch(g_DeinterleavedNormals, FfxInt32x3(coord, pass), 0).xyz; +} +#endif // #if defined CACAO_BIND_SRV_DEINTERLEAVED_NORMALS + +#if defined CACAO_BIND_UAV_SSAO_BUFFER_PING +void FFX_CACAO_SSAOGeneration_StoreOutput(FfxUInt32x2 coord, FfxFloat32x2 val, FfxUInt32 layerId) +{ + imageStore(g_RwSsaoBufferPing, FfxInt32x3(coord, layerId), FfxFloat32x4(val, 0, 0)); +} +#endif // #if defined CACAO_BIND_UAV_SSAO_BUFFER_PING + +// ============================================================================ +// Apply +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PING +FfxFloat32 FFX_CACAO_Apply_SampleSSAOUVPass(FfxFloat32x2 uv, FfxUInt32 pass) +{ + return textureLod(sampler2DArray(g_SsaoBufferPing, g_LinearClampSampler), FfxFloat32x3(uv, pass), 0.0f).x; +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PING + +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PING +FfxFloat32x2 FFX_CACAO_Apply_LoadSSAOPass(FfxUInt32x2 coord, FfxUInt32 pass) +{ + return texelFetch(g_SsaoBufferPing, FfxInt32x3(coord, pass), 0).xy; +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PING + +#if defined CACAO_BIND_UAV_OUTPUT +void FFX_CACAO_Apply_StoreOutput(FfxUInt32x2 coord, FfxFloat32 val) +{ + FfxFloat32x4 prev = imageLoad(g_RwOutput, FfxInt32x2(coord)); + imageStore(g_RwOutput, FfxInt32x2(coord), FfxFloat32x4(val, prev.g, prev.b, prev.a)); +} +#endif // #if defined CACAO_BIND_UAV_OUTPUT + +// ============================================================================= +// Prepare +#if defined CACAO_BIND_SRV_DEPTH_IN +FfxFloat32x4 FFX_CACAO_Prepare_SampleDepthOffsets(FfxFloat32x2 uv) +{ + FfxFloat32x4 samples; + samples.x = textureLodOffset(sampler2D(g_DepthIn, g_PointClampSampler), uv, 0.0f, FfxInt32x2(0, 2)).x; + samples.y = textureLodOffset(sampler2D(g_DepthIn, g_PointClampSampler), uv, 0.0f, FfxInt32x2(2, 2)).x; + samples.z = textureLodOffset(sampler2D(g_DepthIn, g_PointClampSampler), uv, 0.0f, FfxInt32x2(2, 0)).x; + samples.w = textureLodOffset(sampler2D(g_DepthIn, g_PointClampSampler), uv, 0.0f, FfxInt32x2(0, 0)).x; + return samples; +} +#endif // #if defined CACAO_BIND_SRV_DEPTH_IN + +#if defined CACAO_BIND_SRV_DEPTH_IN +FfxFloat32x4 FFX_CACAO_Prepare_GatherDepth(FfxFloat32x2 uv) +{ + return textureGather(sampler2D(g_DepthIn, g_PointClampSampler), uv, 0); +} +#endif // #if defined CACAO_BIND_SRV_DEPTH_IN + +#if defined CACAO_BIND_SRV_DEPTH_IN +FfxFloat32 FFX_CACAO_Prepare_LoadDepth(FfxUInt32x2 coord) +{ + return texelFetch(g_DepthIn, FfxInt32x2(coord), 0).x; +} +#endif // #if defined CACAO_BIND_SRV_DEPTH_IN + +#if defined CACAO_BIND_SRV_DEPTH_IN +FfxFloat32 FFX_CACAO_Prepare_LoadDepthOffset(FfxUInt32x2 coord, FfxInt32x2 offset) +{ + return texelFetch(g_DepthIn, FfxInt32x2(coord) + offset, 0).x; //CACAO_TODO +} +#endif // #if defined CACAO_BIND_SRV_DEPTH_IN + +#if defined CACAO_BIND_SRV_DEPTH_IN +FfxFloat32x4 FFX_CACAO_Prepare_GatherDepthOffset(FfxFloat32x2 uv, FfxInt32x2 offset) +{ + return textureGatherOffset(sampler2D(g_DepthIn, g_PointClampSampler), uv, offset, 0); +} +#endif // #if defined CACAO_BIND_SRV_DEPTH_IN + +#if defined CACAO_BIND_SRV_NORMAL_IN +FfxFloat32x3 FFX_CACAO_Prepare_LoadNormal(FfxUInt32x2 coord) +{ + FfxFloat32x3 normal = texelFetch(g_NormalIn, FfxInt32x2(coord), 0).xyz; + normal = normal * NormalsUnpackMul().xxx + NormalsUnpackAdd().xxx; + normal = FFX_TRANSFORM_VECTOR(normal, FfxFloat32x3x3(NormalsWorldToViewspaceMatrix())).xyz; + return normal; +} +#endif // #if defined CACAO_BIND_SRV_NORMAL_IN + +#if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS +void FFX_CACAO_Prepare_StoreDepthMip0(FfxUInt32x2 coord, FfxUInt32 index, FfxFloat32 val) +{ + imageStore(g_RwDepthMips[0], FfxInt32x3(coord, index), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS + +#if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS +void FFX_CACAO_Prepare_StoreDepthMip1(FfxUInt32x2 coord, FfxUInt32 index, FfxFloat32 val) +{ + imageStore(g_RwDepthMips[1], FfxInt32x3(coord, index), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS + +#if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS +void FFX_CACAO_Prepare_StoreDepthMip2(FfxUInt32x2 coord, FfxUInt32 index, FfxFloat32 val) +{ + imageStore(g_RwDepthMips[2], FfxInt32x3(coord, index), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS + +#if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS +void FFX_CACAO_Prepare_StoreDepthMip3(FfxUInt32x2 coord, FfxUInt32 index, FfxFloat32 val) +{ + imageStore(g_RwDepthMips[3], FfxInt32x3(coord, index), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_DEPTH_DOWNSAMPLED_MIPS + +#if defined CACAO_BIND_UAV_DEINTERLEAVED_DEPTHS +void FFX_CACAO_Prepare_StoreDepth(FfxUInt32x2 coord, FfxUInt32 index, FfxFloat32 val) +{ + imageStore(g_RwDeinterleavedDepth, FfxInt32x3(coord, index), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_DEINTERLEAVED_DEPTHS + +#if defined CACAO_BIND_UAV_DEINTERLEAVED_DEPTHS +void FFX_CACAO_Prepare_StoreNormal(FfxUInt32x2 coord, FfxUInt32 index, FfxFloat32x3 normal) +{ + imageStore(g_RwDeinterleavedNormals, FfxInt32x3(coord, index), FfxFloat32x4(normal, 1.0f)); +} +#endif // #if defined CACAO_BIND_UAV_DEINTERLEAVED_DEPTHS + +// ============================================================================= +// Importance Map +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PONG +FfxFloat32x4 FFX_CACAO_Importance_GatherSSAO(FfxFloat32x2 uv, FfxUInt32 index) +{ + return textureGather(sampler2DArray(g_SsaoBufferPong, g_PointClampSampler), FfxFloat32x3(uv, index), 0); +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PONG + +#if defined CACAO_BIND_UAV_IMPORTANCE_MAP +void FFX_CACAO_Importance_StoreImportance(FfxUInt32x2 coord, FfxFloat32 val) +{ + imageStore(g_RwImportanceMap, FfxInt32x2(coord), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_IMPORTANCE_MAP + +#if defined CACAO_BIND_SRV_IMPORTANCE_MAP +FfxFloat32 FFX_CACAO_Importance_SampleImportanceA(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_ImportanceMap, g_LinearClampSampler), uv, 0.0f).x; +} +#endif // #if defined CACAO_BIND_SRV_IMPORTANCE_MAP + +#if defined CACAO_BIND_UAV_IMPORTANCE_MAP_PONG +void FFX_CACAO_Importance_StoreImportanceA(FfxUInt32x2 coord, FfxFloat32 val) +{ + imageStore(g_RwImportanceMapPong, FfxInt32x2(coord), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_IMPORTANCE_MAP_PONG + +#if defined CACAO_BIND_SRV_IMPORTANCE_MAP_PONG +FfxFloat32 FFX_CACAO_Importance_SampleImportanceB(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(g_ImportanceMapPong, g_LinearClampSampler), uv, 0.0f).x; +} +#endif // #if defined CACAO_BIND_SRV_IMPORTANCE_MAP_PONG + +#if defined CACAO_BIND_UAV_IMPORTANCE_MAP +void FFX_CACAO_Importance_StoreImportanceB(FfxUInt32x2 coord, FfxFloat32 val) +{ + imageStore(g_RwImportanceMap, FfxInt32x2(coord), FfxFloat32x4(val, val, val, val)); +} +#endif // #if defined CACAO_BIND_UAV_IMPORTANCE_MAP + +#if defined CACAO_BIND_UAV_LOAD_COUNTER +void FFX_CACAO_Importance_LoadCounterInterlockedAdd(FfxUInt32 val) +{ + imageAtomicAdd(g_RwLoadCounter, 0, val); +} +#endif // #if defined CACAO_BIND_UAV_LOAD_COUNTER + +// ============================================================================= +// Bilateral Upscale + +// These resources ping/pong which is handled by schedule dispatch +#if defined CACAO_BIND_UAV_OUTPUT +void FFX_CACAO_BilateralUpscale_StoreOutput(FfxUInt32x2 coord, FfxInt32x2 offset, FfxFloat32 val) +{ + FfxFloat32x4 prev = imageLoad(g_RwOutput, FfxInt32x2(coord) + offset); + imageStore(g_RwOutput, FfxInt32x2(coord) + offset, FfxFloat32x4(val, prev.g, prev.b, prev.a)); +} +#endif // #if defined CACAO_BIND_UAV_OUTPUT + +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PING +FfxFloat32 FFX_CACAO_BilateralUpscale_SampleSSAOLinear(FfxFloat32x2 uv, FfxUInt32 index) +{ + return textureLod(sampler2DArray(g_SsaoBufferPing, g_LinearClampSampler), FfxFloat32x3(uv, index), 0).r; +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PING + +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PING +FfxFloat32 FFX_CACAO_BilateralUpscale_SampleSSAOPoint(FfxFloat32x2 uv, FfxUInt32 index) +{ + return textureLod(sampler2DArray(g_SsaoBufferPing, g_PointClampSampler), FfxFloat32x3(uv, index), 0).r; +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PING + +#if defined CACAO_BIND_SRV_SSAO_BUFFER_PING +FfxFloat32x2 FFX_CACAO_BilateralUpscale_LoadSSAO(FfxUInt32x2 coord, FfxUInt32 index) +{ + return texelFetch(g_SsaoBufferPing, FfxInt32x3(coord, index), 0).rg; +} +#endif // #if defined CACAO_BIND_SRV_SSAO_BUFFER_PING + +#if defined CACAO_BIND_SRV_DEPTH_IN +FfxFloat32x4 FFX_CACAO_BilateralUpscale_LoadDepths(FfxUInt32x2 coord) +{ + FfxFloat32x4 depths; + depths.x = texelFetchOffset(g_DepthIn, FfxInt32x2(coord), 0, FfxInt32x2(0, 0)).x; + depths.y = texelFetchOffset(g_DepthIn, FfxInt32x2(coord), 0, FfxInt32x2(1, 0)).x; + depths.z = texelFetchOffset(g_DepthIn, FfxInt32x2(coord), 0, FfxInt32x2(0, 1)).x; + depths.w = texelFetchOffset(g_DepthIn, FfxInt32x2(coord), 0, FfxInt32x2(1, 1)).x; + return depths; +} +#endif // #if defined CACAO_BIND_SRV_DEPTH_IN + +#if defined CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS +FfxFloat32 FFX_CACAO_BilateralUpscale_LoadDownscaledDepth(FfxUInt32x2 coord, FfxUInt32 index) +{ + return texelFetch(g_DeinterleavedDepth, FfxInt32x3(coord, index), 0).x; +} +#endif // #if defined CACAO_BIND_SRV_DEINTERLEAVED_DEPTHS + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cas/CMakeCompileCASShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cas/CMakeCompileCASShaders.txt new file mode 100644 index 00000000..e4943597 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cas/CMakeCompileCASShaders.txt @@ -0,0 +1,47 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(CAS_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(CAS_PERMUTATION_ARGS + -DFFX_CAS_OPTION_SHARPEN_ONLY={0,1} + -DFFX_CAS_COLOR_SPACE_CONVERSION={0,1,2,3,4}) + +set(CAS_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/cas") + +if (NOT CAS_SHADER_EXT) + set(CAS_SHADER_EXT *) +endif() + +file(GLOB CAS_SHADERS + "shaders/cas/ffx_cas_sharpen_pass.${CAS_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${CAS_BASE_ARGS}" "${CAS_API_BASE_ARGS}" "${CAS_PERMUTATION_ARGS}" "${CAS_INCLUDE_ARGS}" + "${CAS_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" CAS_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${CAS_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cas/ffx_cas_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cas/ffx_cas_callbacks_glsl.h new file mode 100644 index 00000000..d3ad38f8 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/cas/ffx_cas_callbacks_glsl.h @@ -0,0 +1,184 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_cas_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(CAS_BIND_CB_CAS) +layout(set = 0, binding = CAS_BIND_CB_CAS, std140) uniform cbCAS_t +{ + FfxUInt32x4 const0; + FfxUInt32x4 const1; +} +cbCAS; +#endif + +FfxUInt32x4 Const0() +{ +#if defined(CAS_BIND_CB_CAS) + return cbCAS.const0; +#else + return 0.f; +#endif +} + +FfxUInt32x4 Const1() +{ +#if defined(CAS_BIND_CB_CAS) + return cbCAS.const1; +#else + return 0.f; +#endif +} + +layout(set = 0, binding = 1000) uniform sampler s_LinearClamp; + + // SRVs + #if defined CAS_BIND_SRV_INPUT_COLOR + layout(set = 0, binding = CAS_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color; + #endif + + // UAV declarations + #if defined CAS_BIND_UAV_OUTPUT_COLOR + layout(set = 0, binding = CAS_BIND_UAV_OUTPUT_COLOR, rgba16) uniform image2D rw_output_color; + #endif + +#if FFX_HALF + + FfxFloat16x3 casLoadHalf(FFX_PARAMETER_IN FfxInt16x2 position) + { + #if defined(CAS_BIND_SRV_INPUT_COLOR) + return FfxFloat16x3(texelFetch(r_input_color, FfxInt32x2(position), 0).rgb); + #else + return FfxFloat16x3(0.f); + #endif + } + + // Transform input from the load into a linear color space between 0 and 1. + void casInputHalf(FFX_PARAMETER_INOUT FfxFloat16x2 red, FFX_PARAMETER_INOUT FfxFloat16x2 green, FFX_PARAMETER_INOUT FfxFloat16x2 blue) + { + #if FFX_CAS_COLOR_SPACE_CONVERSION == 1 // gamma 2.0 + red *= red; + green *= green; + blue *= blue; + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 2 // gamma 2.2 + red = ffxLinearFromGammaHalf(red, FfxFloat16(2.2f)); + green = ffxLinearFromGammaHalf(green, FfxFloat16(2.2f)); + blue = ffxLinearFromGammaHalf(blue, FfxFloat16(2.2f)); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 3 // sRGB output (auto-degamma'd on sampler read) + + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 4 // sRGB input/output + red = ffxLinearFromSrgbHalf(red); + green = ffxLinearFromSrgbHalf(green); + blue = ffxLinearFromSrgbHalf(blue); + #endif + } + + void casOutputHalf(FFX_PARAMETER_INOUT FfxFloat16x2 red, FFX_PARAMETER_INOUT FfxFloat16x2 green, FFX_PARAMETER_INOUT FfxFloat16x2 blue) + { + #if FFX_CAS_COLOR_SPACE_CONVERSION == 1 // gamma 2.0 + red = ffxSqrt(red); + green = ffxSqrt(green); + blue = ffxSqrt(blue); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 2 // gamma 2.2 + red = ffxGammaFromLinearHalf(red, FfxFloat16(1/2.2f)); + green = ffxGammaFromLinearHalf(green, FfxFloat16(1/2.2f)); + blue = ffxGammaFromLinearHalf(blue, FfxFloat16(1/2.2f)); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 3 // sRGB output (auto-degamma'd on sampler read) + red = ffxSrgbFromLinearHalf(red); + green = ffxSrgbFromLinearHalf(green); + blue = ffxSrgbFromLinearHalf(blue); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 4 // sRGB input/output + red = ffxSrgbFromLinearHalf(red); + green = ffxSrgbFromLinearHalf(green); + blue = ffxSrgbFromLinearHalf(blue); + #endif + } + + #else + + FfxFloat32x3 casLoad(FFX_PARAMETER_IN FfxInt32x2 position) + { + #if defined(CAS_BIND_SRV_INPUT_COLOR) + return texelFetch(r_input_color, position, 0).rgb; + #else + return FfxFloat32x3(0.f); + #endif + } + + // Transform input from the load into a linear color space between 0 and 1. + void casInput(FFX_PARAMETER_INOUT FfxFloat32 red, FFX_PARAMETER_INOUT FfxFloat32 green, FFX_PARAMETER_INOUT FfxFloat32 blue) + { + #if FFX_CAS_COLOR_SPACE_CONVERSION == 1 // gamma 2.0 + red *= red; + green *= green; + blue *= blue; + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 2 // gamma 2.2 + red = ffxLinearFromGamma(red, FfxFloat32(2.2f)); + green = ffxLinearFromGamma(green, FfxFloat32(2.2f)); + blue = ffxLinearFromGamma(blue, FfxFloat32(2.2f)); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 3 // sRGB output (auto-degamma'd on sampler read) + + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 4 // sRGB input/output + red = ffxLinearFromSrgb(red); + green = ffxLinearFromSrgb(green); + blue = ffxLinearFromSrgb(blue); + #endif + } + + void casOutput(FFX_PARAMETER_INOUT FfxFloat32 red, FFX_PARAMETER_INOUT FfxFloat32 green, FFX_PARAMETER_INOUT FfxFloat32 blue) + { + #if FFX_CAS_COLOR_SPACE_CONVERSION == 1 // gamma 2.0 + red = ffxSqrt(red); + green = ffxSqrt(green); + blue = ffxSqrt(blue); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 2 // gamma 2.2 + red = ffxGammaFromLinear(red, FfxFloat32(1/2.2f)); + green = ffxGammaFromLinear(green, FfxFloat32(1/2.2f)); + blue = ffxGammaFromLinear(blue, FfxFloat32(1/2.2f)); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 3 // sRGB output (auto-degamma'd on sampler read) + red = ffxSrgbFromLinear(red); + green = ffxSrgbFromLinear(green); + blue = ffxSrgbFromLinear(blue); + #elif FFX_CAS_COLOR_SPACE_CONVERSION == 4 // sRGB input/output + red = ffxSrgbFromLinear(red); + green = ffxSrgbFromLinear(green); + blue = ffxSrgbFromLinear(blue); + #endif + } + + #endif // FFX_HALF + + void casStoreOutput(FfxInt32x2 iPxPos, FfxFloat32x4 fColor) + { + #if defined(CAS_BIND_UAV_OUTPUT_COLOR) + imageStore(rw_output_color, iPxPos, fColor); + #endif + } + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/CMakeCompileClassifierShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/CMakeCompileClassifierShaders.txt new file mode 100644 index 00000000..b62699ea --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/CMakeCompileClassifierShaders.txt @@ -0,0 +1,49 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(CLASSIFIER_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(CLASSIFIER_PERMUTATION_ARGS + -DFFX_CLASSIFIER_OPTION_INVERTED_DEPTH={0,1} + -DFFX_CLASSIFIER_OPTION_CLASSIFIER_MODE={0,1} +) + +set(CLASSIFIER_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/classifier") + +if (NOT CLASSIFIER_SHADER_EXT) + set(CLASSIFIER_SHADER_EXT *) +endif() + +file(GLOB CLASSIFIER_SHADERS + "shaders/classifier/ffx_classifier_shadows_pass.${CLASSIFIER_SHADER_EXT}" + "shaders/classifier/ffx_classifier_reflections_pass.${CLASSIFIER_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${CLASSIFIER_BASE_ARGS}" "${CLASSIFIER_API_BASE_ARGS}" "${CLASSIFIER_PERMUTATION_ARGS}" "${CLASSIFIER_INCLUDE_ARGS}" + "${CLASSIFIER_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" CLASSIFIER_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${CLASSIFIER_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_common.h new file mode 100644 index 00000000..3e896fd5 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_common.h @@ -0,0 +1,102 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#define TILE_SIZE_X 8 +#define TILE_SIZE_Y 4 +#define k_pushOff 4e-2f +#define k_tileSize FfxUInt32x2(TILE_SIZE_X, TILE_SIZE_Y) + +//-------------------------------------------------------------------------------------- +// I/O Structures +//-------------------------------------------------------------------------------------- + +struct Tile +{ +#if FFX_HALF + FfxUInt16x2 location; +#else + FfxUInt32x2 location; // Dead code, f32 not supported +#endif + FfxUInt32 mask; + + FfxFloat32 minT; + FfxFloat32 maxT; +}; + +Tile TileCreate(const FfxUInt32x2 id) +{ +#if FFX_HALF + FfxUInt16x2 f16ID = FfxUInt16x2(FfxUInt16(id.x), FfxUInt16(id.y)); + Tile t = { f16ID, 0, k_pushOff, FFX_POSITIVE_INFINITY_FLOAT }; // skyHeight +#else + Tile t = { id, 0, k_pushOff, FFX_POSITIVE_INFINITY_FLOAT }; //skyHeight +#endif + return t; +} + +FfxUInt32x4 TileToUint(const Tile t) +{ + const FfxUInt32x4 ui = FfxUInt32x4((FfxUInt32(t.location.y) << 16) | FfxUInt32(t.location.x), t.mask, ffxAsUInt32(t.minT), ffxAsUInt32(t.maxT)); + return ui; +} + +Tile TileFromUint(const FfxUInt32x4 ui) +{ +#if FFX_HALF + FfxUInt16x2 id = FfxUInt16x2(ui.x & 0xffff, (ui.x >> 16) & 0xffff); +#else + FfxUInt32x2 id; +#endif + Tile t = { id, ui.y, ffxAsFloat(ui.z), ffxAsFloat(ui.w) }; + return t; +} + +//-------------------------------------------------------------------------------------- +// helper functions +//-------------------------------------------------------------------------------------- + +FfxUInt32 LaneIdToBitShift(FfxUInt32x2 localID) +{ + return localID.y * TILE_SIZE_X + localID.x; +} + +FfxUInt32 BoolToWaveMask(FfxBoolean b, FfxUInt32x2 localID) +{ + const FfxUInt32 value = FfxUInt32(b) << LaneIdToBitShift(localID); + return ffxWaveOr(value); +} + +FfxBoolean WaveMaskToBool(FfxUInt32 mask, FfxUInt32x2 localID) +{ + return FfxBoolean((FfxUInt32(1) << LaneIdToBitShift(localID)) & mask); +} + + +#define k_pi 3.1415926535897932384f +#define k_2pi 2.0f * k_pi +#define k_pi_over_2 0.5f * k_pi + +// made using a modified version of https://www.asawicki.info/news_952_poisson_disc_generator +#define k_poissonDiscSampleCountLow 8 +#define k_poissonDiscSampleCountMid 16 +#define k_poissonDiscSampleCountHigh 24 +#define k_poissonDiscSampleCountUltra 32 diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections.h new file mode 100644 index 00000000..9ac58a86 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections.h @@ -0,0 +1,378 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#define TILE_CLASS_FULL_SW 0 +#define TILE_CLASS_HALF_SW 1 +#define TILE_CLASS_FULL_HW 2 + +#define FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + +#include "ffx_classifier_reflections_common.h" + +FfxFloat32x2 Hash22(FfxFloat32x2 p) +{ + FfxFloat32x3 p3 = ffxFract(FfxFloat32x3(p.xyx) * FfxFloat32x3(.1031, .1030, .0973)); + p3 += dot(p3, p3.yzx + 33.33); + return ffxFract((p3.xx + p3.yz) * p3.zy); +} + +FfxFloat32x2 GetRandom(FfxUInt32x2 index) +{ + FfxFloat32 v = 0.152f; + FfxFloat32x2 pos = (FfxFloat32x2(index) * v + FfxFloat32(FrameIndex()) / 60.0f * 1500.0f + 50.0f); + return Hash22(pos); +} + +FfxFloat32x2 GetRandomLastFrame(FfxUInt32x2 index) +{ + FfxFloat32 v = 0.152f; + FfxFloat32x2 pos = (FfxFloat32x2(index) * v + FfxFloat32(FrameIndex() - 1) / 60.0f * 1500.0f + 50.0f); + return Hash22(pos); +} + +FfxBoolean IsSW(FfxFloat32 hitcounter, FfxFloat32 misscounter, FfxFloat32 rnd) +{ + // Turn a random tile full hybrid once in a while to get the opportunity for testing HiZ traversal + return rnd <= (+HybridSpawnRate() + hitcounter - misscounter * HybridMissWeight()); +} + +FfxBoolean IsConverged(FfxUInt32x2 pixel_coordinate, FfxFloat32x2 uv) +{ + FfxFloat32x2 motion_vector = LoadMotionVector(FfxInt32x2(pixel_coordinate)); + ; + return SampleVarianceHistory(uv - motion_vector) < VRTVarianceThreshold(); +} + +// In case no ray is traced we need to clear the buffers +void FillEnvironment(FfxUInt32x2 ray_coord, FfxFloat32 factor) +{ + // Fall back to the environment probe + FfxUInt32x2 screen_size = FfxUInt32x2(ReflectionWidth(), ReflectionHeight()); + FfxFloat32x2 uv = (ray_coord + 0.5) * InverseRenderSize(); + FfxFloat32x3 world_space_normal = LoadWorldSpaceNormal(FfxInt32x2(ray_coord)); + FfxFloat32 roughness = LoadRoughnessFromMaterialParametersInput(FfxUInt32x3(ray_coord, 0)); + FfxFloat32 z = GetInputDepth(ray_coord); + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, z); + FfxFloat32x3 view_space_ray = ScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 view_space_ray_direction = normalize(view_space_ray); + FfxFloat32x3 view_space_surface_normal = FFX_MATRIX_MULTIPLY(ViewMatrix(), FfxFloat32x4(world_space_normal, 0)).xyz; + FfxFloat32x3 view_space_reflected_direction = reflect(view_space_ray_direction, view_space_surface_normal); + FfxFloat32x3 world_space_reflected_direction = FFX_MATRIX_MULTIPLY(InvView(), FfxFloat32x4(view_space_reflected_direction, 0)).xyz; + FfxFloat32x3 world_space_ray_origin = FFX_MATRIX_MULTIPLY(InvView(), FfxFloat32x4(view_space_ray, 1)).xyz; + + FfxFloat32x3 env_sample = SampleEnvironmentMap(world_space_reflected_direction, sqrt(roughness)); + + if (!any(isnan(env_sample))) + StoreRadiance(ray_coord, env_sample.xyzz * factor); + else + StoreRadiance(ray_coord, (0.0f).xxxx); +} + +void ZeroBuffers(FfxUInt32x2 dispatch_thread_id) +{ + StoreRadiance(dispatch_thread_id, (0.0f).xxxx); +} + +FfxFloat32x2 GetSurfaceReprojection(FfxFloat32x2 uv, FfxFloat32x2 motion_vector) +{ + // Reflector position reprojection + FfxFloat32x2 history_uv = uv - motion_vector; + return history_uv; +} + +FfxBoolean IsBaseRay(FfxUInt32x2 dispatch_thread_id, FfxUInt32 samples_per_quad) +{ + switch (samples_per_quad) + { + case 1: + return ((dispatch_thread_id.x & 1) | (dispatch_thread_id.y & 1)) == 0; // Deactivates 3 out of 4 rays + case 2: + return (dispatch_thread_id.x & 1) == (dispatch_thread_id.y & 1); // Deactivates 2 out of 4 rays. Keeps diagonal. + default: // case 4: + return true; + } +} + +FFX_GROUPSHARED FfxUInt32 g_TileCount; +FFX_GROUPSHARED FfxInt32 g_TileClass; +FFX_GROUPSHARED FfxUInt32 g_SWCount; +FFX_GROUPSHARED FfxUInt32 g_SWCountTotal; +FFX_GROUPSHARED FfxUInt32 g_base_ray_index_sw; + +void ClassifyTiles(FfxUInt32x2 dispatch_thread_id, + FfxUInt32x2 group_thread_id, + FfxFloat32 roughness, + FfxFloat32x3 view_space_surface_normal, + FfxFloat32 depth, + FfxInt32x2 screen_size, + FfxUInt32 samples_per_quad, + FfxBoolean enable_temporal_variance_guided_tracing, + FfxBoolean enable_hitcounter, + FfxBoolean enable_screen_space_tracing, + FfxBoolean enable_hw_ray_tracing) +{ + FfxUInt32 flat_group_thread_id = group_thread_id.x + group_thread_id.y * 8; + FfxBoolean is_first_lane_of_wave = ffxWaveIsFirstLane(); + + if (group_thread_id.x == 0 && group_thread_id.y == 0) + { + // Initialize group shared variables + g_TileCount = 0; + g_SWCount = 0; + g_SWCountTotal = 0; + g_base_ray_index_sw = 0; + +#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + // Initialize per 8x8 tile hit counter + if (enable_hitcounter) + { + // In case we do hybrid + if (enable_screen_space_tracing && enable_hw_ray_tracing) + { + // Feedback counters + // See Intersect.hlsl + FfxUInt32 hitcounter = 0; + + // Use surface motion vectors of one of the 8x8 pixels in the tile to reproject statistics from the previous frame + // Helps a lot in movement to sustain temoporal coherence +#define FFX_CLASSIFIER_CLASSIFICATION_REPROJECT_HITCOUNTER +#ifdef FFX_CLASSIFIER_CLASSIFICATION_REPROJECT_HITCOUNTER + { + // Grab motion vector from a random point in the subgroup + FfxFloat32x2 xi = GetRandom(dispatch_thread_id.xy / 8); + FfxInt32x2 mix = FfxInt32x2(xi * 8.0f); + FfxFloat32x2 motion_vector = LoadMotionVector(FfxInt32x2(dispatch_thread_id) + mix); + FfxFloat32x2 uv8 = (FfxFloat32x2(dispatch_thread_id.xy + mix)) / FFX_DNSR_Reflections_RoundUp8(screen_size); + FfxFloat32x2 surface_reprojection_uv = GetSurfaceReprojection(uv8, motion_vector); + hitcounter = LoadHitCounterHistory(FfxUInt32x2(surface_reprojection_uv * (FFX_DNSR_Reflections_RoundUp8(screen_size) / 8))); + } +#endif // FFX_CLASSIFIER_CLASSIFICATION_REPROJECT_HITCOUNTER + + // Use 3x3 region to grab the biggest success rate and create a safe band of hybrid rays to hide artefacts in movements +#define FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND +#ifdef FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND + FfxUInt32 same_pixel_hitcounter = 0; + // We need a safe band for some geometry not in the BVH to avoid fireflies + const FfxInt32 radius = 1; + for (FfxInt32 y = -radius; y <= radius; y++) + { + for (FfxInt32 x = -radius; x <= radius; x++) + { + FfxUInt32 pt = LoadHitCounterHistory(dispatch_thread_id.xy / 8 + FfxInt32x2(x, y)); + if (FFX_Hitcounter_GetSWHits(pt) > FFX_Hitcounter_GetSWHits(same_pixel_hitcounter)) + same_pixel_hitcounter = pt; + } + } +#else // FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND + FfxUInt32 same_pixel_hitcounter = LoadHitCounterHistory(dispatch_thread_id.xy / 8); +#endif // FFX_CLASSIFIER_CLASSIFICATION_SAFEBAND + + // Again compare with the same pixel and Pick the one with the biggest success rate + if (FFX_Hitcounter_GetSWHits(hitcounter) < FFX_Hitcounter_GetSWHits(same_pixel_hitcounter)) + hitcounter = same_pixel_hitcounter; + + FfxFloat32 rnd = GetRandom(dispatch_thread_id.xy / 8).x; + FfxFloat32 rnd_last = GetRandomLastFrame(dispatch_thread_id.xy / 8).x; + FfxFloat32 sw_hitcount_new = FfxFloat32(FFX_Hitcounter_GetSWHits(hitcounter)); + FfxFloat32 sw_hitcount_old = FfxFloat32(FFX_Hitcounter_GetOldSWHits(hitcounter)); + FfxFloat32 sw_misscount_new = FfxFloat32(FFX_Hitcounter_GetSWMisses(hitcounter)); + FfxFloat32 sw_misscount_old = FfxFloat32(FFX_Hitcounter_GetOldSWMisses(hitcounter)); + FfxBoolean new_class = IsSW(sw_hitcount_new, sw_misscount_new, rnd); + FfxBoolean old_class = IsSW(sw_hitcount_old, sw_misscount_old, rnd_last); + + // To make transition less obvious we do and extra checkerboard stage + if (new_class == old_class) + { + if (new_class) + { + g_TileClass = TILE_CLASS_FULL_SW; + } + else + { + g_TileClass = TILE_CLASS_FULL_HW; + } + } + else + { + g_TileClass = TILE_CLASS_HALF_SW; + } + sw_hitcount_old = sw_hitcount_new; + sw_misscount_old = sw_misscount_new; + StoreHitCounter(dispatch_thread_id.xy / 8, + (FfxUInt32(clamp(sw_hitcount_old, 0.0f, 255.0f)) << 8) | (FfxUInt32(clamp(sw_misscount_old, 0.0f, 255.0f)) << 24)); + } + } + else + { + g_TileClass = TILE_CLASS_FULL_SW; + } +#endif // FFX_HYBRID_REFLECTIONS + } + FFX_GROUP_MEMORY_BARRIER; + + // First we figure out on a per thread basis if we need to shoot a reflection ray + FfxBoolean is_on_screen = (dispatch_thread_id.x < screen_size.x) && (dispatch_thread_id.y < screen_size.y); + // Allow for additional engine side checks. For example engines could additionally only cast reflection rays for specific depth ranges + FfxBoolean is_surface = !IsBackground(depth); + // Don't shoot a ray on very rough surfaces + FfxBoolean is_glossy_reflection = is_surface && IsGlossyReflection(roughness); + FfxBoolean needs_ray = is_on_screen && is_glossy_reflection; + + // Decide which ray to keep + FfxBoolean is_base_ray = IsBaseRay(dispatch_thread_id, samples_per_quad); + FfxBoolean is_converged = true; + if (enable_temporal_variance_guided_tracing) + { + FfxFloat32x2 uv = (dispatch_thread_id + 0.5) / screen_size; + is_converged = IsConverged(dispatch_thread_id, uv); + } + + needs_ray = needs_ray && (is_base_ray || !is_converged); + + // Extra check for back-facing rays, fresnel, mirror etc. + if (abs(view_space_surface_normal.z) > ReflectionsBackfacingThreshold()) + { + FillEnvironment(dispatch_thread_id, IBLFactor()); + needs_ray = false; + } + + // We need denoiser even for mirrors since ssr/hw transition ends up creating poping tile firefies. + FfxBoolean needs_denoiser = is_glossy_reflection; + + // Next we have to figure out for which pixels that ray is creating the values for. Thus, if we have to copy its value horizontal, vertical or across. + FfxBoolean require_copy = + !needs_ray && needs_denoiser; // Our pixel only requires a copy if we want to run a denoiser on it but don't want to shoot a ray for it. + + FfxBoolean copy_horizontal = FfxBoolean(ffxWaveXorU1(FfxUInt32(require_copy), 1)) && (samples_per_quad != 4) && is_base_ray; // QuadReadAcrossX + FfxBoolean copy_vertical = FfxBoolean(ffxWaveXorU1(FfxUInt32(require_copy), 2)) && (samples_per_quad == 1) && is_base_ray; // QuadReadAcrossY + FfxBoolean copy_diagonal = FfxBoolean(ffxWaveXorU1(FfxUInt32(require_copy), 3)) && (samples_per_quad == 1) && is_base_ray; // QuadReadAcrossDiagonal + + FfxBoolean needs_sw_ray = true; + + // In case there's only software rays we don't do hybridization +#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + needs_sw_ray = needs_ray && enable_screen_space_tracing; + + FfxBoolean needs_hw_ray = false; + if (enable_hw_ray_tracing && roughness < RTRoughnessThreshold()) + { + FfxBoolean checkerboard = ((group_thread_id.x ^ group_thread_id.y) & 1) == 0; + needs_sw_ray = needs_sw_ray && ((g_TileClass == TILE_CLASS_FULL_SW ? true : (g_TileClass == TILE_CLASS_HALF_SW ? checkerboard : false))); + needs_hw_ray = needs_ray && !needs_sw_ray; + } +#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + + FfxUInt32 local_ray_index_in_wave_sw = ffxWavePrefixCountBits(needs_sw_ray); + FfxUInt32 wave_ray_offset_in_group_sw; + FfxUInt32 wave_ray_count_sw = ffxWaveActiveCountBits(needs_sw_ray); + +#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + FfxUInt32 local_ray_index_in_wave_hw = ffxWavePrefixCountBits(needs_hw_ray); + FfxUInt32 wave_ray_count_hw = ffxWaveActiveCountBits(needs_hw_ray); + FfxUInt32 base_ray_index_hw = 0; +#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + + if (is_first_lane_of_wave) + { + if (wave_ray_count_sw > 0) + { +#ifdef FFX_GLSL + wave_ray_offset_in_group_sw = FFX_ATOMIC_ADD(g_SWCount, FfxInt32(wave_ray_count_sw)); +#else + InterlockedAdd(g_SWCount, wave_ray_count_sw, wave_ray_offset_in_group_sw); +#endif + } + +#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + if (wave_ray_count_hw > 0) + IncrementRayCounterHW(wave_ray_count_hw, base_ray_index_hw); +#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + } + + base_ray_index_hw = ffxWaveReadLaneFirstU1(base_ray_index_hw); + wave_ray_offset_in_group_sw = ffxWaveReadLaneFirstU1(wave_ray_offset_in_group_sw); + + FFX_GROUP_MEMORY_BARRIER; + if (flat_group_thread_id == 0 && g_SWCount > 0) + { + // [IMPORTANT] We need to round up to the multiple of 32 for software rays, because of the atomic increment coalescing optimization + g_SWCountTotal = g_SWCount < 32 ? 32 : (g_SWCount > 32 ? 64 : 32); + IncrementRayCounterSW(g_SWCountTotal, g_base_ray_index_sw); + } + FFX_GROUP_MEMORY_BARRIER; + + if (needs_sw_ray) + { + FfxUInt32 ray_index_sw = g_base_ray_index_sw + wave_ray_offset_in_group_sw + local_ray_index_in_wave_sw; + StoreRay(ray_index_sw, dispatch_thread_id, copy_horizontal, copy_vertical, copy_diagonal); + } + +#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + else if (needs_hw_ray) + { + FfxUInt32 ray_index_hw = base_ray_index_hw + local_ray_index_in_wave_hw; + StoreRayHW(ray_index_hw, dispatch_thread_id, copy_horizontal, copy_vertical, copy_diagonal); + } +#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + + if (flat_group_thread_id < g_SWCountTotal - g_SWCount) + { + // [IMPORTANT] We need to round up to the multiple of 32 for software rays, because of the atomic increment coalescing optimization + // Emit helper(dead) lanes to fill up 32 lanes per 8x8 tile + FfxUInt32 ray_index_sw = g_base_ray_index_sw + g_SWCount + flat_group_thread_id; + StoreRaySWHelper(ray_index_sw); + } + + // We only need denoiser if we trace any rays in the tile + if (is_first_lane_of_wave && (wave_ray_count_sw > 0 +#ifdef FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + || wave_ray_count_hw > 0 +#endif // FFX_CLASSIFIER_CLASSIFICATION_HW_RAYTRACING_ENABLED + )) + { + FFX_ATOMIC_ADD(g_TileCount, 1); + } + + FFX_GROUP_MEMORY_BARRIER; // Wait until all waves wrote into g_TileCount + + if (g_TileCount > 0) + { + if (group_thread_id.x == 0 && group_thread_id.y == 0) + { + FfxUInt32 tile_index; + IncrementDenoiserTileCounter(tile_index); + StoreDenoiserTile(tile_index, dispatch_thread_id); + } + } + + if ((!needs_ray && !require_copy) // Discarded for some reason + || (needs_ray && !needs_hw_ray && !needs_sw_ray) // Or needs a ray but was discarded for some other reason + ) + { + if (is_surface) + { + FillEnvironment(dispatch_thread_id, IBLFactor()); + } + else + ZeroBuffers(dispatch_thread_id); + } +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_callbacks_glsl.h new file mode 100644 index 00000000..6cb82ab0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_callbacks_glsl.h @@ -0,0 +1,527 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_classifier_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(CLASSIFIER_BIND_CB_CLASSIFIER) + layout (set = 0, binding = CLASSIFIER_BIND_CB_CLASSIFIER, std140) uniform cbClassifierReflections_t + { + FfxFloat32Mat4 invViewProjection; + FfxFloat32Mat4 projection; + FfxFloat32Mat4 invProjection; + FfxFloat32Mat4 viewMatrix; + FfxFloat32Mat4 invView; + FfxFloat32Mat4 prevViewProjection; + FfxUInt32x2 renderSize; + FfxFloat32x2 inverseRenderSize; + FfxFloat32 iblFactor; + FfxUInt32 frameIndex; + FfxUInt32 samplesPerQuad; + FfxUInt32 temporalVarianceGuidedTracingEnabled; + FfxFloat32 globalRoughnessThreshold; + FfxFloat32 rtRoughnessThreshold; + FfxUInt32 mask; + FfxUInt32 reflectionWidth; + FfxUInt32 reflectionHeight; + FfxFloat32 hybridMissWeight; + FfxFloat32 hybridSpawnRate; + FfxFloat32 vrtVarianceThreshold; + FfxFloat32 reflectionsBackfacingThreshold; + FfxUInt32 randomSamplesPerPixel; + FfxFloat32x2 motionVectorScale; + FfxFloat32 normalsUnpackMul; + FfxFloat32 normalsUnpackAdd; + FfxUInt32 roughnessChannel; + FfxUInt32 isRoughnessPerceptual; + } cbClassifierReflection; + +FfxFloat32Mat4 InvViewProjection() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.invViewProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 Projection() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.projection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 InvProjection() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.invProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 ViewMatrix() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.viewMatrix; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 InvView() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.invView; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 PrevViewProjection() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.prevViewProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxUInt32x2 RenderSize() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.renderSize; +#else + return FfxUInt32x2(0); +#endif +} + +FfxFloat32x2 InverseRenderSize() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.inverseRenderSize; +#else + return FfxFloat32x2(0.0f); +#endif +} + +FfxFloat32 IBLFactor() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.iblFactor; +#else + return 0.0f; +#endif +} + +FfxUInt32 FrameIndex() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.frameIndex; +#else + return 0; +#endif +} + +FfxUInt32 SamplesPerQuad() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.samplesPerQuad; +#else + return 0; +#endif +} + +FfxBoolean TemporalVarianceGuidedTracingEnabled() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return FfxBoolean(cbClassifierReflection.temporalVarianceGuidedTracingEnabled); +#else + return false; +#endif +} + +FfxFloat32 RoughnessThreshold() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.globalRoughnessThreshold; +#else + return 0.0f; +#endif +} + +FfxFloat32 RTRoughnessThreshold() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.rtRoughnessThreshold; +#else + return 0.0f; +#endif +} + +FfxUInt32 Mask() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.mask; +#else + return 0; +#endif +} + +FfxUInt32 ReflectionWidth() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.reflectionWidth; +#else + return 0; +#endif +} + +FfxUInt32 ReflectionHeight() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.reflectionHeight; +#else + return 0; +#endif +} + +FfxFloat32 HybridMissWeight() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.hybridMissWeight; +#else + return 0.f; +#endif +} + +FfxFloat32 HybridSpawnRate() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.hybridSpawnRate; +#else + return 0.f; +#endif +} + +FfxFloat32 VRTVarianceThreshold() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.vrtVarianceThreshold; +#else + return 0.f; +#endif +} + +FfxFloat32 ReflectionsBackfacingThreshold() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.reflectionsBackfacingThreshold; +#else + return 0.f; +#endif +} + +FfxUInt32 RandomSamplesPerPixel() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.randomSamplesPerPixel; +#else + return 0; +#endif +} + +FfxFloat32x2 MotionVectorScale() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.motionVectorScale; +#else + return FfxFloat32x2(0.0f); +#endif +} + +FfxFloat32 NormalsUnpackMul() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.normalsUnpackMul; +#else + return 0.0f; +#endif +} + +FfxFloat32 NormalsUnpackAdd() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.normalsUnpackAdd; +#else + return 0.0f; +#endif +} + +FfxUInt32 RoughnessChannel() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return cbClassifierReflection.roughnessChannel; +#else + return 0; +#endif +} + +FfxBoolean IsRoughnessPerceptual() +{ +#if defined CLASSIFIER_BIND_CB_CLASSIFIER + return FfxBoolean(cbClassifierReflection.isRoughnessPerceptual); +#else + return false; +#endif +} + +#endif // #if defined(CLASSIFIER_BIND_CB_CLASSIFIER) + +layout (set = 0, binding = 1000) uniform sampler s_EnvironmentMapSampler; +layout (set = 0, binding = 1001) uniform sampler s_LinearSampler; + +// SRVs +#if defined CLASSIFIER_BIND_SRV_INPUT_DEPTH + layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_DEPTH) uniform texture2D r_input_depth; +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS + layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors; +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_NORMAL + layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_NORMAL) uniform texture2D r_input_normal; +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS + layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS) uniform texture2D r_input_material_parameters; +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP + layout (set = 0, binding = CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP) uniform textureCube r_input_environment_map; +#endif +#if defined CLASSIFIER_BIND_SRV_VARIANCE_HISTORY + layout (set = 0, binding = CLASSIFIER_BIND_SRV_VARIANCE_HISTORY) uniform texture2D r_variance_history; +#endif +#if defined CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY + layout(set = 0, binding = CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY) uniform utexture2D r_hit_counter_history; +#endif + +// UAVs +#if defined CLASSIFIER_BIND_UAV_RADIANCE + layout (set = 0, binding = CLASSIFIER_BIND_UAV_RADIANCE, rgba32f) uniform image2D rw_radiance; +#endif +#if defined CLASSIFIER_BIND_UAV_RAY_LIST + layout (set = 0, binding = CLASSIFIER_BIND_UAV_RAY_LIST, std430) buffer rw_ray_list_t + { + FfxUInt32 data[]; + } rw_ray_list; +#endif +#if defined CLASSIFIER_BIND_UAV_HW_RAY_LIST + layout(set = 0, binding = CLASSIFIER_BIND_UAV_HW_RAY_LIST, std430) buffer rw_hw_ray_list_t + { + FfxUInt32 data[]; + } rw_hw_ray_list; +#endif +#if defined CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST + layout (set = 0, binding = CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST, std430) buffer rw_denoiser_tile_list_t + { + FfxUInt32 data[]; + } rw_denoiser_tile_list; +#endif +#if defined CLASSIFIER_BIND_UAV_RAY_COUNTER + layout (set = 0, binding = CLASSIFIER_BIND_UAV_RAY_COUNTER, std430) buffer rw_ray_counter_t + { + FfxUInt32 data[]; + } rw_ray_counter; +#endif +#if defined CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS + layout (set = 0, binding = CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS, r32f) uniform image2D rw_extracted_roughness; +#endif +#if defined CLASSIFIER_BIND_UAV_HIT_COUNTER + layout(set = 0, binding = CLASSIFIER_BIND_UAV_HIT_COUNTER, r32ui) uniform uimage2D rw_hit_counter; +#endif + + +FfxFloat32x3 LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ +#if defined(CLASSIFIER_BIND_SRV_INPUT_NORMAL) + return normalize(NormalsUnpackMul() * texelFetch(r_input_normal, pixel_coordinate, 0).xyz + NormalsUnpackAdd()); +#else + return FfxFloat32x3(0.f); +#endif +} + +FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 direction, FfxFloat32 preceptualRoughness) +{ +#if defined(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP) + FfxInt32x2 cubeSize = textureSize(r_input_environment_map, 0); + FfxInt32 maxMipLevel = FfxInt32(log2(FfxFloat32(cubeSize.x > 0 ? cubeSize.x : 1))); + FfxFloat32 lod = clamp(preceptualRoughness * FfxFloat32(maxMipLevel), 0.0, FfxFloat32(maxMipLevel)); + return textureLod(samplerCube(r_input_environment_map, s_EnvironmentMapSampler), direction, lod).xyz * IBLFactor(); +#else + return FfxFloat32x3(0.0f); +#endif +} + +void IncrementRayCounterSW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value) +{ +#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) + original_value = atomicAdd(rw_ray_counter.data[0], value); +#endif +} + +void IncrementRayCounterHW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value) +{ +#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) + original_value = atomicAdd(rw_ray_counter.data[4], value); +#endif +} + +void IncrementDenoiserTileCounter(FFX_PARAMETER_OUT FfxUInt32 original_value) +{ +#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) + original_value = atomicAdd(rw_ray_counter.data[2], 1); +#endif +} + +FfxUInt32 PackRayCoords(FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 ray_x_15bit = ray_coord.x & 32767; // 0b111111111111111 + FfxUInt32 ray_y_14bit = ray_coord.y & 16383; // 0b11111111111111; + FfxUInt32 copy_horizontal_1bit = copy_horizontal ? 1 : 0; + FfxUInt32 copy_vertical_1bit = copy_vertical ? 1 : 0; + FfxUInt32 copy_diagonal_1bit = copy_diagonal ? 1 : 0; + + FfxUInt32 packed = (copy_diagonal_1bit << 31) | (copy_vertical_1bit << 30) | (copy_horizontal_1bit << 29) | (ray_y_14bit << 15) | (ray_x_15bit << 0); + return packed; +} + +void StoreRay(FfxUInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ +#if defined (CLASSIFIER_BIND_UAV_RAY_LIST) + FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace + rw_ray_list.data[index] = packedRayCoords; +#endif +} + +void StoreRaySWHelper(FfxUInt32 index) +{ +#if defined (CLASSIFIER_BIND_UAV_RAY_LIST) + rw_ray_list.data[index] = 0xffffffffu; +#endif +} + +void StoreRayHW(FfxUInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ +#if defined (CLASSIFIER_BIND_UAV_RAY_LIST) + FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace + rw_hw_ray_list.data[index] = packedRayCoords; +#endif +} + +void StoreDenoiserTile(FfxUInt32 index, FfxUInt32x2 tile_coord) +{ +#if defined (CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST) + rw_denoiser_tile_list.data[index] = ((tile_coord.y & 0xffffu) << 16) | ((tile_coord.x & 0xffffu) << 0); // Store out pixel to trace +#endif +} + +void StoreExtractedRoughness(FfxUInt32x2 coordinate, FfxFloat32 roughness) +{ +#if defined (CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS) + imageStore(rw_extracted_roughness, FfxInt32x2(coordinate), FfxFloat32x4(roughness)); +#endif +} + +FfxFloat32 LoadRoughnessFromMaterialParametersInput(FfxUInt32x3 coordinate) +{ +#if defined (CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS) + FfxFloat32 rawRoughness = texelFetch(r_input_material_parameters, FfxInt32x2(coordinate.xy), FfxInt32(coordinate.z))[RoughnessChannel()]; + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +#else + return 0.0f; +#endif +} + +FfxFloat32 SampleVarianceHistory(FfxFloat32x2 coordinate) /**/ +{ +#if defined ( CLASSIFIER_BIND_SRV_VARIANCE_HISTORY ) + return FfxFloat32(textureLod(sampler2D(r_variance_history, s_LinearSampler), coordinate, 0.0f).x); +#else + return 0.0; +#endif +} + +void StoreRadiance(FfxUInt32x2 coordinate, FfxFloat32x4 radiance) +{ +#if defined (CLASSIFIER_BIND_UAV_RADIANCE) + imageStore(rw_radiance, FfxInt32x2(coordinate), radiance); +#endif +} + +FfxFloat32 GetInputDepth(FfxUInt32x2 coordinate) +{ +#if defined (CLASSIFIER_BIND_SRV_INPUT_DEPTH) + return texelFetch(r_input_depth, FfxInt32x2(coordinate), 0).r; +#else + return 0.0f; +#endif +} + +void StoreHitCounter(FfxUInt32x2 coordinate, FfxUInt32 value) +{ +#if defined(CLASSIFIER_BIND_UAV_HIT_COUNTER) + imageStore(rw_hit_counter, FfxInt32x2(coordinate), FfxUInt32x4(value)); +#endif +} + +FfxUInt32 LoadHitCounterHistory(FfxUInt32x2 coordinate) +{ +#if defined(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY) + return FfxUInt32(texelFetch(r_hit_counter_history, FfxInt32x2(coordinate), 0).r); +#else + return 0; +#endif +} + +FfxFloat32x2 LoadMotionVector(FfxInt32x2 pixel_coordinate) +{ +#if defined (CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS) + return MotionVectorScale() * texelFetch(r_input_motion_vectors, pixel_coordinate, 0).xy; +#else + return FfxFloat32x2(0.0f); +#endif +} + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_callbacks_hlsl.h new file mode 100644 index 00000000..d458058d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_callbacks_hlsl.h @@ -0,0 +1,477 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_classifier_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(FFX_GPU) +#pragma warning(disable: 3205) // conversion from larger type to smaller +#endif // #if defined(FFX_GPU) + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_CLASSIFIER_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_CLASSIFIER_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_CLASSIFIER_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(CLASSIFIER_BIND_CB_CLASSIFIER) +cbuffer cbClassifierReflection : FFX_CLASSIFIER_DECLARE_CB(CLASSIFIER_BIND_CB_CLASSIFIER) +{ + FfxFloat32Mat4 invViewProjection; + FfxFloat32Mat4 projection; + FfxFloat32Mat4 invProjection; + FfxFloat32Mat4 viewMatrix; + FfxFloat32Mat4 invView; + FfxFloat32Mat4 prevViewProjection; + FfxUInt32x2 renderSize; + FfxFloat32x2 inverseRenderSize; + FfxFloat32 iblFactor; + FfxUInt32 frameIndex; + FfxUInt32 samplesPerQuad; + FfxUInt32 temporalVarianceGuidedTracingEnabled; + FfxFloat32 globalRoughnessThreshold; + FfxFloat32 rtRoughnessThreshold; + FfxUInt32 mask; + FfxUInt32 reflectionWidth; + FfxUInt32 reflectionHeight; + FfxFloat32 hybridMissWeight; + FfxFloat32 hybridSpawnRate; + FfxFloat32 vrtVarianceThreshold; + FfxFloat32 reflectionsBackfacingThreshold; + FfxUInt32 randomSamplesPerPixel; + FfxFloat32x2 motionVectorScale; + FfxFloat32 normalsUnpackMul; + FfxFloat32 normalsUnpackAdd; + FfxUInt32 roughnessChannel; + FfxUInt32 isRoughnessPerceptual; + +#define FFX_CLASSIFIER_CONSTANT_BUFFER_1_SIZE 120 +}; +#else +#define invViewProjection 0 +#define projection 0 +#define invProjection 0 +#define viewMatrix 0 +#define invView 0 +#define prevViewProjection 0 +#define renderSize 0 +#define inverseRenderSize 0 +#define iblFactor 0 +#define roughnessThreshold 0 +#define varianceThreshold 0 +#define frameIndex 0 +#define samplesPerQuad 0 +#define temporalVarianceGuidedTracingEnabled 0 +#define globalRoughnessThreshold 0 +#define rtRoughnessThreshold 0 +#define mask 0 +#define reflectionWidth 0 +#define reflectionHeight 0 +#define hybridMissWeight 0 +#define hybridSpawnRate 0 +#define vrtVarianceThreshold 0 +#define reflectionsBackfacingThreshold 0 +#define randomSamplesPerPixel 0 +#define motionVectorScale 0 +#define normalsUnpackMul 0 +#define normalsUnpackAdd 0 +#define roughnessChannel 0 +#define isRoughnessPerceptual 0 +#endif + +#if defined(FFX_GPU) +#define FFX_CLASSIFIER_ROOTSIG_STRINGIFY(p) FFX_CLASSIFIER_ROOTSIG_STR(p) +#define FFX_CLASSIFIER_ROOTSIG_STR(p) #p +#define FFX_CLASSIFIER_ROOTSIG [RootSignature("DescriptorTable(UAV(u0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_WRAP, " \ + "comparisonFunc = COMPARISON_ALWAYS, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK, " \ + "maxAnisotropy = 1), " \ + "StaticSampler(s1, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_ALWAYS, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK, " \ + "maxAnisotropy = 1)" )] + +#if defined(FFX_CLASSIFIER_EMBED_ROOTSIG) +#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT FFX_CLASSIFIER_ROOTSIG +#else +#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_CLASSIFIER_EMBED_ROOTSIG + +#endif // #if defined(FFX_GPU) + +SamplerState s_EnvironmentMapSampler : register(s0); +SamplerState s_LinearSampler : register(s1); + +FfxFloat32Mat4 InvViewProjection() +{ + return invViewProjection; +} + +FfxFloat32Mat4 Projection() +{ + return projection; +} + +FfxFloat32Mat4 InvProjection() +{ + return invProjection; +} + +FfxFloat32Mat4 ViewMatrix() +{ + return viewMatrix; +} + +FfxFloat32Mat4 InvView() +{ + return invView; +} + +FfxFloat32Mat4 PrevViewProjection() +{ + return prevViewProjection; +} + +FfxUInt32x2 RenderSize() +{ + return renderSize; +} + +FfxFloat32x2 InverseRenderSize() +{ + return inverseRenderSize; +} + +FfxFloat32 IBLFactor() +{ + return iblFactor; +} + +FfxFloat32 RoughnessThreshold() +{ + return globalRoughnessThreshold; +} + +FfxUInt32 FrameIndex() +{ + return frameIndex; +} + +FfxUInt32 SamplesPerQuad() +{ + return samplesPerQuad; +} + +FfxBoolean TemporalVarianceGuidedTracingEnabled() +{ + return FfxBoolean(temporalVarianceGuidedTracingEnabled); +} + +FfxFloat32 RTRoughnessThreshold() +{ + return rtRoughnessThreshold; +} + +FfxUInt32 Mask() +{ + return mask; +} + +FfxUInt32 ReflectionWidth() +{ + return reflectionWidth; +} + +FfxUInt32 ReflectionHeight() +{ + return reflectionHeight; +} + +FfxFloat32 HybridMissWeight() +{ + return hybridMissWeight; +} + +FfxFloat32 HybridSpawnRate() +{ + return hybridSpawnRate; +} + +FfxFloat32 VRTVarianceThreshold() +{ + return vrtVarianceThreshold; +} + +FfxFloat32 ReflectionsBackfacingThreshold() +{ + return reflectionsBackfacingThreshold; +} + +FfxUInt32 RandomSamplesPerPixel() +{ + return randomSamplesPerPixel; +} + +FfxFloat32x2 MotionVectorScale() +{ + return motionVectorScale; +} + + +FfxFloat32 NormalsUnpackMul() +{ + return normalsUnpackMul; +} + +FfxFloat32 NormalsUnpackAdd() +{ + return normalsUnpackAdd; +} + +FfxUInt32 RoughnessChannel() +{ + return roughnessChannel; +} + +FfxBoolean IsRoughnessPerceptual() +{ + return FfxBoolean(isRoughnessPerceptual); +} + + +#if defined CLASSIFIER_BIND_SRV_INPUT_DEPTH + Texture2D r_input_depth : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_DEPTH); +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS + Texture2D r_input_motion_vectors : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS); +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_NORMAL + Texture2D r_input_normal : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_NORMAL); +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS + Texture2D r_input_material_parameters : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS); +#endif +#if defined CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP + TextureCube r_input_environment_map : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP); +#endif +#if defined CLASSIFIER_BIND_SRV_VARIANCE_HISTORY + Texture2D r_variance_history : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_VARIANCE_HISTORY); +#endif +#if defined CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY + Texture2D r_hit_counter_history : FFX_CLASSIFIER_DECLARE_SRV(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY); +#endif + + +// UAVs +#if defined CLASSIFIER_BIND_UAV_RADIANCE + RWTexture2D rw_radiance : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_RADIANCE); +#endif +#if defined CLASSIFIER_BIND_UAV_RAY_LIST + RWStructuredBuffer rw_ray_list : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_RAY_LIST); +#endif +#if defined CLASSIFIER_BIND_UAV_HW_RAY_LIST + RWStructuredBuffer rw_hw_ray_list : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_HW_RAY_LIST); +#endif +#if defined CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST + RWStructuredBuffer rw_denoiser_tile_list : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST); +#endif +#if defined CLASSIFIER_BIND_UAV_RAY_COUNTER + globallycoherent RWStructuredBuffer rw_ray_counter : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_RAY_COUNTER); +#endif +#if defined CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS + RWTexture2D rw_extracted_roughness : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS); +#endif +#if defined CLASSIFIER_BIND_UAV_HIT_COUNTER + RWTexture2D rw_hit_counter : FFX_CLASSIFIER_DECLARE_UAV(CLASSIFIER_BIND_UAV_HIT_COUNTER); +#endif + +#if FFX_HALF + +#endif // #if defined(FFX_HALF) + +#if defined(CLASSIFIER_BIND_SRV_INPUT_NORMAL) +FfxFloat32x3 LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ + return normalize(NormalsUnpackMul() * r_input_normal.Load(FfxInt32x3(pixel_coordinate, 0)).xyz + NormalsUnpackAdd()); +} +#endif // #if defined(CLASSIFIER_BIND_SRV_INPUT_NORMAL) + +#if defined(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP) +FfxFloat32x3 SampleEnvironmentMap(FfxFloat32x3 direction, FfxFloat32 preceptualRoughness) +{ + FfxFloat32 Width; FfxFloat32 Height; + r_input_environment_map.GetDimensions(Width, Height); + FfxInt32 maxMipLevel = FfxInt32(log2(FfxFloat32(Width > 0 ? Width : 1))); + FfxFloat32 mip = clamp(preceptualRoughness * FfxFloat32(maxMipLevel), 0.0, FfxFloat32(maxMipLevel)); + return r_input_environment_map.SampleLevel(s_EnvironmentMapSampler, direction, mip).xyz * IBLFactor(); +} +#endif // #if defined(CLASSIFIER_BIND_SRV_INPUT_ENVIRONMENT_MAP) + +#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) +void IncrementRayCounterSW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value) +{ + InterlockedAdd(rw_ray_counter[0], value, original_value); +} +#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) + +#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) +void IncrementRayCounterHW(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value) +{ + InterlockedAdd(rw_ray_counter[4], value, original_value); +} +#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) + +#if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) +void IncrementDenoiserTileCounter(FFX_PARAMETER_OUT FfxUInt32 original_value) +{ + InterlockedAdd(rw_ray_counter[2], 1, original_value); +} +#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_COUNTER) + +FfxUInt32 PackRayCoords(FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 ray_x_15bit = ray_coord.x & 32767; // 0b111111111111111 + FfxUInt32 ray_y_14bit = ray_coord.y & 16383; // 0b11111111111111; + FfxUInt32 copy_horizontal_1bit = copy_horizontal ? 1 : 0; + FfxUInt32 copy_vertical_1bit = copy_vertical ? 1 : 0; + FfxUInt32 copy_diagonal_1bit = copy_diagonal ? 1 : 0; + + FfxUInt32 packed = (copy_diagonal_1bit << 31) | (copy_vertical_1bit << 30) | (copy_horizontal_1bit << 29) | (ray_y_14bit << 15) | (ray_x_15bit << 0); + return packed; +} + +#if defined (CLASSIFIER_BIND_UAV_RAY_LIST) +void StoreRay(FfxInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace + rw_ray_list[index] = packedRayCoords; +} +#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_LIST) + +#if defined (CLASSIFIER_BIND_UAV_RAY_LIST) +void StoreRaySWHelper(FfxInt32 index) +{ + rw_ray_list[index] = 0xffffffffu; +} +#endif // #if defined (CLASSIFIER_BIND_UAV_RAY_LIST) + +#if defined (CLASSIFIER_BIND_UAV_HW_RAY_LIST) +void StoreRayHW(FfxInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace + rw_hw_ray_list[index] = packedRayCoords; +} +#endif // #if defined (CLASSIFIER_BIND_UAV_HW_RAY_LIST) + +#if defined (CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST) +void StoreDenoiserTile(FfxInt32 index, FfxUInt32x2 tile_coord) +{ + rw_denoiser_tile_list[index] = ((tile_coord.y & 0xffffu) << 16) | ((tile_coord.x & 0xffffu) << 0); // Store out pixel to trace +} +#endif // #if defined (CLASSIFIER_BIND_UAV_DENOISER_TILE_LIST) + +#if defined (CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS) +void StoreExtractedRoughness(FfxUInt32x2 coordinate, FfxFloat32 roughness) +{ + rw_extracted_roughness[coordinate] = roughness; +} +#endif // #if defined (CLASSIFIER_BIND_UAV_EXTRACTED_ROUGHNESS) + +#if defined (CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS) +FfxFloat32 LoadRoughnessFromMaterialParametersInput(FfxUInt32x3 coordinate) /**/ +{ + FfxFloat32 rawRoughness = r_input_material_parameters.Load(coordinate)[RoughnessChannel()]; + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (CLASSIFIER_BIND_SRV_INPUT_MATERIAL_PARAMETERS) + +#if defined (CLASSIFIER_BIND_SRV_VARIANCE_HISTORY) +FfxFloat32 SampleVarianceHistory(FfxFloat32x2 coordinate) +{ + return (FfxFloat32)r_variance_history.SampleLevel(s_LinearSampler, coordinate, 0.0f).x; +} +#endif // #if defined (CLASSIFIER_BIND_SRV_VARIANCE_HISTORY) + +#if defined (CLASSIFIER_BIND_UAV_RADIANCE) +void StoreRadiance(FfxUInt32x2 coordinate, FfxFloat32x4 radiance) /**/ +{ + rw_radiance[coordinate] = radiance; +} +#endif // #if defined (CLASSIFIER_BIND_UAV_RADIANCE) + +#if defined (CLASSIFIER_BIND_SRV_INPUT_DEPTH) +FfxFloat32 GetInputDepth(FfxUInt32x2 coordinate) +{ + return r_input_depth[coordinate]; +} +#endif // #if defined (CLASSIFIER_BIND_SRV_INPUT_DEPTH) + +#if defined(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY) +FfxUInt32 LoadHitCounterHistory(FfxUInt32x2 coordinate) +{ + return r_hit_counter_history[coordinate]; +} +#endif // #if defined(CLASSIFIER_BIND_SRV_HIT_COUNTER_HISTORY) + +#if defined(CLASSIFIER_BIND_UAV_HIT_COUNTER) +void StoreHitCounter(FfxUInt32x2 coordinate, FfxUInt32 value) +{ + rw_hit_counter[coordinate] = value; +} +#endif // #if defined(CLASSIFIER_BIND_UAV_HIT_COUNTER) + +#if defined (CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS) +FfxFloat32x2 LoadMotionVector(FfxInt32x2 pixel_coordinate) +{ + return MotionVectorScale() * r_input_motion_vectors.Load(FfxInt32x3(pixel_coordinate, 0)); +} +#endif // #if defined (CLASSIFIER_BIND_SRV_INPUT_MOTION_VECTORS) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_common.h new file mode 100644 index 00000000..052082d0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_reflections_common.h @@ -0,0 +1,118 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +// Use hitcounter feedback +#define FFX_CLASSIFIER_FLAGS_USE_HIT_COUNTER (1 << 0) +// Traverse in screen space +#define FFX_CLASSIFIER_FLAGS_USE_SCREEN_SPACE (1 << 1) +// Traverse using HW ray tracing +#define FFX_CLASSIFIER_FLAGS_USE_RAY_TRACING (1 << 2) +// Iterate BVH to search for the opaque fragment +#define FFX_CLASSIFIER_FLAGS_RESOLVE_TRANSPARENT (1 << 3) +// Grab radiance from screen space shaded image for ray traced intersections, when possible +#define FFX_CLASSIFIER_FLAGS_SHADING_USE_SCREEN (1 << 5) +// defines FFX_HSR_OPTION_SHADING_USE_SCREEN + +// Extra flags for debugging +#define FFX_CLASSIFIER_FLAGS_FLAG_0 (1 << 9) +#define FFX_CLASSIFIER_FLAGS_FLAG_1 (1 << 10) +#define FFX_CLASSIFIER_FLAGS_FLAG_2 (1 << 11) +#define FFX_CLASSIFIER_FLAGS_FLAG_3 (1 << 12) + +// Visualization tweaking +#define FFX_CLASSIFIER_FLAGS_SHOW_DEBUG_TARGET (1 << 13) +#define FFX_CLASSIFIER_FLAGS_SHOW_INTERSECTION (1 << 14) +#define FFX_CLASSIFIER_FLAGS_SHOW_REFLECTION_TARGET (1 << 15) +#define FFX_CLASSIFIER_FLAGS_APPLY_REFLECTIONS (1 << 16) +#define FFX_CLASSIFIER_FLAGS_INTERSECTION_ACCUMULATE (1 << 17) + +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_WAVES (1 << 18) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_AVG_RADIANCE (1 << 19) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_VARIANCE (1 << 20) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_NUM_SAMPLES (1 << 21) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_RAY_LENGTH (1 << 23) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_REPROJECTION (1 << 25) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_TRANSPARENT_QUERY (1 << 26) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_HIT_COUNTER (1 << 27) +#define FFX_CLASSIFIER_FLAGS_VISUALIZE_PRIMARY_RAYS (1 << 28) + +#if defined(FFX_GPU) + +#define FFX_REFLECTIONS_SKY_DISTANCE 100.0f + +// Helper defines for hitcouter and classification +#define FFX_HITCOUNTER_SW_HIT_FLAG (1u << 0u) +#define FFX_HITCOUNTER_SW_HIT_SHIFT 0u +#define FFX_HITCOUNTER_SW_OLD_HIT_SHIFT 8u +#define FFX_HITCOUNTER_MASK 0xffu +#define FFX_HITCOUNTER_SW_MISS_FLAG (1u << 16u) +#define FFX_HITCOUNTER_SW_MISS_SHIFT 16u +#define FFX_HITCOUNTER_SW_OLD_MISS_SHIFT 24u + +#define FFX_Hitcounter_GetSWHits(counter) ((counter >> FFX_HITCOUNTER_SW_HIT_SHIFT) & FFX_HITCOUNTER_MASK) +#define FFX_Hitcounter_GetSWMisses(counter) ((counter >> FFX_HITCOUNTER_SW_MISS_SHIFT) & FFX_HITCOUNTER_MASK) +#define FFX_Hitcounter_GetOldSWHits(counter) ((counter >> FFX_HITCOUNTER_SW_OLD_HIT_SHIFT) & FFX_HITCOUNTER_MASK) +#define FFX_Hitcounter_GetOldSWMisses(counter) ((counter >> FFX_HITCOUNTER_SW_OLD_MISS_SHIFT) & FFX_HITCOUNTER_MASK) + +//=== Common functions of the HsrSample === + +void UnpackRayCoords(FfxUInt32 packed, FFX_PARAMETER_OUT FfxUInt32x2 ray_coord, FFX_PARAMETER_OUT FfxBoolean copy_horizontal, FFX_PARAMETER_OUT FfxBoolean copy_vertical, FFX_PARAMETER_OUT FfxBoolean copy_diagonal) { + ray_coord.x = (packed >> 0) & 32767; // 0b111111111111111; + ray_coord.y = (packed >> 15) & 16383; // 0b11111111111111; + copy_horizontal = FfxBoolean((packed >> 29) & 1u); + copy_vertical = FfxBoolean((packed >> 30) & 1u); + copy_diagonal = FfxBoolean((packed >> 31) & 1u); +} + +// Mat must be able to transform origin from texture space to a linear space. +FfxFloat32x3 InvProjectPosition(FfxFloat32x3 coord, FfxFloat32Mat4 mat) { + coord.y = (1 - coord.y); + coord.xy = 2 * coord.xy - 1; + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(coord, 1)); + projected.xyz /= projected.w; + return projected.xyz; +} + +FfxBoolean IsGlossyReflection(FfxFloat32 roughness) { + return roughness < RoughnessThreshold(); +} + +FfxFloat32x3 ScreenSpaceToViewSpace(FfxFloat32x3 screen_uv_coord) { + return InvProjectPosition(screen_uv_coord, InvProjection()); +} + +FfxBoolean IsBackground(FfxFloat32 depth) +{ +#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH + return depth < 1.e-6f; +#else + return depth >= (1.0f - 1.e-6f); +#endif +} + +// Rounds value to the nearest multiple of 8 +FfxUInt32x2 FFX_DNSR_Reflections_RoundUp8(FfxUInt32x2 value) { + FfxUInt32x2 round_down = value & ~7; // 0b111; + return FFX_SELECT((round_down == value), value, value + 8); +} + +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_resources.h new file mode 100644 index 00000000..c3df115f --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_resources.h @@ -0,0 +1,59 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_CLASSIFIER_RESOURCES_H +#define FFX_CLASSIFIER_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_DEPTH 1 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_NORMAL 2 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_WORK_QUEUE 3 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_WORK_QUEUE_COUNTER 4 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_RAY_HIT 5 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_SHADOW_MAPS 7 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS 8 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_SPECULAR_ROUGHNESS 9 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_ENVIRONMENT_MAP 10 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_VARIANCE_HISTORY 11 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_HIT_COUNTER_HISTORY 12 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_HIT_COUNTER 13 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_RAY_LIST 14 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_HW_RAY_LIST 15 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_EXTRACTED_ROUGHNESS 16 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_RAY_COUNTER 17 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_DENOISER_TILE_LIST 18 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_DEBUG_IMAGE 19 +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_RADIANCE 20 + +#define FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT 25 // 21 + FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT +#if defined(FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT) +static_assert(FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT == 4, + "This count represents 21 + FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT. This assert monitors if MAX_SHADOW_MAP_TEXTURES_COUNT has changed"); +#endif // #if defined(FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT) + +#define FFX_CLASSIFIER_CONSTANTBUFFER_IDENTIFIER_CLASSIFIER 0 +#define FFX_CLASSIFIER_CONSTANTBUFFER_IDENTIFIER_REFLECTION 1 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif //!defined( FFX_CLASSIFIER_RESOURCES_H ) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows.h new file mode 100644 index 00000000..3bc5fc71 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows.h @@ -0,0 +1,221 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup FfxGPUClassifier FidelityFX Classifier +/// FidelityFX Classifier GPU documentation +/// +/// @ingroup FfxGPUEffects + +#include "ffx_classifier_common.h" + +struct ClassifyResults +{ + FfxBoolean bIsActiveLane; + FfxBoolean bIsInLight; + FfxFloat32 minT; + FfxFloat32 maxT; +}; + +ClassifyResults FfxClassify(const FfxUInt32x2 pixelCoord, + const FfxBoolean bUseNormal, + const FfxBoolean bUseCascadeBlocking) +{ + const FfxBoolean bIsInViewport = all(FFX_LESS_THAN(pixelCoord, TextureSize().xy)); + const FfxFloat32 depth = FfxClassifierSampleDepth(pixelCoord); + +#if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH + FfxBoolean bIsActiveLane = bIsInViewport && (depth > 0.0f); +#else + FfxBoolean bIsActiveLane = bIsInViewport && (depth < 1.0f); +#endif + FfxBoolean bIsInLight = FFX_FALSE; + FfxFloat32 minT = FFX_POSITIVE_INFINITY_FLOAT; + FfxFloat32 maxT = 0.f; + + if (bUseNormal && bIsActiveLane) + { + const FfxFloat32x3 normal = normalize(FfxClassifierSampleNormal(pixelCoord)); + const FfxBoolean bIsNormalFacingLight = dot(normal, -LightDir()) > 0; + + bIsActiveLane = bIsActiveLane && bIsNormalFacingLight; + } + + if (bUseCascadeBlocking && bIsActiveLane) + { + const FfxFloat32x2 uv = pixelCoord * TextureSize().zw; + const FfxFloat32x4 homogeneous = FFX_MATRIX_MULTIPLY(ViewToWorld(), FfxFloat32x4(2.0f * FfxFloat32x2(uv.x, 1.0f - uv.y) - 1.0f, depth, 1)); + const FfxFloat32x3 worldPos = homogeneous.xyz / homogeneous.w; + + const FfxFloat32x3 lightViewSpacePos = FFX_MATRIX_MULTIPLY(LightView(), FfxFloat32x4(worldPos, 1)).xyz; + + FfxBoolean bIsInActiveCascade = FFX_FALSE; + + if (bUseCascadeBlocking) + { + const FfxFloat32 radius = SunSizeLightSpace() * lightViewSpacePos.z; + + FfxFloat32x3 shadowCoord = FfxFloat32x3(0, 0, 0); + FfxUInt32 cascadeIndex = 0; + for (FfxUInt32 i = 0; i < CascadeCount(); ++i) + { + shadowCoord = lightViewSpacePos * CascadeScale(i).xyz + CascadeOffset(i).xyz; + if (all(FFX_GREATER_THAN(shadowCoord.xy, FfxFloat32x2(0, 0))) && all(FFX_LESS_THAN(shadowCoord.xy, FfxFloat32x2(1, 1)))) + { + cascadeIndex = i; + break; + } + } + + // grow search area by a pixel to make sure we search a wide enough area + // also scale everything from UV to pixel coord for image loads. + const FfxFloat32x2 radiusCoord = abs(FfxFloat32x2(radius, radius) * CascadeScale(cascadeIndex).xy) * FfxFloat32x2(CascadeSize(), CascadeSize()) + FfxFloat32x2(1,1); + shadowCoord.xy *= CascadeSize(); + + #if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH + const FfxFloat32 depthCmp = shadowCoord.z + BlockerOffset(); + #else + const FfxFloat32 depthCmp = shadowCoord.z - BlockerOffset(); + #endif + + #if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH + FfxFloat32 maxD = 1; + FfxFloat32 minD = 0; + FfxFloat32 closetDepth = 1; + #else + FfxFloat32 maxD = 0; + FfxFloat32 minD = 1; + FfxFloat32 closetDepth = 0; + #endif + + + // With small shadow maps we will be bound on filtering since the shadow map can end up completely in LO cache + // using an image load is faster then a sample in RDNA but we will be losing the benefit of doing some of the ALU + // in the filter and getting 4 pixels of data per tap. + for (FfxUInt32 x = 0; x < k_poissonDiscSampleCountHigh; ++x) + { + const FfxFloat32x2 sampleUV = shadowCoord.xy + k_poissonDisc[x] * radiusCoord + 0.5f; + + // UV bounds check + if (!(all(FFX_GREATER_THAN_EQUAL(sampleUV.xy, FfxFloat32x2(0, 0))) && + all(FFX_LESS_THAN(sampleUV.xy, FfxFloat32x2(CascadeSize(), CascadeSize()))))) + continue; + const FfxFloat32 pixelDepth = FfxClassifierSampleShadowMap(sampleUV, cascadeIndex); + + // using min and max to reduce number of cmps + #if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH + maxD = min(maxD, pixelDepth); + minD = max(minD, pixelDepth); + + // need to find closet point in front of the receiver + if (pixelDepth > depthCmp) + { + closetDepth = min(closetDepth, pixelDepth); + } + #else + maxD = max(maxD, pixelDepth); + minD = min(minD, pixelDepth); + + // need to find closet point in front of the receiver + if (pixelDepth < depthCmp) + { + closetDepth = max(closetDepth, pixelDepth); + } + #endif + } + + #if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH + const FfxBoolean bIsInShadow = (maxD >= depthCmp); + bIsInLight = RejectLitPixels() && (minD <= depthCmp); + #else + const FfxBoolean bIsInShadow = (maxD <= depthCmp); + bIsInLight = RejectLitPixels() && (minD >= depthCmp); + #endif + bIsInActiveCascade = !bIsInShadow && !bIsInLight; + + if (bIsInActiveCascade && UseCascadesForRayT()) + { + #if FFX_CLASSIFIER_OPTION_INVERTED_DEPTH + const FfxFloat32 viewMinT = abs(min(shadowCoord.z + closetDepth + BlockerOffset(), 0) / CascadeScale(cascadeIndex).z); + const FfxFloat32 viewMaxT = abs((shadowCoord.z + minD - BlockerOffset()) / CascadeScale(cascadeIndex).z); + #else + const FfxFloat32 viewMinT = abs(max(shadowCoord.z - closetDepth - BlockerOffset(), 0) / CascadeScale(cascadeIndex).z); + const FfxFloat32 viewMaxT = abs((shadowCoord.z - minD + BlockerOffset()) / CascadeScale(cascadeIndex).z); + #endif + + // if its known that the light view matrix is only a rotation or has uniform scale this can be optimized. + minT = length(FFX_MATRIX_MULTIPLY(InverseLightView(), FfxFloat32x4(0, 0, viewMinT, 0)).xyz); + maxT = length(FFX_MATRIX_MULTIPLY(InverseLightView(), FfxFloat32x4(0, radius, viewMaxT, 0)).xyz); + + } + } + + bIsActiveLane = bIsActiveLane && bIsInActiveCascade; + } + + const ClassifyResults results = { bIsActiveLane, bIsInLight, minT, maxT }; + + return results; +} + +/// Classifier pass entry point. +/// +/// @param LocalThreadId The "flattened" index of a thread within a thread group (SV_GroupIndex). +/// @param WorkGroupId Index of the thread group currently executed (SV_GroupID). +/// @ingroup FfxGPUClassifier +void FfxClassifyShadows(FfxUInt32 LocalThreadId, FfxUInt32x3 WorkGroupId) +{ + const FfxUInt32x2 localID = ffxRemapForWaveReduction(LocalThreadId); + const FfxUInt32x2 pixelCoord = WorkGroupId.xy * k_tileSize + localID.xy; + +#if FFX_CLASSIFIER_OPTION_CLASSIFIER_MODE == 0 + ClassifyResults results = FfxClassify(pixelCoord, FFX_TRUE, FFX_FALSE); +#endif +#if FFX_CLASSIFIER_OPTION_CLASSIFIER_MODE == 1 + ClassifyResults results = FfxClassify(pixelCoord, FFX_TRUE, FFX_TRUE); +#endif + Tile currentTile = TileCreate(WorkGroupId.xy); + const FfxUInt32 mask = BoolToWaveMask(results.bIsActiveLane, localID); + currentTile.mask = mask; + +#if FFX_CLASSIFIER_OPTION_CLASSIFIER_MODE == 1 + if (UseCascadesForRayT()) + { + // At lest one lane must be active for the tile to be written out, so the infinitly and zero will be emoved by the wave min and max. + // Otherwise we will get minT to be infinite and maxT to be 0 + currentTile.minT = max(ffxWaveMin(results.minT), currentTile.minT); + currentTile.maxT = min(ffxWaveMax(results.maxT), currentTile.maxT); + } +#endif + + const FfxUInt32 lightMask = BoolToWaveMask(results.bIsInLight, localID); + const FfxBoolean bDiscardTile = (CountBits(mask) <= TileTolerance()); + + if (LocalThreadId == 0) + { + if (!bDiscardTile) + { + FfxClassifierStoreTile(TileToUint(currentTile)); + } + + FfxClassifierStoreLightMask(WorkGroupId.xy, lightMask); + } +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows_callbacks_glsl.h new file mode 100644 index 00000000..1126bb57 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows_callbacks_glsl.h @@ -0,0 +1,287 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_classifier_resources.h" +#include "ffx_core.h" + +#if defined(FFX_GPU) + +const FfxFloat32x2 k_poissonDisc[] = { + FfxFloat32x2(0.640736f, -0.355205f), FfxFloat32x2(-0.725411f, -0.688316f), FfxFloat32x2(-0.185095f, 0.722648f), FfxFloat32x2(0.770596f, 0.637324f), + FfxFloat32x2(-0.921445f, 0.196997f), FfxFloat32x2(0.076571f, -0.98822f), FfxFloat32x2(-0.1348f, -0.0908536f), FfxFloat32x2(0.320109f, 0.257241f), + FfxFloat32x2(0.994021f, 0.109193f), FfxFloat32x2(0.304934f, 0.952374f), FfxFloat32x2(-0.698577f, 0.715535f), FfxFloat32x2(0.548701f, -0.836019f), + FfxFloat32x2(-0.443159f, 0.296121f), FfxFloat32x2(0.15067f, -0.489731f), FfxFloat32x2(-0.623829f, -0.208167f), FfxFloat32x2(-0.294778f, -0.596545f), + FfxFloat32x2(0.334086f, -0.128208f), FfxFloat32x2(-0.0619831f, 0.311747f), FfxFloat32x2(0.166112f, 0.61626f), FfxFloat32x2(-0.289127f, -0.957291f), + FfxFloat32x2(-0.98748f, -0.157745f), FfxFloat32x2(0.637501f, 0.0651571f), FfxFloat32x2(0.971376f, -0.237545f), FfxFloat32x2(-0.0170599f, 0.98059f), + FfxFloat32x2(-0.442564f, 0.896737f), FfxFloat32x2(0.48619f, 0.518723f), FfxFloat32x2(-0.725272f, 0.419965f), FfxFloat32x2(0.781417f, -0.624009f), + FfxFloat32x2(-0.899227f, -0.437482f), FfxFloat32x2(0.769219f, 0.33372f), FfxFloat32x2(-0.414411f, 0.00375378f), FfxFloat32x2(0.262856f, -0.759514f), +}; + +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_CB_CLASSIFIER, std140) uniform cbClassifier_t + { + FfxFloat32x4 textureSize; + FfxFloat32x3 lightDir; + FfxFloat32 skyHeight; + + FfxFloat32x4 blockerOffset_cascadeSize_sunSizeLightSpace_pad; + FfxUInt32x4 cascadeCount_tileTolerance_pad_pad; + FfxFloat32x4 bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd; + + FfxFloat32x4 cascadeScale[4]; + FfxFloat32x4 cascadeOffset[4]; + + // Matrices + FfxFloat32Mat4 viewToWorld; + FfxFloat32Mat4 lightView; + FfxFloat32Mat4 inverseLightView; + + //#define FFX_CLASSIFIER_CONSTANT_BUFFER_1_SIZE 18 + 2 booleans + 32 + 48// Number of 32-bit values + } cbClassifier; +#endif + +FfxFloat32x4 TextureSize() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.textureSize; +#endif + return FfxFloat32x4(0,0,0,0); +} + +FfxFloat32x3 LightDir() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.lightDir; +#endif + return FfxFloat32x3(0, 0, 0); +} + +FfxFloat32 SkyHeight() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.skyHeight; +#endif + return FfxFloat32(0); +} + +FfxUInt32 CascadeCount() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.cascadeCount_tileTolerance_pad_pad[0]; +#endif + return 0; +} + +FfxUInt32 TileTolerance() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.cascadeCount_tileTolerance_pad_pad[1]; +#endif + return 0; +} + +FfxFloat32 BlockerOffset() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.blockerOffset_cascadeSize_sunSizeLightSpace_pad[0]; +#endif + return 0; +} + +FfxFloat32 CascadeSize() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.blockerOffset_cascadeSize_sunSizeLightSpace_pad[1]; +#endif + return 0; +} + +FfxFloat32 SunSizeLightSpace() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.blockerOffset_cascadeSize_sunSizeLightSpace_pad[2]; +#endif + return 0; +} + +FfxBoolean RejectLitPixels() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return FfxBoolean(cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[0]); +#endif + return false; +} + +FfxBoolean UseCascadesForRayT() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return FfxBoolean(cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[1]); +#endif + return false; +} + +FfxFloat32 NormalsUnpackMul() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[2]; +#else + return 0; +#endif +} + +FfxFloat32 NormalsUnpackAdd() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[3]; +#else + return 0; +#endif +} + +FfxFloat32x4 CascadeScale(FfxUInt32 index) +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.cascadeScale[index]; +#else + return FfxFloat32x4(0,0,0,0); +#endif +} + +FfxFloat32x4 CascadeOffset(FfxUInt32 index) +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.cascadeOffset[index]; +#else + return FfxFloat32x4(0,0,0,0); +#endif +} + +FfxFloat32Mat4 ViewToWorld() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.viewToWorld; +#endif + return FfxFloat32Mat4(0); +} + +FfxFloat32Mat4 LightView() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.lightView; +#endif + return FfxFloat32Mat4(0); +} + +FfxFloat32Mat4 InverseLightView() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cbClassifier.inverseLightView; +#endif + return FfxFloat32Mat4(0); +} + +// SRVs +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH) + uniform texture2D r_input_depth; +#endif +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS) + uniform texture2D r_input_normal; +#endif +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS) + uniform texture2D r_input_shadowMap[4]; +#endif + +// UAVs +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES, std430) + buffer rwsb_tiles_t + { + FfxUInt32x4 data[]; + } rwsb_tiles; +#endif +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT, std430) + coherent buffer rwb_tileCount_t + { + FfxUInt32 data[]; + } rwb_tileCount; +#endif +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT, r32ui) + uniform uimage2D rwt2d_rayHitResults; +#endif +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_TEXTURE) + layout (set = 0, binding = FFX_CLASSIFIER_BIND_UAV_OUTPUT_TEXTURE, rgba32f) + uniform image2D rwt2d_output; +#endif + +FfxFloat32 FfxClassifierSampleDepth(FfxUInt32x2 uiPxPos) +{ +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH) + return texelFetch(r_input_depth, ivec2(uiPxPos), 0).r; +#else + return 0.0; +#endif // defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH) +} + +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS) +FfxFloat32x3 FfxClassifierSampleNormal(FfxUInt32x2 uiPxPos) +{ + FfxFloat32x3 normal = texelFetch(r_input_normal, ivec2(uiPxPos), 0).rgb; + normal = normal * NormalsUnpackMul().xxx + NormalsUnpackAdd().xxx; + return normalize(normal); +} +#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS) + +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS) +FfxFloat32 FfxClassifierSampleShadowMap(FfxFloat32x2 sampleUV, FfxUInt32 cascadeIndex) +{ + nonuniformEXT FfxUInt32 nonUniformCascadeIndex = cascadeIndex; + return texelFetch(r_input_shadowMap[nonUniformCascadeIndex], ivec2(sampleUV), 0).r; +} +#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS) + +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT) +void FfxClassifierStoreLightMask(FfxUInt32x2 index, FfxUInt32 lightMask) +{ + imageStore(rwt2d_rayHitResults, ivec2(index), FfxUInt32x4(~lightMask, 0,0,0)); +} +#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT) + +FfxUInt32 CountBits(const FfxUInt32 mask) +{ + return bitCount(mask); +} + +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT) +void FfxClassifierStoreTile(FfxUInt32x4 uiTile) +{ + uint index = ~0; + index = atomicAdd(rwb_tileCount.data[0], 1); + rwsb_tiles.data[index] = uiTile; +} +#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows_callbacks_hlsl.h new file mode 100644 index 00000000..6c286761 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/classifier/ffx_classifier_shadows_callbacks_hlsl.h @@ -0,0 +1,311 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_classifier_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + + +static const FfxFloat32x2 k_poissonDisc[] = { + FfxFloat32x2(0.640736f, -0.355205f), FfxFloat32x2(-0.725411f, -0.688316f), FfxFloat32x2(-0.185095f, 0.722648f), FfxFloat32x2(0.770596f, 0.637324f), + FfxFloat32x2(-0.921445f, 0.196997f), FfxFloat32x2(0.076571f, -0.98822f), FfxFloat32x2(-0.1348f, -0.0908536f), FfxFloat32x2(0.320109f, 0.257241f), + FfxFloat32x2(0.994021f, 0.109193f), FfxFloat32x2(0.304934f, 0.952374f), FfxFloat32x2(-0.698577f, 0.715535f), FfxFloat32x2(0.548701f, -0.836019f), + FfxFloat32x2(-0.443159f, 0.296121f), FfxFloat32x2(0.15067f, -0.489731f), FfxFloat32x2(-0.623829f, -0.208167f), FfxFloat32x2(-0.294778f, -0.596545f), + FfxFloat32x2(0.334086f, -0.128208f), FfxFloat32x2(-0.0619831f, 0.311747f), FfxFloat32x2(0.166112f, 0.61626f), FfxFloat32x2(-0.289127f, -0.957291f), + FfxFloat32x2(-0.98748f, -0.157745f), FfxFloat32x2(0.637501f, 0.0651571f), FfxFloat32x2(0.971376f, -0.237545f), FfxFloat32x2(-0.0170599f, 0.98059f), + FfxFloat32x2(-0.442564f, 0.896737f), FfxFloat32x2(0.48619f, 0.518723f), FfxFloat32x2(-0.725272f, 0.419965f), FfxFloat32x2(0.781417f, -0.624009f), + FfxFloat32x2(-0.899227f, -0.437482f), FfxFloat32x2(0.769219f, 0.33372f), FfxFloat32x2(-0.414411f, 0.00375378f), FfxFloat32x2(0.262856f, -0.759514f), +}; + + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_CLASSIFIER_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_CLASSIFIER_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_CLASSIFIER_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + cbuffer cbClassifier : FFX_CLASSIFIER_DECLARE_CB(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + { + FfxFloat32x4 textureSize; + FfxFloat32x3 lightDir; + FfxFloat32 skyHeight; + + FfxFloat32x4 blockerOffset_cascadeSize_sunSizeLightSpace_pad; + FfxUInt32x4 cascadeCount_tileTolerance_pad_pad; + FfxFloat32x4 bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd; + + FfxFloat32x4 cascadeScale[4]; + FfxFloat32x4 cascadeOffset[4]; + + // Matrices + FfxFloat32Mat4 viewToWorld; + FfxFloat32Mat4 lightView; + FfxFloat32Mat4 inverseLightView; + + #define FFX_CLASSIFIER_CONSTANT_BUFFER_1_SIZE 100 + }; +#endif + +#define FFX_CLASSIFIER_ROOTSIG_STRINGIFY(p) FFX_CLASSIFIER_ROOTSIG_STR(p) +#define FFX_CLASSIFIER_ROOTSIG_STR(p) #p +#define FFX_CLASSIFIER_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_CLASSIFIER_ROOTSIG_STRINGIFY(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_NEVER, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK)" )] + +#if defined(FFX_CLASSIFIER_EMBED_ROOTSIG) +#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT FFX_CLASSIFIER_ROOTSIG +#else +#define FFX_CLASSIFIER_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_CLASSIFIER_EMBED_ROOTSIG + +FfxFloat32x4 TextureSize() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return textureSize; +#endif + return FfxFloat32x4(0, 0, 0, 0); +} + +FfxFloat32x3 LightDir() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return lightDir; +#endif + return FfxFloat32x3(0, 0, 0); +} + +FfxFloat32 SkyHeight() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return skyHeight; +#endif + return 0; +} + +FfxUInt32 CascadeCount() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cascadeCount_tileTolerance_pad_pad[0]; +#endif + return 0; +} + +FfxUInt32 TileTolerance() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cascadeCount_tileTolerance_pad_pad[1]; +#endif + return 0; +} + +FfxFloat32 BlockerOffset() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return blockerOffset_cascadeSize_sunSizeLightSpace_pad[0]; +#endif + return 0; +} + +FfxFloat32 CascadeSize() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return blockerOffset_cascadeSize_sunSizeLightSpace_pad[1]; +#endif + return 0; +} + +FfxFloat32 SunSizeLightSpace() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return blockerOffset_cascadeSize_sunSizeLightSpace_pad[2]; +#endif + return 0; +} + +FfxBoolean RejectLitPixels() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[0]; +#endif + return false; +} + +FfxBoolean UseCascadesForRayT() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[1]; +#endif + return false; +} + +FfxFloat32 NormalsUnpackMul() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[2]; +#else + return 0; +#endif +} + +FfxFloat32 NormalsUnpackAdd() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return bRejectLitPixels_bUseCascadesForRayT_normalsUnpackMul_unpackAdd[3]; +#else + return 0; +#endif +} + +FfxFloat32x4 CascadeScale(int index) +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cascadeScale[index]; +#else + return FfxFloat32x4(0,0,0,0); +#endif +} + +FfxFloat32x4 CascadeOffset(int index) +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return cascadeOffset[index]; +#else + return FfxFloat32x4(0,0,0,0); +#endif +} + +FfxFloat32Mat4 ViewToWorld() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return viewToWorld; +#endif + return 0; +} + +FfxFloat32Mat4 LightView() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return lightView; +#endif + return 0; +} + +FfxFloat32Mat4 InverseLightView() +{ +#if defined(FFX_CLASSIFIER_BIND_CB_CLASSIFIER) + return inverseLightView; +#endif + return 0; +} + +// SRVs +#if defined FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH + Texture2D r_input_depth : FFX_CLASSIFIER_DECLARE_SRV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_DEPTH); +#endif +#if defined FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS + Texture2D r_input_normal : FFX_CLASSIFIER_DECLARE_SRV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_NORMAL); +#endif +#if defined FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS + Texture2D r_input_shadowMap[4] : FFX_CLASSIFIER_DECLARE_SRV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_INPUT_SHADOW_MAPS); +#endif + +// UAVs +#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES + RWStructuredBuffer rwsb_tiles : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_WORK_QUEUE); +#endif +#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT + globallycoherent RWStructuredBuffer rwb_tileCount : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_WORK_QUEUE_COUNTER); +#endif +#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT + RWTexture2D rwt2d_rayHitResults : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_RAY_HIT); +#endif +#if defined FFX_CLASSIFIER_BIND_UAV_OUTPUT_TEXTURE + RWTexture2D rwt2d_output : FFX_CLASSIFIER_DECLARE_UAV(FFX_CLASSIFIER_RESOURCE_IDENTIFIER_OUTPUT_COLOR); +#endif + +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH) +FfxFloat32 FfxClassifierSampleDepth(FfxUInt32x2 uiPxPos) +{ + return r_input_depth[uiPxPos].r; +} +#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_DEPTH) + +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS) +FfxFloat32x3 FfxClassifierSampleNormal(FfxUInt32x2 uiPxPos) +{ + FfxFloat32x3 normal = r_input_normal[uiPxPos].rgb; + normal = normal * NormalsUnpackMul().xxx + NormalsUnpackAdd().xxx; + return normalize(normal); +} +#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_NORMALS) + +#if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS) +FfxFloat32 FfxClassifierSampleShadowMap(FfxFloat32x2 sampleUV, FfxUInt32 cascadeIndex) +{ + return r_input_shadowMap[NonUniformResourceIndex(cascadeIndex)][FfxUInt32x2(sampleUV)]; +} +#endif // #if defined(FFX_CLASSIFIER_BIND_SRV_INPUT_SHADOW_MAPS) + +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT) +void FfxClassifierStoreLightMask(FfxUInt32x2 index, FfxUInt32 lightMask) +{ + rwt2d_rayHitResults[index] = ~lightMask; +} +#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_RAY_HIT) + +FfxUInt32 CountBits(const FfxUInt32 mask) +{ + return countbits(mask); +} + +#if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT) +void FfxClassifierStoreTile(FfxUInt32x4 uiTile) +{ + uint index = ~0; + InterlockedAdd(rwb_tileCount[0], 1, index); + rwsb_tiles[index] = uiTile; +} +#endif // #if defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES) || defined(FFX_CLASSIFIER_BIND_UAV_OUTPUT_WORK_TILES_COUNT) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/CMakeCompileDenoiserShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/CMakeCompileDenoiserShaders.txt new file mode 100644 index 00000000..567424ce --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/CMakeCompileDenoiserShaders.txt @@ -0,0 +1,52 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(DENOISER_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(DENOISER_PERMUTATION_ARGS + -DFFX_DENOISER_OPTION_INVERTED_DEPTH={0,1}) + +set(DENOISER_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/denoiser") + +if (NOT DENOISER_SHADER_EXT) + set(DENOISER_SHADER_EXT *) +endif() + +file(GLOB DENOISER_SHADERS + "shaders/denoiser/ffx_denoiser_prepare_shadow_mask_pass.${DENOISER_SHADER_EXT}" + "shaders/denoiser/ffx_denoiser_shadows_tile_classification_pass.${DENOISER_SHADER_EXT}" + "shaders/denoiser/ffx_denoiser_filter_soft_shadows_0_pass.${DENOISER_SHADER_EXT}" + "shaders/denoiser/ffx_denoiser_filter_soft_shadows_1_pass.${DENOISER_SHADER_EXT}" + "shaders/denoiser/ffx_denoiser_filter_soft_shadows_2_pass.${DENOISER_SHADER_EXT}" + "shaders/denoiser/ffx_denoiser_prefilter_reflections_pass.${DENOISER_SHADER_EXT}" + "shaders/denoiser/ffx_denoiser_reproject_reflections_pass.${DENOISER_SHADER_EXT}" + "shaders/denoiser/ffx_denoiser_resolve_temporal_reflections_pass.${DENOISER_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${DENOISER_BASE_ARGS}" "${DENOISER_API_BASE_ARGS}" "${DENOISER_PERMUTATION_ARGS}" "${DENOISER_INCLUDE_ARGS}" + "${DENOISER_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" DENOISER_PERMUTATION_OUTPUTS) + +add_shader_output("${DENOISER_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_callbacks_glsl.h new file mode 100644 index 00000000..1244e342 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_callbacks_glsl.h @@ -0,0 +1,642 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_denoiser_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(DENOISER_BIND_CB_DENOISER) + layout (set = 0, binding = DENOISER_BIND_CB_DENOISER, std140) uniform cbDenoiserReflections_t + { + FfxFloat32Mat4 invProjection; + FfxFloat32Mat4 invView; + FfxFloat32Mat4 prevViewProjection; + FfxUInt32x2 renderSize; + FfxFloat32x2 inverseRenderSize; + FfxFloat32x2 motionVectorScale; + FfxFloat32 normalsUnpackMul; + FfxFloat32 normalsUnpackAdd; + FfxBoolean isRoughnessPerceptual; + FfxFloat32 temporalStabilityFactor; + FfxFloat32 roughnessThreshold; + } cbDenoiserReflections; + +FfxFloat32Mat4 InvProjection() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.invProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 InvView() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.invView; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 PrevViewProjection() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.prevViewProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxUInt32x2 RenderSize() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.renderSize; +#else + return FfxUInt32x2(0); +#endif +} + +FfxFloat32x2 InverseRenderSize() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.inverseRenderSize; +#else + return FfxFloat32x2(0.0f); +#endif +} + +FfxFloat32x2 MotionVectorScale() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.motionVectorScale; +#else + return FfxFloat32x2(0.0f); +#endif +} + +FfxFloat32 NormalsUnpackMul() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.normalsUnpackMul; +#else + return 0.0f; +#endif +} + +FfxFloat32 NormalsUnpackAdd() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.normalsUnpackAdd; +#else + return 0.0f; +#endif +} + +FfxBoolean IsRoughnessPerceptual() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.isRoughnessPerceptual; +#else + return false; +#endif +} + +FfxFloat32 TemporalStabilityFactor() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.temporalStabilityFactor; +#else + return 0.0f; +#endif +} + +FfxFloat32 RoughnessThreshold() +{ +#if defined DENOISER_BIND_CB_DENOISER + return cbDenoiserReflections.roughnessThreshold; +#else + return 0.0f; +#endif +} + +#endif // #if defined(DENOISER_BIND_CB_DENOISER) + +layout (set = 0, binding = 1000) uniform sampler s_LinearSampler; + +#if defined DENOISER_BIND_SRV_INPUT_DEPTH_HIERARCHY + layout (set = 0, binding = DENOISER_BIND_SRV_INPUT_DEPTH_HIERARCHY) uniform texture2D r_input_depth_hierarchy; +#endif +#if defined DENOISER_BIND_SRV_INPUT_MOTION_VECTORS + layout (set = 0, binding = DENOISER_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors; +#endif +#if defined DENOISER_BIND_SRV_INPUT_NORMAL + layout (set = 0, binding = DENOISER_BIND_SRV_INPUT_NORMAL) uniform texture2D r_input_normal; +#endif +#if defined DENOISER_BIND_SRV_RADIANCE + layout (set = 0, binding = DENOISER_BIND_SRV_RADIANCE) uniform texture2D r_radiance; +#endif +#if defined DENOISER_BIND_SRV_RADIANCE_HISTORY + layout (set = 0, binding = DENOISER_BIND_SRV_RADIANCE_HISTORY) uniform texture2D r_radiance_history; +#endif +#if defined DENOISER_BIND_SRV_VARIANCE + layout (set = 0, binding = DENOISER_BIND_SRV_VARIANCE) uniform texture2D r_variance; +#endif +#if defined DENOISER_BIND_SRV_SAMPLE_COUNT + layout (set = 0, binding = DENOISER_BIND_SRV_SAMPLE_COUNT) uniform texture2D r_sample_count; +#endif +#if defined DENOISER_BIND_SRV_AVERAGE_RADIANCE + layout (set = 0, binding = DENOISER_BIND_SRV_AVERAGE_RADIANCE) uniform texture2D r_average_radiance; +#endif +#if defined DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS + layout (set = 0, binding = DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) uniform texture2D r_extracted_roughness; +#endif +#if defined DENOISER_BIND_SRV_DEPTH_HISTORY + layout (set = 0, binding = DENOISER_BIND_SRV_DEPTH_HISTORY) uniform texture2D r_depth_history; +#endif +#if defined DENOISER_BIND_SRV_NORMAL_HISTORY + layout (set = 0, binding = DENOISER_BIND_SRV_NORMAL_HISTORY) uniform texture2D r_normal_history; +#endif +#if defined DENOISER_BIND_SRV_ROUGHNESS_HISTORY + layout (set = 0, binding = DENOISER_BIND_SRV_ROUGHNESS_HISTORY) uniform texture2D r_roughness_history; +#endif +#if defined DENOISER_BIND_SRV_REPROJECTED_RADIANCE + layout (set = 0, binding = DENOISER_BIND_SRV_REPROJECTED_RADIANCE) uniform texture2D r_reprojected_radiance; +#endif + +// UAVs +#if defined DENOISER_BIND_UAV_RADIANCE + layout (set = 0, binding = DENOISER_BIND_UAV_RADIANCE, rgba16f) uniform image2D rw_radiance; +#endif +#if defined DENOISER_BIND_UAV_VARIANCE + layout (set = 0, binding = DENOISER_BIND_UAV_VARIANCE, r16f) uniform image2D rw_variance; +#endif +#if defined DENOISER_BIND_UAV_SAMPLE_COUNT + layout (set = 0, binding = DENOISER_BIND_UAV_SAMPLE_COUNT, r16f) uniform image2D rw_sample_count; +#endif +#if defined DENOISER_BIND_UAV_AVERAGE_RADIANCE + layout (set = 0, binding = DENOISER_BIND_UAV_AVERAGE_RADIANCE, r11f_g11f_b10f) uniform image2D rw_average_radiance; +#endif +#if defined DENOISER_BIND_UAV_DENOISER_TILE_LIST + layout (set = 0, binding = DENOISER_BIND_UAV_DENOISER_TILE_LIST, std430) buffer rw_denoiser_tile_list_t + { + FfxUInt32 data[]; + } rw_denoiser_tile_list; +#endif +#if defined DENOISER_BIND_UAV_REPROJECTED_RADIANCE + layout (set = 0, binding = DENOISER_BIND_UAV_REPROJECTED_RADIANCE, rgba16f) uniform image2D rw_reprojected_radiance; +#endif + +#if FFX_HALF + +FfxFloat16x3 FFX_DENOISER_LoadWorldSpaceNormalH(FfxInt32x2 pixel_coordinate) +{ +#if defined(DENOISER_BIND_SRV_INPUT_NORMAL) + return normalize(FfxFloat16x3(NormalsUnpackMul() * texelFetch(r_input_normal, pixel_coordinate, 0).xyz + NormalsUnpackAdd())); +#else + return FfxFloat16x3(0.0f); +#endif +} + +FfxFloat16x3 LoadRadianceH(FfxInt32x3 coordinate) +{ +#if defined (DENOISER_BIND_SRV_RADIANCE) + return FfxFloat16x3(texelFetch(r_radiance, coordinate.xy, coordinate.z).xyz); +#else + return FfxFloat16x3(0.0f); +#endif +} + +FfxFloat16 LoadVarianceH(FfxInt32x3 coordinate) +{ +#if defined (DENOISER_BIND_SRV_VARIANCE) + return FfxFloat16(texelFetch(r_variance, coordinate.xy, coordinate.z).x); +#else + return FfxFloat16(0.0f); +#endif +} + +#if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) +FfxFloat16x3 FFX_DNSR_Reflections_SampleAverageRadiance(FfxFloat32x2 uv) +{ + return FfxFloat16x3(textureLod(sampler2D(r_average_radiance, s_LinearSampler), uv, 0.0f).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) + +#if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) +FfxFloat16 FFX_DNSR_Reflections_LoadRoughness(FfxInt32x2 pixel_coordinate) +{ + FfxFloat16 rawRoughness = FfxFloat16(texelFetch(r_extracted_roughness, pixel_coordinate, 0).x); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) + +void StoreRadianceH(FfxInt32x2 coordinate, FfxFloat16x4 radiance) +{ +#if defined (DENOISER_BIND_UAV_RADIANCE) + imageStore(rw_radiance, coordinate, radiance); +#endif +} + +void StoreVarianceH(FfxInt32x2 coordinate, FfxFloat16 variance) +{ +#if defined (DENOISER_BIND_UAV_VARIANCE) + imageStore(rw_variance, coordinate, FfxFloat16x4(variance)); +#endif +} + +void FFX_DNSR_Reflections_StorePrefilteredReflections(FfxInt32x2 pixel_coordinate, FfxFloat16x3 radiance, FfxFloat16 variance) +{ + StoreRadianceH(pixel_coordinate, radiance.xyzz); + StoreVarianceH(pixel_coordinate, variance.x); +} + +void FFX_DNSR_Reflections_StoreTemporalAccumulation(FfxInt32x2 pixel_coordinate, FfxFloat16x3 radiance, FfxFloat16 variance) +{ + StoreRadianceH(pixel_coordinate, radiance.xyzz); + StoreVarianceH(pixel_coordinate, variance.x); +} + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_LoadRadianceHistory(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat16x3(texelFetch(r_radiance_history, pixel_coordinate, 0).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_SampleRadianceHistory(FfxFloat32x2 uv) +{ + return FfxFloat16x3(textureLod(sampler2D(r_radiance_history, s_LinearSampler), uv, 0.0f).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_VARIANCE) +FfxFloat16 FFX_DNSR_Reflections_SampleVarianceHistory(FfxFloat32x2 uv) +{ + return FfxFloat16(textureLod(sampler2D(r_variance, s_LinearSampler), uv, 0.0f).x); +} +#endif // #if defined (DENOISER_BIND_SRV_VARIANCE) + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat16 FFX_DNSR_Reflections_SampleNumSamplesHistory(FfxFloat32x2 uv) +{ + return FfxFloat16(textureLod(sampler2D(r_sample_count, s_LinearSampler), uv, 0.0f).x); +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) +void FFX_DNSR_Reflections_StoreRadianceReprojected(FfxInt32x2 pixel_coordinate, FfxFloat16x3 value) +{ + imageStore(rw_reprojected_radiance, pixel_coordinate, FfxFloat16x4(value, 0.0f)); +} +#endif // #if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) + +#if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) +void FFX_DNSR_Reflections_StoreAverageRadiance(FfxInt32x2 pixel_coordinate, FfxFloat16x3 value) +{ + imageStore(rw_average_radiance, pixel_coordinate, FfxFloat16x4(value, 0.0f)); +} +#endif // #if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) + +FfxFloat16x3 FFX_DNSR_Reflections_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ + return FFX_DENOISER_LoadWorldSpaceNormalH(pixel_coordinate); +} + +#if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) +FfxFloat16 FFX_DNSR_Reflections_SampleRoughnessHistory(FfxFloat32x2 uv) +{ + FfxFloat16 rawRoughness = FfxFloat16(textureLod(sampler2D(r_roughness_history, s_LinearSampler), uv, 0.0f).x); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(FfxInt32x2 pixel_coordinate) +{ + return normalize(FfxFloat16x3(NormalsUnpackMul() * texelFetch(r_normal_history, pixel_coordinate.xy, 0).xyz + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(FfxFloat32x2 uv) +{ + return normalize(FfxFloat16x3(NormalsUnpackMul() * textureLod(sampler2D(r_normal_history, s_LinearSampler), uv, 0.0f).xyz + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE) +FfxFloat16 FFX_DNSR_Reflections_LoadRayLength(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat16(texelFetch(r_radiance, pixel_coordinate, 0).w); +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE) + +void FFX_DNSR_Reflections_StoreVariance(FfxInt32x2 pixel_coordinate, FfxFloat16 value) +{ + StoreVarianceH(pixel_coordinate, value); +} + +#if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) +void FFX_DNSR_Reflections_StoreNumSamples(FfxInt32x2 pixel_coordinate, FfxFloat16 value) +{ + imageStore(rw_sample_count, pixel_coordinate, FfxFloat16x4(value)); +} +#endif // #if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) + +FfxFloat16x3 FFX_DNSR_Reflections_LoadRadiance(FfxInt32x2 pixel_coordinate) +{ + return LoadRadianceH(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) +FfxFloat16x3 FFX_DNSR_Reflections_LoadRadianceReprojected(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat16x3(texelFetch(r_reprojected_radiance, pixel_coordinate, 0).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) + +FfxFloat16 FFX_DNSR_Reflections_LoadVariance(FfxInt32x2 pixel_coordinate) +{ + return LoadVarianceH(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat16 FFX_DNSR_Reflections_LoadNumSamples(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat16(texelFetch(r_sample_count, pixel_coordinate, 0).x); +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#else // FFX_HALF + +FfxFloat32x3 LoadRadiance(FfxInt32x3 coordinate) +{ +#if defined (DENOISER_BIND_SRV_RADIANCE) + return texelFetch(r_radiance, coordinate.xy, coordinate.z).xyz; +#else + return FfxFloat32x3(0.0f); +#endif +} + +FfxFloat32 LoadVariance(FfxInt32x3 coordinate) +{ +#if defined (DENOISER_BIND_SRV_VARIANCE) + return texelFetch(r_variance, coordinate.xy, coordinate.z).x; +#else + return 0.0f; +#endif +} + +FfxFloat32x3 FFX_DENOISER_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ +#if defined(DENOISER_BIND_SRV_INPUT_NORMAL) + return normalize(NormalsUnpackMul() * texelFetch(r_input_normal, pixel_coordinate, 0).xyz + NormalsUnpackAdd()); +#else + return FfxFloat32x3(0.0f); +#endif +} + +#if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) +FfxFloat32 FFX_DNSR_Reflections_LoadRoughness(FfxInt32x2 pixel_coordinate) +{ + FfxFloat32 rawRoughness = FfxFloat32(texelFetch(r_extracted_roughness, pixel_coordinate, 0).x); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) + +void StoreRadiance(FfxInt32x2 coordinate, FfxFloat32x4 radiance) +{ +#if defined (DENOISER_BIND_UAV_RADIANCE) + imageStore(rw_radiance, coordinate, radiance); +#endif +} + +void StoreVariance(FfxInt32x2 coordinate, FfxFloat32 variance) +{ +#if defined (DENOISER_BIND_UAV_VARIANCE) + imageStore(rw_variance, coordinate, FfxFloat32x4(variance)); +#endif +} + +void FFX_DNSR_Reflections_StorePrefilteredReflections(FfxInt32x2 pixel_coordinate, FfxFloat32x3 radiance, FfxFloat32 variance) +{ + StoreRadiance(pixel_coordinate, radiance.xyzz); + StoreVariance(pixel_coordinate, variance.x); +} + +void FFX_DNSR_Reflections_StoreTemporalAccumulation(FfxInt32x2 pixel_coordinate, FfxFloat32x3 radiance, FfxFloat32 variance) +{ + StoreRadiance(pixel_coordinate, radiance.xyzz); + StoreVariance(pixel_coordinate, variance.x); +} + +#if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) +FfxFloat32x3 FFX_DNSR_Reflections_SampleAverageRadiance(FfxFloat32x2 uv) +{ + return FfxFloat32x3(textureLod(sampler2D(r_average_radiance, s_LinearSampler), uv, 0.0f).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_LoadRadianceHistory(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat32x3(texelFetch(r_radiance_history, pixel_coordinate, 0).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_SampleRadianceHistory(FfxFloat32x2 uv) +{ + return FfxFloat32x3(textureLod(sampler2D(r_radiance_history, s_LinearSampler), uv, 0.0f).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_VARIANCE) +FfxFloat32 FFX_DNSR_Reflections_SampleVarianceHistory(FfxFloat32x2 uv) +{ + return FfxFloat32(textureLod(sampler2D(r_variance, s_LinearSampler), uv, 0.0f).x); +} +#endif // #if defined (DENOISER_BIND_SRV_VARIANCE) + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat32 FFX_DNSR_Reflections_SampleNumSamplesHistory(FfxFloat32x2 uv) +{ + return FfxFloat32(textureLod(sampler2D(r_sample_count, s_LinearSampler), uv, 0.0f).x); +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) +void FFX_DNSR_Reflections_StoreRadianceReprojected(FfxInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + imageStore(rw_reprojected_radiance, pixel_coordinate, FfxFloat32x4(value, 0.0f)); +} +#endif // #if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) + +#if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) +void FFX_DNSR_Reflections_StoreAverageRadiance(FfxInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + imageStore(rw_average_radiance, pixel_coordinate, FfxFloat32x4(value, 0.0f)); +} +#endif // #if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) + +FfxFloat32x3 FFX_DNSR_Reflections_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ + return FFX_DENOISER_LoadWorldSpaceNormal(pixel_coordinate); +} + +#if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) +FfxFloat32 FFX_DNSR_Reflections_SampleRoughnessHistory(FfxFloat32x2 uv) +{ + FfxFloat32 rawRoughness = FfxFloat32(textureLod(sampler2D(r_roughness_history, s_LinearSampler), uv, 0.0f).x); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(FfxInt32x2 pixel_coordinate) +{ + return normalize(FfxFloat32x3(NormalsUnpackMul() * texelFetch(r_normal_history, pixel_coordinate.xy, 0).xyz + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(FfxFloat32x2 uv) +{ + return normalize(FfxFloat32x3(NormalsUnpackMul() * textureLod(sampler2D(r_normal_history, s_LinearSampler), uv, 0.0f).xyz + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE) +FfxFloat32 FFX_DNSR_Reflections_LoadRayLength(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat32(texelFetch(r_radiance, pixel_coordinate, 0).w); +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE) + +void FFX_DNSR_Reflections_StoreVariance(FfxInt32x2 pixel_coordinate, FfxFloat32 value) +{ + StoreVariance(pixel_coordinate, value); +} + +#if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) +void FFX_DNSR_Reflections_StoreNumSamples(FfxInt32x2 pixel_coordinate, FfxFloat32 value) +{ + imageStore(rw_sample_count, pixel_coordinate, FfxFloat32x4(value)); +} +#endif // #if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) + +FfxFloat32x3 FFX_DNSR_Reflections_LoadRadiance(FfxInt32x2 pixel_coordinate) +{ + return LoadRadiance(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) +FfxFloat32x3 FFX_DNSR_Reflections_LoadRadianceReprojected(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat32x3(texelFetch(r_reprojected_radiance, pixel_coordinate, 0).xyz); +} +#endif // #if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) + +FfxFloat32 FFX_DNSR_Reflections_LoadVariance(FfxInt32x2 pixel_coordinate) +{ + return LoadVariance(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat32 FFX_DNSR_Reflections_LoadNumSamples(FfxInt32x2 pixel_coordinate) +{ + return FfxFloat32(texelFetch(r_sample_count, pixel_coordinate, 0).x); +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#endif // #if defined(FFX_HALF) + +FfxFloat32 FFX_DENOISER_LoadDepth(FfxInt32x2 pixel_coordinate, FfxInt32 mip) +{ +#if defined(DENOISER_BIND_SRV_INPUT_DEPTH_HIERARCHY) + return texelFetch(r_input_depth_hierarchy, pixel_coordinate, mip).x; +#else + return 0.0f; +#endif +} + +#if defined (DENOISER_BIND_UAV_DENOISER_TILE_LIST) +FfxUInt32 GetDenoiserTile(FfxUInt32 group_id) +{ + return rw_denoiser_tile_list.data[group_id]; +} +#endif // #if defined (DENOISER_BIND_UAV_DENOISER_TILE_LIST) + +#if defined (DENOISER_BIND_SRV_INPUT_MOTION_VECTORS) +FfxFloat32x2 FFX_DNSR_Reflections_LoadMotionVector(FfxInt32x2 pixel_coordinate) +{ + return MotionVectorScale() * texelFetch(r_input_motion_vectors, pixel_coordinate, 0).xy; +} +#endif // #if defined (DENOISER_BIND_SRV_INPUT_MOTION_VECTORS) + +FfxFloat32 FFX_DNSR_Reflections_LoadDepth(FfxInt32x2 pixel_coordinate) +{ + return FFX_DENOISER_LoadDepth(pixel_coordinate, 0); +} + +#if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) +FfxFloat32 FFX_DNSR_Reflections_LoadDepthHistory(FfxInt32x2 pixel_coordinate) +{ + return texelFetch(r_depth_history, pixel_coordinate, 0).x; +} +#endif // #if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) + +#if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) +FfxFloat32 FFX_DNSR_Reflections_SampleDepthHistory(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(r_depth_history, s_LinearSampler), uv, 0.0f).x; +} +#endif // #if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_callbacks_hlsl.h new file mode 100644 index 00000000..203c5792 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_callbacks_hlsl.h @@ -0,0 +1,647 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_denoiser_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_DENOISER_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_DENOISER_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_DENOISER_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(DENOISER_BIND_CB_DENOISER) + cbuffer cbDenoiserReflections : FFX_DENOISER_DECLARE_CB(DENOISER_BIND_CB_DENOISER) + { + FfxFloat32Mat4 invProjection; + FfxFloat32Mat4 invView; + FfxFloat32Mat4 prevViewProjection; + FfxUInt32x2 renderSize; + FfxFloat32x2 inverseRenderSize; + FfxFloat32x2 motionVectorScale; + FfxFloat32 normalsUnpackMul; + FfxFloat32 normalsUnpackAdd; + FfxBoolean isRoughnessPerceptual; + FfxFloat32 temporalStabilityFactor; + FfxFloat32 roughnessThreshold; + #define FFX_DENOISER_CONSTANT_BUFFER_1_SIZE 54 // Number of 32-bit values. This must be kept in sync with the cbDenoiser size. + }; +#else + #define invProjection 0 + #define invView 0 + #define prevViewProjection 0 + #define renderSize 0 + #define inverseRenderSize 0 + #define motionVectorScale 0 + #define normalsUnpackMul 0 + #define normalsUnpackAdd 0 + #define isRoughnessPerceptual 0 + #define temporalStabilityFactor 0 + #define roughnessThreshold 0 +#endif + +#if defined(FFX_GPU) +#define FFX_DENOISER_ROOTSIG_STRINGIFY(p) FFX_DENOISER_ROOTSIG_STR(p) +#define FFX_DENOISER_ROOTSIG_STR(p) #p +#define FFX_DENOISER_ROOTSIG [RootSignature("DescriptorTable(UAV(u0, numDescriptors = " FFX_DENOISER_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_DENOISER_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_LINEAR_MIP_POINT, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_ALWAYS, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK, " \ + "maxAnisotropy = 1)" )] + +#if defined(FFX_DENOISER_EMBED_ROOTSIG) +#define FFX_DENOISER_EMBED_ROOTSIG_CONTENT FFX_DENOISER_ROOTSIG +#else +#define FFX_DENOISER_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_DENOISER_EMBED_ROOTSIG + +#endif // #if defined(FFX_GPU) + +SamplerState s_LinearSampler : register(s0); + +FfxFloat32Mat4 InvProjection() +{ + return invProjection; +} + +FfxFloat32Mat4 InvView() +{ + return invView; +} + +FfxFloat32Mat4 PrevViewProjection() +{ + return prevViewProjection; +} + +FfxUInt32x2 RenderSize() +{ + return renderSize; +} + +FfxFloat32x2 InverseRenderSize() +{ + return inverseRenderSize; +} + +FfxFloat32x2 MotionVectorScale() +{ + return motionVectorScale; +} + +FfxFloat32 NormalsUnpackMul() +{ + return normalsUnpackMul; +} + +FfxFloat32 NormalsUnpackAdd() +{ + return normalsUnpackAdd; +} + +FfxBoolean IsRoughnessPerceptual() +{ + return isRoughnessPerceptual; +} + +FfxFloat32 TemporalStabilityFactor() +{ + return temporalStabilityFactor; +} + +FfxFloat32 RoughnessThreshold() +{ + return roughnessThreshold; +} + +// SRVs + #if defined DENOISER_BIND_SRV_INPUT_DEPTH_HIERARCHY + Texture2D r_input_depth_hierarchy : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_INPUT_DEPTH_HIERARCHY); + #endif + #if defined DENOISER_BIND_SRV_INPUT_MOTION_VECTORS + Texture2D r_input_motion_vectors : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_INPUT_MOTION_VECTORS); + #endif + #if defined DENOISER_BIND_SRV_INPUT_NORMAL + Texture2D r_input_normal : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_INPUT_NORMAL); + #endif + #if defined DENOISER_BIND_SRV_RADIANCE + Texture2D r_radiance : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_RADIANCE); + #endif + #if defined DENOISER_BIND_SRV_RADIANCE_HISTORY + Texture2D r_radiance_history : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_RADIANCE_HISTORY); + #endif + #if defined DENOISER_BIND_SRV_VARIANCE + Texture2D r_variance : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_VARIANCE); + #endif + #if defined DENOISER_BIND_SRV_SAMPLE_COUNT + Texture2D r_sample_count : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_SAMPLE_COUNT); + #endif + #if defined DENOISER_BIND_SRV_AVERAGE_RADIANCE + Texture2D r_average_radiance : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_AVERAGE_RADIANCE); + #endif + #if defined DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS + Texture2D r_extracted_roughness : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS); + #endif + #if defined DENOISER_BIND_SRV_DEPTH_HISTORY + Texture2D r_depth_history : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_DEPTH_HISTORY); + #endif + #if defined DENOISER_BIND_SRV_NORMAL_HISTORY + Texture2D r_normal_history : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_NORMAL_HISTORY); + #endif + #if defined DENOISER_BIND_SRV_ROUGHNESS_HISTORY + Texture2D r_roughness_history : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_ROUGHNESS_HISTORY); + #endif + #if defined DENOISER_BIND_SRV_REPROJECTED_RADIANCE + Texture2D r_reprojected_radiance : FFX_DENOISER_DECLARE_SRV(DENOISER_BIND_SRV_REPROJECTED_RADIANCE); + #endif + +// UAVs + #if defined DENOISER_BIND_UAV_RADIANCE + RWTexture2D rw_radiance : FFX_DENOISER_DECLARE_UAV(DENOISER_BIND_UAV_RADIANCE); + #endif + #if defined DENOISER_BIND_UAV_VARIANCE + RWTexture2D rw_variance : FFX_DENOISER_DECLARE_UAV(DENOISER_BIND_UAV_VARIANCE); + #endif + #if defined DENOISER_BIND_UAV_SAMPLE_COUNT + RWTexture2D rw_sample_count : FFX_DENOISER_DECLARE_UAV(DENOISER_BIND_UAV_SAMPLE_COUNT); + #endif + #if defined DENOISER_BIND_UAV_AVERAGE_RADIANCE + RWTexture2D rw_average_radiance : FFX_DENOISER_DECLARE_UAV(DENOISER_BIND_UAV_AVERAGE_RADIANCE); + #endif + #if defined DENOISER_BIND_UAV_DENOISER_TILE_LIST + RWStructuredBuffer rw_denoiser_tile_list : FFX_DENOISER_DECLARE_UAV(DENOISER_BIND_UAV_DENOISER_TILE_LIST); + #endif + #if defined DENOISER_BIND_UAV_REPROJECTED_RADIANCE + RWTexture2D rw_reprojected_radiance : FFX_DENOISER_DECLARE_UAV(DENOISER_BIND_UAV_REPROJECTED_RADIANCE); + #endif + +#if FFX_HALF + + +FfxFloat16x3 FFX_DENOISER_LoadWorldSpaceNormalH(FfxInt32x2 pixel_coordinate) +{ + #if defined(DENOISER_BIND_SRV_INPUT_NORMAL) + return normalize((FfxFloat16x3)(NormalsUnpackMul() * r_input_normal.Load(FfxInt32x3(pixel_coordinate, 0)) + NormalsUnpackAdd())); + #else + return 0.0f; + #endif // #if defined(DENOISER_BIND_SRV_INPUT_NORMAL) +} + +FfxFloat16x3 LoadRadianceH(FfxInt32x3 coordinate) +{ + #if defined (DENOISER_BIND_SRV_RADIANCE) + return (FfxFloat16x3)r_radiance.Load(coordinate).xyz; + #else + return 0.0f; + #endif // #if defined (DENOISER_BIND_SRV_RADIANCE) +} + +FfxFloat16 LoadVarianceH(FfxInt32x3 coordinate) +{ + #if defined (DENOISER_BIND_SRV_VARIANCE) + return (FfxFloat16)r_variance.Load(coordinate).x; + #else + return 0.0f; + #endif // #if defined (DENOISER_BIND_SRV_VARIANCE) +} + +#if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) +FfxFloat16x3 FFX_DNSR_Reflections_SampleAverageRadiance(FfxFloat32x2 uv) +{ + return (FfxFloat16x3)r_average_radiance.SampleLevel(s_LinearSampler, uv, 0.0f).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) + +#if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) +FfxFloat16 FFX_DNSR_Reflections_LoadRoughness(FfxInt32x2 pixel_coordinate) +{ + FfxFloat16 rawRoughness = (FfxFloat16)r_extracted_roughness.Load(FfxInt32x3(pixel_coordinate, 0)); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) + +void StoreRadianceH(FfxInt32x2 coordinate, FfxFloat16x4 radiance) +{ + #if defined (DENOISER_BIND_UAV_RADIANCE) + rw_radiance[coordinate] = radiance; + #endif // #if defined (DENOISER_BIND_UAV_RADIANCE) +} + +void StoreVarianceH(FfxInt32x2 coordinate, FfxFloat16 variance) +{ + #if defined (DENOISER_BIND_UAV_VARIANCE) + rw_variance[coordinate] = variance; + #endif // #if defined (DENOISER_BIND_UAV_VARIANCE) +} + +void FFX_DNSR_Reflections_StorePrefilteredReflections(FfxInt32x2 pixel_coordinate, FfxFloat16x3 radiance, FfxFloat16 variance) +{ + StoreRadianceH(pixel_coordinate, radiance.xyzz); + StoreVarianceH(pixel_coordinate, variance.x); +} + +void FFX_DNSR_Reflections_StoreTemporalAccumulation(FfxInt32x2 pixel_coordinate, FfxFloat16x3 radiance, FfxFloat16 variance) +{ + StoreRadianceH(pixel_coordinate, radiance.xyzz); + StoreVarianceH(pixel_coordinate, variance.x); +} + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_LoadRadianceHistory(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat16x3)r_radiance_history.Load(FfxInt32x3(pixel_coordinate, 0)).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_SampleRadianceHistory(FfxFloat32x2 uv) +{ + return (FfxFloat16x3)r_radiance_history.SampleLevel(s_LinearSampler, uv, 0.0f).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_VARIANCE) +FfxFloat16 FFX_DNSR_Reflections_SampleVarianceHistory(FfxFloat32x2 uv) +{ + return (FfxFloat16)r_variance.SampleLevel(s_LinearSampler, uv, 0.0f).x; +} +#endif // #if defined (DENOISER_BIND_SRV_VARIANCE) + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat16 FFX_DNSR_Reflections_SampleNumSamplesHistory(FfxFloat32x2 uv) +{ + return (FfxFloat16)r_sample_count.SampleLevel(s_LinearSampler, uv, 0.0f).x; +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) +void FFX_DNSR_Reflections_StoreRadianceReprojected(FfxInt32x2 pixel_coordinate, FfxFloat16x3 value) +{ + rw_reprojected_radiance[pixel_coordinate] = value; +} +#endif // #if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) + +#if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) +void FFX_DNSR_Reflections_StoreAverageRadiance(FfxInt32x2 pixel_coordinate, FfxFloat16x3 value) +{ + rw_average_radiance[pixel_coordinate] = value; +} +#endif // #if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) + +FfxFloat16x3 FFX_DNSR_Reflections_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ + return FFX_DENOISER_LoadWorldSpaceNormalH(pixel_coordinate); +} + +#if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) +FfxFloat16 FFX_DNSR_Reflections_SampleRoughnessHistory(FfxFloat32x2 uv) +{ + FfxFloat16 rawRoughness = (FfxFloat16)r_roughness_history.SampleLevel(s_LinearSampler, uv, 0.0f); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(FfxInt32x2 pixel_coordinate) +{ + return normalize((FfxFloat16x3)(NormalsUnpackMul() * r_normal_history.Load(FfxInt32x3(pixel_coordinate, 0)) + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat16x3 FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(FfxFloat32x2 uv) +{ + return normalize((FfxFloat16x3)(NormalsUnpackMul() * r_normal_history.SampleLevel(s_LinearSampler, uv, 0.0f) + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE) +FfxFloat16 FFX_DNSR_Reflections_LoadRayLength(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat16)r_radiance.Load(FfxInt32x3(pixel_coordinate, 0)).w; +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE) + +void FFX_DNSR_Reflections_StoreVariance(FfxInt32x2 pixel_coordinate, FfxFloat16 value) +{ + StoreVarianceH(pixel_coordinate, value); +} + +#if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) +void FFX_DNSR_Reflections_StoreNumSamples(FfxInt32x2 pixel_coordinate, FfxFloat16 value) +{ + rw_sample_count[pixel_coordinate] = value; +} +#endif // #if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) + +FfxFloat16x3 FFX_DNSR_Reflections_LoadRadiance(FfxInt32x2 pixel_coordinate) +{ + return LoadRadianceH(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) +FfxFloat16x3 FFX_DNSR_Reflections_LoadRadianceReprojected(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat16x3)r_reprojected_radiance.Load(FfxInt32x3(pixel_coordinate, 0)).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) + +FfxFloat16 FFX_DNSR_Reflections_LoadVariance(FfxInt32x2 pixel_coordinate) +{ + return LoadVarianceH(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat16 FFX_DNSR_Reflections_LoadNumSamples(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat16)r_sample_count.Load(FfxInt32x3(pixel_coordinate, 0)).x; +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#else // FFX_HALF + +FfxFloat32x3 LoadRadiance(FfxInt32x3 coordinate) +{ +#if defined (DENOISER_BIND_SRV_RADIANCE) + return r_radiance.Load(coordinate).xyz; +#else + return 0.0f; +#endif +} + +FfxFloat32 LoadVariance(FfxInt32x3 coordinate) +{ +#if defined (DENOISER_BIND_SRV_VARIANCE) + return r_variance.Load(coordinate).x; +#else + return 0.0f; +#endif +} + +FfxFloat32x3 FFX_DENOISER_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ +#if defined(DENOISER_BIND_SRV_INPUT_NORMAL) + return normalize(NormalsUnpackMul() * r_input_normal.Load(FfxInt32x3(pixel_coordinate, 0)) + NormalsUnpackAdd()); +#else + return 0.0f; +#endif +} + +#if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) +FfxFloat32 FFX_DNSR_Reflections_LoadRoughness(FfxInt32x2 pixel_coordinate) +{ + FfxFloat32 rawRoughness = (FfxFloat32)r_extracted_roughness.Load(FfxInt32x3(pixel_coordinate, 0)); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_EXTRACTED_ROUGHNESS) + +void StoreRadiance(FfxInt32x2 coordinate, FfxFloat32x4 radiance) +{ +#if defined (DENOISER_BIND_UAV_RADIANCE) + rw_radiance[coordinate] = radiance; +#endif +} + +void StoreVariance(FfxInt32x2 coordinate, FfxFloat32 variance) +{ +#if defined (DENOISER_BIND_UAV_VARIANCE) + rw_variance[coordinate] = variance; +#endif +} + +void FFX_DNSR_Reflections_StorePrefilteredReflections(FfxInt32x2 pixel_coordinate, FfxFloat32x3 radiance, FfxFloat32 variance) +{ + StoreRadiance(pixel_coordinate, radiance.xyzz); + StoreVariance(pixel_coordinate, variance.x); +} + +void FFX_DNSR_Reflections_StoreTemporalAccumulation(FfxInt32x2 pixel_coordinate, FfxFloat32x3 radiance, FfxFloat32 variance) +{ + StoreRadiance(pixel_coordinate, radiance.xyzz); + StoreVariance(pixel_coordinate, variance.x); +} + +#if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) +FfxFloat32x3 FFX_DNSR_Reflections_SampleAverageRadiance(FfxFloat32x2 uv) +{ + return (FfxFloat32x3)r_average_radiance.SampleLevel(s_LinearSampler, uv, 0.0f).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_AVERAGE_RADIANCE) + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_LoadRadianceHistory(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat32x3)r_radiance_history.Load(FfxInt32x3(pixel_coordinate, 0)).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_SampleRadianceHistory(FfxFloat32x2 uv) +{ + return (FfxFloat32x3)r_radiance_history.SampleLevel(s_LinearSampler, uv, 0.0f).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE_HISTORY) + +#if defined (DENOISER_BIND_SRV_VARIANCE) +FfxFloat32 FFX_DNSR_Reflections_SampleVarianceHistory(FfxFloat32x2 uv) +{ + return (FfxFloat32)r_variance.SampleLevel(s_LinearSampler, uv, 0.0f).x; +} +#endif // #if defined (DENOISER_BIND_SRV_VARIANCE) + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat32 FFX_DNSR_Reflections_SampleNumSamplesHistory(FfxFloat32x2 uv) +{ + return (FfxFloat32)r_sample_count.SampleLevel(s_LinearSampler, uv, 0.0f).x; +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) +void FFX_DNSR_Reflections_StoreRadianceReprojected(FfxInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + rw_reprojected_radiance[pixel_coordinate] = value; +} +#endif // #if defined (DENOISER_BIND_UAV_REPROJECTED_RADIANCE) + +#if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) +void FFX_DNSR_Reflections_StoreAverageRadiance(FfxInt32x2 pixel_coordinate, FfxFloat32x3 value) +{ + rw_average_radiance[pixel_coordinate] = value; +} +#endif // #if defined (DENOISER_BIND_UAV_AVERAGE_RADIANCE) + +FfxFloat32x3 FFX_DNSR_Reflections_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ + return FFX_DENOISER_LoadWorldSpaceNormal(pixel_coordinate); +} + +#if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) +FfxFloat32 FFX_DNSR_Reflections_SampleRoughnessHistory(FfxFloat32x2 uv) +{ + FfxFloat32 rawRoughness = (FfxFloat32)r_roughness_history.SampleLevel(s_LinearSampler, uv, 0.0f); + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (DENOISER_BIND_SRV_ROUGHNESS_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(FfxInt32x2 pixel_coordinate) +{ + return normalize((FfxFloat32x3)(NormalsUnpackMul() * r_normal_history.Load(FfxInt32x3(pixel_coordinate, 0)) + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) +FfxFloat32x3 FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(FfxFloat32x2 uv) +{ + return normalize((FfxFloat32x3)(NormalsUnpackMul() * r_normal_history.SampleLevel(s_LinearSampler, uv, 0.0f) + NormalsUnpackAdd())); +} +#endif // #if defined (DENOISER_BIND_SRV_NORMAL_HISTORY) + +#if defined (DENOISER_BIND_SRV_RADIANCE) +FfxFloat32 FFX_DNSR_Reflections_LoadRayLength(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat32)r_radiance.Load(FfxInt32x3(pixel_coordinate, 0)).w; +} +#endif // #if defined (DENOISER_BIND_SRV_RADIANCE) + +void FFX_DNSR_Reflections_StoreVariance(FfxInt32x2 pixel_coordinate, FfxFloat32 value) +{ + StoreVariance(pixel_coordinate, value); +} + +#if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) +void FFX_DNSR_Reflections_StoreNumSamples(FfxInt32x2 pixel_coordinate, FfxFloat32 value) +{ + rw_sample_count[pixel_coordinate] = value; +} +#endif // #if defined (DENOISER_BIND_UAV_SAMPLE_COUNT) + +FfxFloat32x3 FFX_DNSR_Reflections_LoadRadiance(FfxInt32x2 pixel_coordinate) +{ + return LoadRadiance(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) +FfxFloat32x3 FFX_DNSR_Reflections_LoadRadianceReprojected(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat32x3)r_reprojected_radiance.Load(FfxInt32x3(pixel_coordinate, 0)).xyz; +} +#endif // #if defined (DENOISER_BIND_SRV_REPROJECTED_RADIANCE) + +FfxFloat32 FFX_DNSR_Reflections_LoadVariance(FfxInt32x2 pixel_coordinate) +{ + return LoadVariance(FfxInt32x3(pixel_coordinate, 0)); +} + +#if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) +FfxFloat32 FFX_DNSR_Reflections_LoadNumSamples(FfxInt32x2 pixel_coordinate) +{ + return (FfxFloat32)r_sample_count.Load(FfxInt32x3(pixel_coordinate, 0)).x; +} +#endif // #if defined (DENOISER_BIND_SRV_SAMPLE_COUNT) + +#endif // #if defined(FFX_HALF) + +FfxFloat32 FFX_DENOISER_LoadDepth(FfxInt32x2 pixel_coordinate, FfxInt32 mip) +{ +#if defined(DENOISER_BIND_SRV_INPUT_DEPTH_HIERARCHY) + return r_input_depth_hierarchy.Load(FfxInt32x3(pixel_coordinate, mip)); +#else + return 0.0f; +#endif +} + +#if defined (DENOISER_BIND_UAV_DENOISER_TILE_LIST) +FfxUInt32 GetDenoiserTile(FfxUInt32 group_id) +{ + return rw_denoiser_tile_list[group_id]; +} +#endif // #if defined (DENOISER_BIND_UAV_DENOISER_TILE_LIST) + +#if defined (DENOISER_BIND_SRV_INPUT_MOTION_VECTORS) +FfxFloat32x2 FFX_DNSR_Reflections_LoadMotionVector(FfxInt32x2 pixel_coordinate) +{ + return MotionVectorScale() * r_input_motion_vectors.Load(FfxInt32x3(pixel_coordinate, 0)); +} +#endif // #if defined (DENOISER_BIND_SRV_INPUT_MOTION_VECTORS) + +FfxFloat32 FFX_DNSR_Reflections_LoadDepth(FfxInt32x2 pixel_coordinate) +{ + return FFX_DENOISER_LoadDepth(pixel_coordinate, 0); +} + +#if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) +FfxFloat32 FFX_DNSR_Reflections_LoadDepthHistory(FfxInt32x2 pixel_coordinate) +{ + return r_depth_history.Load(FfxInt32x3(pixel_coordinate, 0)); +} +#endif // #if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) + +#if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) +FfxFloat32 FFX_DNSR_Reflections_SampleDepthHistory(FfxFloat32x2 uv) +{ + return r_depth_history.SampleLevel(s_LinearSampler, uv, 0.0f); +} +#endif // #if defined (DENOISER_BIND_SRV_DEPTH_HISTORY) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_common.h new file mode 100644 index 00000000..5c1b7b12 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_common.h @@ -0,0 +1,286 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_REFLECTIONS_COMMON +#define FFX_DNSR_REFLECTIONS_COMMON + +#include "ffx_denoiser_reflections_config.h" + +FfxBoolean FFX_DNSR_Reflections_IsGlossyReflection(FfxFloat32 roughness) { + return roughness < RoughnessThreshold(); +} + +FfxBoolean FFX_DNSR_Reflections_IsMirrorReflection(FfxFloat32 roughness) { + return roughness < 0.0001; +} + +// Transforms origin to uv space +// Mat must be able to transform origin from its current space into clip space. +FfxFloat32x3 ProjectPosition(FfxFloat32x3 origin, FfxFloat32Mat4 mat) { + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(origin, 1)); + projected.xyz /= projected.w; + projected.xy = 0.5 * projected.xy + 0.5; + projected.y = (1 - projected.y); + return projected.xyz; +} + +// Mat must be able to transform origin from texture space to a linear space. +FfxFloat32x3 FFX_DNSR_InvProjectPosition(FfxFloat32x3 coord, FfxFloat32Mat4 mat) { + coord.y = (1 - coord.y); + coord.xy = 2 * coord.xy - 1; + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(coord, 1)); + projected.xyz /= projected.w; + return projected.xyz; +} + +FfxFloat32 FFX_DNSR_Reflections_GetLinearDepth(FfxFloat32x2 uv, FfxFloat32 depth) { + const FfxFloat32x3 view_space_pos = FFX_DNSR_InvProjectPosition(FfxFloat32x3(uv, depth), InvProjection()); + return abs(view_space_pos.z); +} + +FfxFloat32x3 FFX_DNSR_Reflections_ScreenSpaceToViewSpace(FfxFloat32x3 screen_uv_coord) { + return FFX_DNSR_InvProjectPosition(screen_uv_coord, InvProjection()); +} + +FfxFloat32x3 FFX_DNSR_Reflections_WorldSpaceToScreenSpacePrevious(FfxFloat32x3 world_space_pos) { + return ProjectPosition(world_space_pos, PrevViewProjection()); +} + +FfxFloat32x3 FFX_DNSR_Reflections_ViewSpaceToWorldSpace(FfxFloat32x4 view_space_coord) { + return FFX_MATRIX_MULTIPLY(InvView(), view_space_coord).xyz; +} + +// Rounds value to the nearest multiple of 8 +FfxUInt32x2 FFX_DNSR_Reflections_RoundUp8(FfxUInt32x2 value) { + FfxUInt32x2 round_down = value & ~7; // 0b111; + return FFX_SELECT((round_down == value), value, value + 8); +} + +#if FFX_HALF + +FfxFloat16 FFX_DNSR_Reflections_Luminance(FfxFloat16x3 color) +{ + return max(FfxFloat16(dot(color, FfxFloat16x3(0.299f, 0.587f, 0.114f))), FfxFloat16(0.001)); +} + +FfxFloat16 FFX_DNSR_Reflections_ComputeTemporalVariance(FfxFloat16x3 history_radiance, FfxFloat16x3 radiance) { + FfxFloat16 history_luminance = FFX_DNSR_Reflections_Luminance(history_radiance); + FfxFloat16 luminance = FFX_DNSR_Reflections_Luminance(radiance); + FfxFloat16 diff = abs(history_luminance - luminance) / max(max(history_luminance, luminance), FfxFloat16(0.5f)); + return diff * diff; +} + +FfxUInt32 FFX_DNSR_Reflections_PackFloat16(FfxFloat16x2 v) +{ +#if defined(FFX_GLSL) + return ffxPackHalf2x16(FfxFloat32x2(v)); +#elif defined(FFX_HLSL) + FfxUInt32x2 p = ffxF32ToF16(FfxFloat32x2(v)); + return p.x | (p.y << 16); +#endif + + return 0; +} + +FfxFloat16x2 FFX_DNSR_Reflections_UnpackFloat16(FfxUInt32 a) +{ +#if defined(FFX_GLSL) + return FfxFloat16x2(unpackHalf2x16(a)); +#elif defined(FFX_HLSL) + FfxFloat32x2 tmp = f16tof32(FfxUInt32x2(a & 0xFFFF, a >> 16)); + return FfxFloat16x2(tmp); +#endif + + return FfxFloat16x2(0.0f, 0.0f); +} + +FfxUInt32x2 FFX_DNSR_Reflections_PackFloat16_4(FfxFloat16x4 v) { return FfxUInt32x2(FFX_DNSR_Reflections_PackFloat16(v.xy), FFX_DNSR_Reflections_PackFloat16(v.zw)); } + +FfxFloat16x4 FFX_DNSR_Reflections_UnpackFloat16_4(FfxUInt32x2 a) { return FfxFloat16x4(FFX_DNSR_Reflections_UnpackFloat16(a.x), FFX_DNSR_Reflections_UnpackFloat16(a.y)); } + +// From "Temporal Reprojection Anti-Aliasing" +// https://github.com/playdeadgames/temporal +/********************************************************************** +Copyright (c) [2015] [Playdead] + +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. +********************************************************************/ +FfxFloat16x3 FFX_DNSR_Reflections_ClipAABB(FfxFloat16x3 aabb_min, FfxFloat16x3 aabb_max, FfxFloat16x3 prev_sample) { + // Main idea behind clipping - it prevents clustering when neighbor color space + // is distant from history sample + + // Here we find intersection between color vector and aabb color box + + // Note: only clips towards aabb center + FfxFloat32x3 aabb_center = 0.5 * (aabb_max + aabb_min); + FfxFloat32x3 extent_clip = 0.5 * (aabb_max - aabb_min) + 0.001; + + // Find color vector + FfxFloat32x3 color_vector = prev_sample - aabb_center; + // Transform into clip space + FfxFloat32x3 color_vector_clip = color_vector / extent_clip; + // Find max absolute component + color_vector_clip = abs(color_vector_clip); + FfxFloat16 max_abs_unit = FfxFloat16(max(max(color_vector_clip.x, color_vector_clip.y), color_vector_clip.z)); + + if (max_abs_unit > 1.0) { + return FfxFloat16x3(aabb_center + color_vector / max_abs_unit); // clip towards color vector + } else { + return FfxFloat16x3(prev_sample); // point is inside aabb + } +} + +#ifdef FFX_DNSR_REFLECTIONS_ESTIMATES_LOCAL_NEIGHBORHOOD + +# ifndef FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS +# define FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS 4 +# endif + +FfxFloat16 FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat16 i) { + const FfxFloat16 radius = FfxFloat16(FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS + 1.0f); + return FfxFloat16(exp(-FFX_DNSR_REFLECTIONS_GAUSSIAN_K * (i * i) / (radius * radius))); +} + +#endif // FFX_DNSR_REFLECTIONS_ESTIMATES_LOCAL_NEIGHBORHOOD + +#else // FFX_HALF + +FfxFloat32 FFX_DNSR_Reflections_Luminance(FfxFloat32x3 color) +{ + return max(FfxFloat32(dot(color, FfxFloat32x3(0.299f, 0.587f, 0.114f))), FfxFloat32(0.001)); +} + +FfxFloat32 FFX_DNSR_Reflections_ComputeTemporalVariance(FfxFloat32x3 history_radiance, FfxFloat32x3 radiance) { + FfxFloat32 history_luminance = FFX_DNSR_Reflections_Luminance(history_radiance); + FfxFloat32 luminance = FFX_DNSR_Reflections_Luminance(radiance); + FfxFloat32 diff = abs(history_luminance - luminance) / max(max(history_luminance, luminance), FfxFloat32(0.5f)); + return diff * diff; +} + +FfxUInt32 FFX_DNSR_Reflections_PackFloat16(FfxFloat32x2 v) +{ +#if defined(FFX_GLSL) + return ffxPackHalf2x16(v); +#elif defined(FFX_HLSL) + FfxUInt32x2 p = ffxF32ToF16(v); + return p.x | (p.y << 16); +#endif + + return 0; +} + +FfxFloat32x2 FFX_DNSR_Reflections_UnpackFloat16(FfxUInt32 a) +{ +#if defined(FFX_GLSL) + return unpackHalf2x16(a); +#elif defined(FFX_HLSL) + FfxFloat32x2 tmp = f16tof32(FfxUInt32x2(a & 0xFFFF, a >> 16)); + return tmp; +#endif + + return FfxFloat32x2(0.0f, 0.0f); +} + +FfxUInt32x2 FFX_DNSR_Reflections_PackFloat16_4(FfxFloat32x4 v) { return FfxUInt32x2(FFX_DNSR_Reflections_PackFloat16(v.xy), FFX_DNSR_Reflections_PackFloat16(v.zw)); } + +FfxFloat32x4 FFX_DNSR_Reflections_UnpackFloat16_4(FfxUInt32x2 a) { return FfxFloat32x4(FFX_DNSR_Reflections_UnpackFloat16(a.x), FFX_DNSR_Reflections_UnpackFloat16(a.y)); } + +// From "Temporal Reprojection Anti-Aliasing" +// https://github.com/playdeadgames/temporal +/********************************************************************** +Copyright (c) [2015] [Playdead] + +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. +********************************************************************/ +FfxFloat32x3 FFX_DNSR_Reflections_ClipAABB(FfxFloat32x3 aabb_min, FfxFloat32x3 aabb_max, FfxFloat32x3 prev_sample) { + // Main idea behind clipping - it prevents clustering when neighbor color space + // is distant from history sample + + // Here we find intersection between color vector and aabb color box + + // Note: only clips towards aabb center + FfxFloat32x3 aabb_center = 0.5 * (aabb_max + aabb_min); + FfxFloat32x3 extent_clip = 0.5 * (aabb_max - aabb_min) + 0.001; + + // Find color vector + FfxFloat32x3 color_vector = prev_sample - aabb_center; + // Transform into clip space + FfxFloat32x3 color_vector_clip = color_vector / extent_clip; + // Find max absolute component + color_vector_clip = abs(color_vector_clip); + FfxFloat32 max_abs_unit = FfxFloat32(max(max(color_vector_clip.x, color_vector_clip.y), color_vector_clip.z)); + + if (max_abs_unit > 1.0) { + return FfxFloat32x3(aabb_center + color_vector / max_abs_unit); // clip towards color vector + } else { + return FfxFloat32x3(prev_sample); // point is inside aabb + } +} + +#ifdef FFX_DNSR_REFLECTIONS_ESTIMATES_LOCAL_NEIGHBORHOOD + +# ifndef FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS +# define FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS 4 +# endif + +FfxFloat32 FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat32 i) { + const FfxFloat32 radius = FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS + 1.0; + return exp(-FFX_DNSR_REFLECTIONS_GAUSSIAN_K * (i * i) / (radius * radius)); +} + +#endif // FFX_DNSR_REFLECTIONS_ESTIMATES_LOCAL_NEIGHBORHOOD + +#endif // FFX_HALF + +#endif // FFX_DNSR_REFLECTIONS_COMMON diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_config.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_config.h new file mode 100644 index 00000000..daba6fb3 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_config.h @@ -0,0 +1,41 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_REFLECTIONS_CONFIG +#define FFX_DNSR_REFLECTIONS_CONFIG + +#define FFX_DNSR_REFLECTIONS_GAUSSIAN_K 3.0 +#define FFX_DNSR_REFLECTIONS_RADIANCE_WEIGHT_BIAS 0.6 +#define FFX_DNSR_REFLECTIONS_RADIANCE_WEIGHT_VARIANCE_K 0.1 +#define FFX_DNSR_REFLECTIONS_AVG_RADIANCE_LUMINANCE_WEIGHT 0.3 +#define FFX_DNSR_REFLECTIONS_PREFILTER_VARIANCE_WEIGHT 4.4 +#define FFX_DNSR_REFLECTIONS_REPROJECT_SURFACE_DISCARD_VARIANCE_WEIGHT 1.5 +#define FFX_DNSR_REFLECTIONS_PREFILTER_VARIANCE_BIAS 0.1 +#define FFX_DNSR_REFLECTIONS_PREFILTER_NORMAL_SIGMA 512.0 +#define FFX_DNSR_REFLECTIONS_PREFILTER_DEPTH_SIGMA 4.0 +#define FFX_DNSR_REFLECTIONS_DISOCCLUSION_NORMAL_WEIGHT 1.4 +#define FFX_DNSR_REFLECTIONS_DISOCCLUSION_DEPTH_WEIGHT 1.0 +#define FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD 0.9 +#define FFX_DNSR_REFLECTIONS_REPROJECTION_NORMAL_SIMILARITY_THRESHOLD 0.9999 +#define FFX_DNSR_REFLECTIONS_SAMPLES_FOR_ROUGHNESS(r) (1.0 - exp(-r * 100.0)) + +#endif // FFX_DNSR_REFLECTIONS_CONFIG diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_prefilter.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_prefilter.h new file mode 100644 index 00000000..f9d61e79 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_prefilter.h @@ -0,0 +1,340 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_REFLECTIONS_PREFILTER +#define FFX_DNSR_REFLECTIONS_PREFILTER + +#include "ffx_denoiser_reflections_common.h" + +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_0[16][16]; +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_1[16][16]; +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_2[16][16]; +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_3[16][16]; +FFX_GROUPSHARED FfxFloat32 g_ffx_dnsr_shared_depth[16][16]; + +#if FFX_HALF + +struct FFX_DNSR_Reflections_NeighborhoodSample { + FfxFloat16x3 radiance; + FfxFloat16 variance; + FfxFloat16x3 normal; + FfxFloat32 depth; +}; + +FFX_DNSR_Reflections_NeighborhoodSample FFX_DNSR_Reflections_LoadFromGroupSharedMemory(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + FfxFloat16x4 unpacked_radiance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance); + FfxUInt32x2 packed_normal_variance = FfxUInt32x2(g_ffx_dnsr_shared_2[idx.y][idx.x], g_ffx_dnsr_shared_3[idx.y][idx.x]); + FfxFloat16x4 unpacked_normal_variance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_normal_variance); + + FFX_DNSR_Reflections_NeighborhoodSample neighborSample; + neighborSample.radiance = unpacked_radiance.xyz; + neighborSample.normal = unpacked_normal_variance.xyz; + neighborSample.variance = unpacked_normal_variance.w; + neighborSample.depth = g_ffx_dnsr_shared_depth[idx.y][idx.x]; + return neighborSample; +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat16x3 radiance, FfxFloat16 variance, FfxFloat16x3 normal, FfxFloat32 depth) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.zz); + g_ffx_dnsr_shared_2[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(normal.xy); + g_ffx_dnsr_shared_3[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(FfxFloat16x2(normal.z, variance)); + g_ffx_dnsr_shared_depth[group_thread_id.y][group_thread_id.x] = depth; +} + +void FFX_DNSR_Reflections_LoadNeighborhood( + FfxInt32x2 pixel_coordinate, + FFX_PARAMETER_OUT FfxFloat16x3 radiance, + FFX_PARAMETER_OUT FfxFloat16 variance, + FFX_PARAMETER_OUT FfxFloat16x3 normal, + FFX_PARAMETER_OUT FfxFloat32 depth, + FfxInt32x2 screen_size) { + + radiance = LoadRadianceH(FfxInt32x3(pixel_coordinate, 0)); + variance = LoadVarianceH(FfxInt32x3(pixel_coordinate, 0)); + + normal = FFX_DENOISER_LoadWorldSpaceNormalH(pixel_coordinate); + + FfxFloat32x2 uv = (pixel_coordinate.xy + (0.5f).xx) / FfxFloat32x2(screen_size.xy); + depth = FFX_DNSR_Reflections_GetLinearDepth(uv, FFX_DENOISER_LoadDepth(pixel_coordinate, 0)); +} + +void FFX_DNSR_Reflections_InitializeGroupSharedMemory(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxInt32x2 screen_size) { + // Load 16x16 region into shared memory using 4 8x8 blocks. + FfxInt32x2 offset[4] = {FfxInt32x2(0, 0), FfxInt32x2(8, 0), FfxInt32x2(0, 8), FfxInt32x2(8, 8)}; + + // Intermediate storage registers to cache the result of all loads + FfxFloat16x3 radiance[4]; + FfxFloat16 variance[4]; + FfxFloat16x3 normal[4]; + FfxFloat32 depth[4]; + + // Start in the upper left corner of the 16x16 region. + dispatch_thread_id -= 4; + + // First store all loads in registers + for (FfxInt32 i = 0; i < 4; ++i) { + FFX_DNSR_Reflections_LoadNeighborhood(dispatch_thread_id + offset[i], radiance[i], variance[i], normal[i], depth[i], screen_size); + } + + // Then move all registers to groupshared memory + for (FfxInt32 j = 0; j < 4; ++j) { + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id + offset[j], radiance[j], variance[j], normal[j], depth[j]); // X + } +} + +FfxFloat16 FFX_DNSR_Reflections_GetEdgeStoppingNormalWeight(FfxFloat16x3 normal_p, FfxFloat16x3 normal_q) { + return FfxFloat16(pow(max(dot(normal_p, normal_q), FfxFloat16(0.0f)), FFX_DNSR_REFLECTIONS_PREFILTER_NORMAL_SIGMA)); +} + +FfxFloat16 FFX_DNSR_Reflections_GetEdgeStoppingDepthWeight(FfxFloat32 center_depth, FfxFloat32 neighbor_depth) { + return FfxFloat16(exp(-abs(center_depth - neighbor_depth) * center_depth * FFX_DNSR_REFLECTIONS_PREFILTER_DEPTH_SIGMA)); +} + +FfxFloat16 FFX_DNSR_Reflections_GetRadianceWeight(FfxFloat16x3 center_radiance, FfxFloat16x3 neighbor_radiance, FfxFloat16 variance) { + return FfxFloat16(max(exp(-(FFX_DNSR_REFLECTIONS_RADIANCE_WEIGHT_BIAS + variance * FFX_DNSR_REFLECTIONS_RADIANCE_WEIGHT_VARIANCE_K) + * length(center_radiance - neighbor_radiance.xyz)) + , 1.0e-2)); +} + +void FFX_DNSR_Reflections_Resolve(FfxInt32x2 group_thread_id, FfxFloat16x3 avg_radiance, FFX_DNSR_Reflections_NeighborhoodSample center, + out FfxFloat16x3 resolved_radiance, out FfxFloat16 resolved_variance) { + // Initial weight is important to remove fireflies. + // That removes quite a bit of energy but makes everything much more stable. + FfxFloat16 accumulated_weight = FFX_DNSR_Reflections_GetRadianceWeight(avg_radiance, center.radiance.xyz, center.variance); + FfxFloat16x3 accumulated_radiance = center.radiance.xyz * accumulated_weight; + FfxFloat16 accumulated_variance = center.variance * accumulated_weight * accumulated_weight; + // First 15 numbers of Halton(2,3) streteched to [-3,3]. Skipping the center, as we already have that in center_radiance and center_variance. + const FfxUInt32 sample_count = 15; + const FfxInt32x2 sample_offsets[] = {FfxInt32x2(0, 1), FfxInt32x2(-2, 1), FfxInt32x2(2, -3), FfxInt32x2(-3, 0), FfxInt32x2(1, 2), FfxInt32x2(-1, -2), FfxInt32x2(3, 0), FfxInt32x2(-3, 3), + FfxInt32x2(0, -3), FfxInt32x2(-1, -1), FfxInt32x2(2, 1), FfxInt32x2(-2, -2), FfxInt32x2(1, 0), FfxInt32x2(0, 2), FfxInt32x2(3, -1)}; + FfxFloat16 variance_weight = FfxFloat16(max(FFX_DNSR_REFLECTIONS_PREFILTER_VARIANCE_BIAS, + 1.0 - exp(-(center.variance * FFX_DNSR_REFLECTIONS_PREFILTER_VARIANCE_WEIGHT)) + )); + for (FfxInt32 i = 0; i < sample_count; ++i) { + FfxInt32x2 new_idx = group_thread_id + sample_offsets[i]; + FFX_DNSR_Reflections_NeighborhoodSample neighbor = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(new_idx); + + FfxFloat16 weight = FfxFloat16(1.0f); + weight *= FFX_DNSR_Reflections_GetEdgeStoppingNormalWeight(center.normal, neighbor.normal); + weight *= FFX_DNSR_Reflections_GetEdgeStoppingDepthWeight(center.depth, neighbor.depth); + weight *= FFX_DNSR_Reflections_GetRadianceWeight(avg_radiance, neighbor.radiance.xyz, center.variance); + weight *= variance_weight; + + // Accumulate all contributions. + accumulated_weight += weight; + accumulated_radiance += weight * neighbor.radiance.xyz; + accumulated_variance += weight * weight * neighbor.variance; + } + + accumulated_radiance /= accumulated_weight; + accumulated_variance /= (accumulated_weight * accumulated_weight); + resolved_radiance = accumulated_radiance; + resolved_variance = accumulated_variance; +} + +void FFX_DNSR_Reflections_Prefilter(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxUInt32x2 screen_size) { + FfxFloat16 center_roughness = FFX_DNSR_Reflections_LoadRoughness(dispatch_thread_id); + FFX_DNSR_Reflections_InitializeGroupSharedMemory(dispatch_thread_id, group_thread_id, FfxInt32x2(screen_size)); + FFX_GROUP_MEMORY_BARRIER; + + group_thread_id += 4; // Center threads in groupshared memory + + FFX_DNSR_Reflections_NeighborhoodSample center = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(group_thread_id); + + FfxFloat16x3 resolved_radiance = center.radiance; + FfxFloat16 resolved_variance = center.variance; + + // Check if we have to denoise or if a simple copy is enough + bool needs_denoiser = center.variance > 0.0 && FFX_DNSR_Reflections_IsGlossyReflection(center_roughness) && !FFX_DNSR_Reflections_IsMirrorReflection(center_roughness); + if (needs_denoiser) { + FfxFloat32x2 uv8 = (FfxFloat32x2(dispatch_thread_id.xy) + (0.5).xx) / FFX_DNSR_Reflections_RoundUp8(screen_size); + FfxFloat16x3 avg_radiance = FFX_DNSR_Reflections_SampleAverageRadiance(uv8); + FFX_DNSR_Reflections_Resolve(group_thread_id, avg_radiance, center, resolved_radiance, resolved_variance); + } + + FFX_DNSR_Reflections_StorePrefilteredReflections(dispatch_thread_id, resolved_radiance, resolved_variance); +} + +#else // FFX_HALF + +struct FFX_DNSR_Reflections_NeighborhoodSample { + FfxFloat32x3 radiance; + FfxFloat32 variance; + FfxFloat32x3 normal; + FfxFloat32 depth; +}; + +FFX_DNSR_Reflections_NeighborhoodSample FFX_DNSR_Reflections_LoadFromGroupSharedMemory(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + FfxFloat32x4 unpacked_radiance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance); + FfxUInt32x2 packed_normal_variance = FfxUInt32x2(g_ffx_dnsr_shared_2[idx.y][idx.x], g_ffx_dnsr_shared_3[idx.y][idx.x]); + FfxFloat32x4 unpacked_normal_variance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_normal_variance); + + FFX_DNSR_Reflections_NeighborhoodSample neighborSample; + neighborSample.radiance = unpacked_radiance.xyz; + neighborSample.normal = unpacked_normal_variance.xyz; + neighborSample.variance = unpacked_normal_variance.w; + neighborSample.depth = g_ffx_dnsr_shared_depth[idx.y][idx.x]; + return neighborSample; +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat32x3 radiance, FfxFloat32 variance, FfxFloat32x3 normal, FfxFloat32 depth) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.zz); + g_ffx_dnsr_shared_2[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(normal.xy); + g_ffx_dnsr_shared_3[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(FfxFloat32x2(normal.z, variance)); + g_ffx_dnsr_shared_depth[group_thread_id.y][group_thread_id.x] = depth; +} + +void FFX_DNSR_Reflections_LoadNeighborhood( + FfxInt32x2 pixel_coordinate, + FFX_PARAMETER_OUT FfxFloat32x3 radiance, + FFX_PARAMETER_OUT FfxFloat32 variance, + FFX_PARAMETER_OUT FfxFloat32x3 normal, + FFX_PARAMETER_OUT FfxFloat32 depth, + FfxInt32x2 screen_size) { + + radiance = LoadRadiance(FfxInt32x3(pixel_coordinate, 0)); + variance = LoadVariance(FfxInt32x3(pixel_coordinate, 0)); + + normal = FFX_DENOISER_LoadWorldSpaceNormal(pixel_coordinate); + + FfxFloat32x2 uv = (pixel_coordinate.xy + (0.5f).xx) / FfxFloat32x2(screen_size.xy); + depth = FFX_DNSR_Reflections_GetLinearDepth(uv, FFX_DENOISER_LoadDepth(pixel_coordinate, 0)); +} + +void FFX_DNSR_Reflections_InitializeGroupSharedMemory(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxInt32x2 screen_size) { + // Load 16x16 region into shared memory using 4 8x8 blocks. + FfxInt32x2 offset[4] = {FfxInt32x2(0, 0), FfxInt32x2(8, 0), FfxInt32x2(0, 8), FfxInt32x2(8, 8)}; + + // Intermediate storage registers to cache the result of all loads + FfxFloat32x3 radiance[4]; + FfxFloat32 variance[4]; + FfxFloat32x3 normal[4]; + FfxFloat32 depth[4]; + + // Start in the upper left corner of the 16x16 region. + dispatch_thread_id -= 4; + + // First store all loads in registers + for (FfxInt32 i = 0; i < 4; ++i) { + FFX_DNSR_Reflections_LoadNeighborhood(dispatch_thread_id + offset[i], radiance[i], variance[i], normal[i], depth[i], screen_size); + } + + // Then move all registers to groupshared memory + for (FfxInt32 j = 0; j < 4; ++j) { + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id + offset[j], radiance[j], variance[j], normal[j], depth[j]); // X + } +} + +FfxFloat32 FFX_DNSR_Reflections_GetEdgeStoppingNormalWeight(FfxFloat32x3 normal_p, FfxFloat32x3 normal_q) { + return FfxFloat32(pow(max(dot(normal_p, normal_q), FfxFloat32(0.0f)), FFX_DNSR_REFLECTIONS_PREFILTER_NORMAL_SIGMA)); +} + +FfxFloat32 FFX_DNSR_Reflections_GetEdgeStoppingDepthWeight(FfxFloat32 center_depth, FfxFloat32 neighbor_depth) { + return FfxFloat32(exp(-abs(center_depth - neighbor_depth) * center_depth * FFX_DNSR_REFLECTIONS_PREFILTER_DEPTH_SIGMA)); +} + +FfxFloat32 FFX_DNSR_Reflections_GetRadianceWeight(FfxFloat32x3 center_radiance, FfxFloat32x3 neighbor_radiance, FfxFloat32 variance) { + return FfxFloat32(max(exp(-(FFX_DNSR_REFLECTIONS_RADIANCE_WEIGHT_BIAS + variance * FFX_DNSR_REFLECTIONS_RADIANCE_WEIGHT_VARIANCE_K) + * length(center_radiance - neighbor_radiance.xyz)) + , 1.0e-2)); +} + +void FFX_DNSR_Reflections_Resolve(FfxInt32x2 group_thread_id, FfxFloat32x3 avg_radiance, FFX_DNSR_Reflections_NeighborhoodSample center, + out FfxFloat32x3 resolved_radiance, out FfxFloat32 resolved_variance) { + // Initial weight is important to remove fireflies. + // That removes quite a bit of energy but makes everything much more stable. + FfxFloat32 accumulated_weight = FFX_DNSR_Reflections_GetRadianceWeight(avg_radiance, center.radiance.xyz, center.variance); + FfxFloat32x3 accumulated_radiance = center.radiance.xyz * accumulated_weight; + FfxFloat32 accumulated_variance = center.variance * accumulated_weight * accumulated_weight; + // First 15 numbers of Halton(2,3) streteched to [-3,3]. Skipping the center, as we already have that in center_radiance and center_variance. + const FfxUInt32 sample_count = 15; + const FfxInt32x2 sample_offsets[] = {FfxInt32x2(0, 1), FfxInt32x2(-2, 1), FfxInt32x2(2, -3), FfxInt32x2(-3, 0), FfxInt32x2(1, 2), FfxInt32x2(-1, -2), FfxInt32x2(3, 0), FfxInt32x2(-3, 3), + FfxInt32x2(0, -3), FfxInt32x2(-1, -1), FfxInt32x2(2, 1), FfxInt32x2(-2, -2), FfxInt32x2(1, 0), FfxInt32x2(0, 2), FfxInt32x2(3, -1)}; + FfxFloat32 variance_weight = FfxFloat32(max(FFX_DNSR_REFLECTIONS_PREFILTER_VARIANCE_BIAS, + 1.0 - exp(-(center.variance * FFX_DNSR_REFLECTIONS_PREFILTER_VARIANCE_WEIGHT)) + )); + for (FfxInt32 i = 0; i < sample_count; ++i) { + FfxInt32x2 new_idx = group_thread_id + sample_offsets[i]; + FFX_DNSR_Reflections_NeighborhoodSample neighbor = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(new_idx); + + FfxFloat32 weight = FfxFloat32(1.0f); + weight *= FFX_DNSR_Reflections_GetEdgeStoppingNormalWeight(center.normal, neighbor.normal); + weight *= FFX_DNSR_Reflections_GetEdgeStoppingDepthWeight(center.depth, neighbor.depth); + weight *= FFX_DNSR_Reflections_GetRadianceWeight(avg_radiance, neighbor.radiance.xyz, center.variance); + weight *= variance_weight; + + // Accumulate all contributions. + accumulated_weight += weight; + accumulated_radiance += weight * neighbor.radiance.xyz; + accumulated_variance += weight * weight * neighbor.variance; + } + + accumulated_radiance /= accumulated_weight; + accumulated_variance /= (accumulated_weight * accumulated_weight); + resolved_radiance = accumulated_radiance; + resolved_variance = accumulated_variance; +} + +void FFX_DNSR_Reflections_Prefilter(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxUInt32x2 screen_size) { + FfxFloat32 center_roughness = FFX_DNSR_Reflections_LoadRoughness(dispatch_thread_id); + FFX_DNSR_Reflections_InitializeGroupSharedMemory(dispatch_thread_id, group_thread_id, FfxInt32x2(screen_size)); + FFX_GROUP_MEMORY_BARRIER; + + group_thread_id += 4; // Center threads in groupshared memory + + FFX_DNSR_Reflections_NeighborhoodSample center = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(group_thread_id); + + FfxFloat32x3 resolved_radiance = center.radiance; + FfxFloat32 resolved_variance = center.variance; + + // Check if we have to denoise or if a simple copy is enough + bool needs_denoiser = center.variance > 0.0 && FFX_DNSR_Reflections_IsGlossyReflection(center_roughness) && !FFX_DNSR_Reflections_IsMirrorReflection(center_roughness); + if (needs_denoiser) { + FfxFloat32x2 uv8 = (FfxFloat32x2(dispatch_thread_id.xy) + (0.5).xx) / FFX_DNSR_Reflections_RoundUp8(screen_size); + FfxFloat32x3 avg_radiance = FFX_DNSR_Reflections_SampleAverageRadiance(uv8); + FFX_DNSR_Reflections_Resolve(group_thread_id, avg_radiance, center, resolved_radiance, resolved_variance); + } + + FFX_DNSR_Reflections_StorePrefilteredReflections(dispatch_thread_id, resolved_radiance, resolved_variance); +} + +#endif // FFX_HALF + +void Prefilter(FfxUInt32 group_index, FfxUInt32 group_id, FfxInt32x2 group_thread_id) { + FfxUInt32 packed_coords = GetDenoiserTile(group_id); + FfxInt32x2 dispatch_thread_id = FfxInt32x2(packed_coords & 0xffffu, (packed_coords >> 16) & 0xffffu) + group_thread_id; + FfxInt32x2 dispatch_group_id = dispatch_thread_id / 8; + FfxInt32x2 remapped_group_thread_id = FfxInt32x2(ffxRemapForWaveReduction(group_index)); + FfxInt32x2 remapped_dispatch_thread_id = FfxInt32x2(dispatch_group_id * 8 + remapped_group_thread_id); + + FFX_DNSR_Reflections_Prefilter(remapped_dispatch_thread_id, remapped_group_thread_id, RenderSize()); +} + +#else + +void Prefilter(FfxUInt32 group_index, FfxUInt32 group_id, FfxInt32x2 group_thread_id) {} + +#endif // FFX_DNSR_REFLECTIONS_PREFILTER diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_reproject.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_reproject.h new file mode 100644 index 00000000..d8ff0e09 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_reproject.h @@ -0,0 +1,722 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_REFLECTIONS_REPROJECT +#define FFX_DNSR_REFLECTIONS_REPROJECT + +#define FFX_DNSR_REFLECTIONS_ESTIMATES_LOCAL_NEIGHBORHOOD +#include "ffx_denoiser_reflections_common.h" + +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_0[16][16]; +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_1[16][16]; + +#if FFX_HALF + +struct FFX_DNSR_Reflections_NeighborhoodSample { + FfxFloat16x3 radiance; +}; + +FFX_DNSR_Reflections_NeighborhoodSample FFX_DNSR_Reflections_LoadFromGroupSharedMemory(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + FfxFloat16x4 unpacked_radiance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance); + + FFX_DNSR_Reflections_NeighborhoodSample neighborSample; + neighborSample.radiance = unpacked_radiance.xyz; + return neighborSample; +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat16x3 radiance) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.zz); +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat16x4 radiance_variance) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance_variance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance_variance.zw); +} + +void FFX_DNSR_Reflections_InitializeGroupSharedMemory(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxInt32x2 screen_size) { + // Load 16x16 region into shared memory using 4 8x8 blocks. + FfxInt32x2 offset[4] = {FfxInt32x2(0, 0), FfxInt32x2(8, 0), FfxInt32x2(0, 8), FfxInt32x2(8, 8)}; + + // Intermediate storage registers to cache the result of all loads + FfxFloat16x3 radiance[4]; + + // Start in the upper left corner of the 16x16 region. + dispatch_thread_id -= 4; + + // First store all loads in registers + for (FfxInt32 i = 0; i < 4; ++i) { + radiance[i] = FFX_DNSR_Reflections_LoadRadiance(dispatch_thread_id + offset[i]); + } + + // Then move all registers to FFX_GROUPSHARED memory + for (FfxInt32 j = 0; j < 4; ++j) { + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id + offset[j], radiance[j]); // X + } +} + +FfxFloat16x4 FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + return FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance); +} + +FfxFloat16 FFX_DNSR_Reflections_GetLuminanceWeight(FfxFloat16x3 val) { + FfxFloat16 luma = FFX_DNSR_Reflections_Luminance(val.xyz); + FfxFloat16 weight = FfxFloat16(max(exp(-luma * FFX_DNSR_REFLECTIONS_AVG_RADIANCE_LUMINANCE_WEIGHT), 1.0e-2)); + return weight; +} + +FfxFloat32x2 FFX_DNSR_Reflections_GetSurfaceReprojection(FfxInt32x2 dispatch_thread_id, FfxFloat32x2 uv, FfxFloat32x2 motion_vector) { + // Reflector position reprojection + FfxFloat32x2 history_uv = uv + motion_vector; + return history_uv; +} + +FfxFloat32x2 FFX_DNSR_Reflections_GetHitPositionReprojection(FfxInt32x2 dispatch_thread_id, FfxFloat32x2 uv, FfxFloat32 reflected_ray_length) { + FfxFloat32 z = FFX_DNSR_Reflections_LoadDepth(dispatch_thread_id); + FfxFloat32x3 view_space_ray = FFX_DNSR_Reflections_ScreenSpaceToViewSpace(FfxFloat32x3(uv, z)); + + // We start out with reconstructing the ray length in view space. + // This includes the portion from the camera to the reflecting surface as well as the portion from the surface to the hit position. + FfxFloat32 surface_depth = length(view_space_ray); + FfxFloat32 ray_length = surface_depth + reflected_ray_length; + + // We then perform a parallax correction by shooting a ray + // of the same length "straight through" the reflecting surface + // and reprojecting the tip of that ray to the previous frame. + view_space_ray /= surface_depth; // == normalize(view_space_ray) + view_space_ray *= ray_length; + FfxFloat32x3 world_hit_position = + FFX_DNSR_Reflections_ViewSpaceToWorldSpace(FfxFloat32x4(view_space_ray, 1)); // This is the "fake" hit position if we would follow the ray straight through the surface. + FfxFloat32x3 prev_hit_position = FFX_DNSR_Reflections_WorldSpaceToScreenSpacePrevious(world_hit_position); + FfxFloat32x2 history_uv = prev_hit_position.xy; + return history_uv; +} + +FfxFloat16 FFX_DNSR_Reflections_GetDisocclusionFactor(FfxFloat16x3 normal, FfxFloat16x3 history_normal, FfxFloat32 linear_depth, FfxFloat32 history_linear_depth) { + FfxFloat16 factor = FfxFloat16(1.0f // + * exp(-abs(1.0f - max(FfxFloat16(0.0f), dot(normal, history_normal))) * FFX_DNSR_REFLECTIONS_DISOCCLUSION_NORMAL_WEIGHT) // + * exp(-abs(history_linear_depth - linear_depth) / linear_depth * FFX_DNSR_REFLECTIONS_DISOCCLUSION_DEPTH_WEIGHT)); + return factor; +} + +struct FFX_DNSR_Reflections_Moments { + FfxFloat16x3 mean; + FfxFloat16x3 variance; +}; + +FFX_DNSR_Reflections_Moments FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(FfxInt32x2 group_thread_id) { + FFX_DNSR_Reflections_Moments estimate; + estimate.mean = FfxFloat16x3(0.0f, 0.0f, 0.0f); + estimate.variance = FfxFloat16x3(0.0f, 0.0f, 0.0f); + FfxFloat16 accumulated_weight = FfxFloat16(0.0f); + for (FfxInt32 j = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; j <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++j) { + for (FfxInt32 i = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; i <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++i) { + FfxInt32x2 new_idx = group_thread_id + FfxInt32x2(i, j); + FfxFloat16x3 radiance = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(new_idx).radiance; + FfxFloat16 weight = FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat16(i)) * FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat16(j)); + accumulated_weight += weight; + estimate.mean += radiance * weight; + estimate.variance += radiance * radiance * weight; + } + } + estimate.mean /= accumulated_weight; + estimate.variance /= accumulated_weight; + + estimate.variance = abs(estimate.variance - estimate.mean * estimate.mean); + return estimate; +} + +FfxFloat32 dot2(FfxFloat32x3 a) { return dot(a, a); } + +void FFX_DNSR_Reflections_PickReprojection(FfxInt32x2 dispatch_thread_id, // + FfxInt32x2 group_thread_id, // + FfxUInt32x2 screen_size, // + FfxFloat16 roughness, // + FfxFloat16 ray_length, // + out FfxFloat16 disocclusion_factor, // + out FfxFloat32x2 reprojection_uv, // + out FfxFloat16x3 reprojection) { + + FFX_DNSR_Reflections_Moments local_neighborhood = FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(group_thread_id); + + FfxFloat32x2 uv = FfxFloat32x2(dispatch_thread_id.x + 0.5, dispatch_thread_id.y + 0.5) / screen_size; + FfxFloat16x3 normal = FFX_DNSR_Reflections_LoadWorldSpaceNormal(dispatch_thread_id); + FfxFloat16x3 history_normal; + FfxFloat32 history_linear_depth; + + { + const FfxFloat32x2 motion_vector = FFX_DNSR_Reflections_LoadMotionVector(dispatch_thread_id); + const FfxFloat32x2 surface_reprojection_uv = FFX_DNSR_Reflections_GetSurfaceReprojection(dispatch_thread_id, uv, motion_vector); + const FfxFloat32x2 hit_reprojection_uv = FFX_DNSR_Reflections_GetHitPositionReprojection(dispatch_thread_id, uv, ray_length); + const FfxFloat16x3 surface_normal = FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(surface_reprojection_uv); + const FfxFloat16x3 hit_normal = FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(hit_reprojection_uv); + const FfxFloat16x3 surface_history = FFX_DNSR_Reflections_SampleRadianceHistory(surface_reprojection_uv); + const FfxFloat16x3 hit_history = FFX_DNSR_Reflections_SampleRadianceHistory(hit_reprojection_uv); + const FfxFloat32 hit_normal_similarity = dot(normalize(FfxFloat32x3(hit_normal)), normalize(FfxFloat32x3(normal))); + const FfxFloat32 surface_normal_similarity = dot(normalize(FfxFloat32x3(surface_normal)), normalize(FfxFloat32x3(normal))); + const FfxFloat16 hit_roughness = FFX_DNSR_Reflections_SampleRoughnessHistory(hit_reprojection_uv); + const FfxFloat16 surface_roughness = FFX_DNSR_Reflections_SampleRoughnessHistory(surface_reprojection_uv); + + // Choose reprojection uv based on similarity to the local neighborhood. + if (hit_normal_similarity > FFX_DNSR_REFLECTIONS_REPROJECTION_NORMAL_SIMILARITY_THRESHOLD // Candidate for mirror reflection parallax + && hit_normal_similarity + 1.0e-3 > surface_normal_similarity // + && abs(hit_roughness - roughness) < abs(surface_roughness - roughness) + 1.0e-3 // + ) { + history_normal = hit_normal; + FfxFloat32 hit_history_depth = FFX_DNSR_Reflections_SampleDepthHistory(hit_reprojection_uv); + FfxFloat32 hit_history_linear_depth = FFX_DNSR_Reflections_GetLinearDepth(hit_reprojection_uv, hit_history_depth); + history_linear_depth = hit_history_linear_depth; + reprojection_uv = hit_reprojection_uv; + reprojection = hit_history; + } else { + // Reject surface reprojection based on simple distance + if (dot2(surface_history - local_neighborhood.mean) < + FFX_DNSR_REFLECTIONS_REPROJECT_SURFACE_DISCARD_VARIANCE_WEIGHT * length(local_neighborhood.variance)) { + history_normal = surface_normal; + FfxFloat32 surface_history_depth = FFX_DNSR_Reflections_SampleDepthHistory(surface_reprojection_uv); + FfxFloat32 surface_history_linear_depth = FFX_DNSR_Reflections_GetLinearDepth(surface_reprojection_uv, surface_history_depth); + history_linear_depth = surface_history_linear_depth; + reprojection_uv = surface_reprojection_uv; + reprojection = surface_history; + } else { + disocclusion_factor = FfxFloat16(0.0f); + return; + } + } + } + FfxFloat32 depth = FFX_DNSR_Reflections_LoadDepth(dispatch_thread_id); + FfxFloat32 linear_depth = FFX_DNSR_Reflections_GetLinearDepth(uv, depth); + // Determine disocclusion factor based on history + disocclusion_factor = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, history_normal, linear_depth, history_linear_depth); + + if (disocclusion_factor > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) // Early out, good enough + return; + + // Try to find the closest sample in the vicinity if we are not convinced of a disocclusion + if (disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) { + FfxFloat32x2 closest_uv = reprojection_uv; + FfxFloat32x2 dudv = 1.0 / FfxFloat32x2(screen_size); + const FfxInt32 search_radius = 1; + for (FfxInt32 y = -search_radius; y <= search_radius; y++) { + for (FfxInt32 x = -search_radius; x <= search_radius; x++) { + FfxFloat32x2 uv = reprojection_uv + FfxFloat32x2(x, y) * dudv; + FfxFloat16x3 history_normal = FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(uv); + FfxFloat32 history_depth = FFX_DNSR_Reflections_SampleDepthHistory(uv); + FfxFloat32 history_linear_depth = FFX_DNSR_Reflections_GetLinearDepth(uv, history_depth); + FfxFloat16 weight = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, history_normal, linear_depth, history_linear_depth); + if (weight > disocclusion_factor) { + disocclusion_factor = weight; + closest_uv = uv; + reprojection_uv = closest_uv; + } + } + } + reprojection = FFX_DNSR_Reflections_SampleRadianceHistory(reprojection_uv); + } + + // Rare slow path - triggered only on the edges. + // Try to get rid of potential leaks at bilinear interpolation level. + if (disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) { + // If we've got a discarded history, try to construct a better sample out of 2x2 interpolation neighborhood + // Helps quite a bit on the edges in movement + FfxFloat32 uvx = ffxFract(FfxFloat32(screen_size.x) * reprojection_uv.x + 0.5); + FfxFloat32 uvy = ffxFract(FfxFloat32(screen_size.y) * reprojection_uv.y + 0.5); + FfxInt32x2 reproject_texel_coords = FfxInt32x2(screen_size * reprojection_uv - 0.5); + FfxFloat16x3 reprojection00 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(0, 0)); + FfxFloat16x3 reprojection10 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(1, 0)); + FfxFloat16x3 reprojection01 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(0, 1)); + FfxFloat16x3 reprojection11 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(1, 1)); + FfxFloat16x3 normal00 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(0, 0)); + FfxFloat16x3 normal10 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(1, 0)); + FfxFloat16x3 normal01 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(0, 1)); + FfxFloat16x3 normal11 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(1, 1)); + FfxFloat32 depth00 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(0, 0))); + FfxFloat32 depth10 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(1, 0))); + FfxFloat32 depth01 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(0, 1))); + FfxFloat32 depth11 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(1, 1))); + FfxFloat16x4 w = FfxFloat16x4(1.0f, 1.0f, 1.0f, 1.0f); + // Initialize with occlusion weights + w.x = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal00, linear_depth, depth00) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat16(1.0f) : FfxFloat16(0.0f); + w.y = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal10, linear_depth, depth10) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat16(1.0f) : FfxFloat16(0.0f); + w.z = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal01, linear_depth, depth01) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat16(1.0f) : FfxFloat16(0.0f); + w.w = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal11, linear_depth, depth11) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat16(1.0f) : FfxFloat16(0.0f); + // And then mix in bilinear weights + w.x = FfxFloat16(w.x * (1.0 - uvx) * (1.0 - uvy)); + w.y = FfxFloat16(w.y * (uvx) * (1.0 - uvy)); + w.z = FfxFloat16(w.z * (1.0 - uvx) * (uvy)); + w.w = FfxFloat16(w.w * (uvx) * (uvy)); + FfxFloat16 ws = max(w.x + w.y + w.z + w.w, FfxFloat16(1.0e-3)); + // normalize + w /= ws; + + FfxFloat16x3 history_normal; + FfxFloat32 history_linear_depth; + reprojection = reprojection00 * w.x + reprojection10 * w.y + reprojection01 * w.z + reprojection11 * w.w; + history_linear_depth = depth00 * w.x + depth10 * w.y + depth01 * w.z + depth11 * w.w; + history_normal = normal00 * w.x + normal10 * w.y + normal01 * w.z + normal11 * w.w; + disocclusion_factor = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, history_normal, linear_depth, history_linear_depth); + } + disocclusion_factor = disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD ? FfxFloat16(0.0f) : disocclusion_factor; +} + +void FFX_DNSR_Reflections_Reproject(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxUInt32x2 screen_size, FfxFloat32 temporal_stability_factor, FfxInt32 max_samples) { + FFX_DNSR_Reflections_InitializeGroupSharedMemory(dispatch_thread_id, group_thread_id, FfxInt32x2(screen_size)); + FFX_GROUP_MEMORY_BARRIER; + + group_thread_id += 4; // Center threads in FFX_GROUPSHARED memory + + FfxFloat16 variance = FfxFloat16(1.0f); + FfxFloat16 num_samples = FfxFloat16(0.0f); + FfxFloat16 roughness = FFX_DNSR_Reflections_LoadRoughness(dispatch_thread_id); + FfxFloat32x3 normal = FFX_DNSR_Reflections_LoadWorldSpaceNormal(dispatch_thread_id); + FfxFloat16x3 radiance = FFX_DNSR_Reflections_LoadRadiance(dispatch_thread_id); + const FfxFloat16 ray_length = FFX_DNSR_Reflections_LoadRayLength(dispatch_thread_id); + + if (FFX_DNSR_Reflections_IsGlossyReflection(roughness)) { + FfxFloat16 disocclusion_factor; + FfxFloat32x2 reprojection_uv; + FfxFloat16x3 reprojection; + FFX_DNSR_Reflections_PickReprojection(/*in*/ dispatch_thread_id, + /* in */ group_thread_id, + /* in */ screen_size, + /* in */ roughness, + /* in */ ray_length, + /* out */ disocclusion_factor, + /* out */ reprojection_uv, + /* out */ reprojection); + if ( (reprojection_uv.x > 0.0f) && (reprojection_uv.y > 0.0f) && (reprojection_uv.x < 1.0f) && (reprojection_uv.y< 1.0f)) { + FfxFloat16 prev_variance = FFX_DNSR_Reflections_SampleVarianceHistory(reprojection_uv); + num_samples = FFX_DNSR_Reflections_SampleNumSamplesHistory(reprojection_uv) * disocclusion_factor; + FfxFloat16 s_max_samples = FfxFloat16(max(8.0f, FfxFloat16(max_samples) * FFX_DNSR_REFLECTIONS_SAMPLES_FOR_ROUGHNESS(roughness))); + num_samples = min(s_max_samples, num_samples + FfxFloat16(1.0f)); + FfxFloat16 new_variance = FFX_DNSR_Reflections_ComputeTemporalVariance(radiance.xyz, reprojection.xyz); + if (disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) { + FFX_DNSR_Reflections_StoreRadianceReprojected(dispatch_thread_id, FfxFloat16x3(0.0f, 0.0f, 0.0f)); + FFX_DNSR_Reflections_StoreVariance(dispatch_thread_id, FfxFloat16(1.0f)); + FFX_DNSR_Reflections_StoreNumSamples(dispatch_thread_id, FfxFloat16(1.0f)); + } else { + FfxFloat16 variance_mix = ffxLerp(new_variance, prev_variance, FfxFloat16(1.0f / num_samples)); + FFX_DNSR_Reflections_StoreRadianceReprojected(dispatch_thread_id, reprojection); + FFX_DNSR_Reflections_StoreVariance(dispatch_thread_id, variance_mix); + FFX_DNSR_Reflections_StoreNumSamples(dispatch_thread_id, num_samples); + // Mix in reprojection for radiance mip computation + radiance = ffxLerp(radiance, reprojection, FfxFloat16(0.3f)); + } + } else { + FFX_DNSR_Reflections_StoreRadianceReprojected(dispatch_thread_id, FfxFloat16x3(0.0f, 0.0f, 0.0f)); + FFX_DNSR_Reflections_StoreVariance(dispatch_thread_id, FfxFloat16(1.0f)); + FFX_DNSR_Reflections_StoreNumSamples(dispatch_thread_id, FfxFloat16(1.0f)); + } + } + + // Downsample 8x8 -> 1 radiance using FFX_GROUPSHARED memory + // Initialize FFX_GROUPSHARED array for downsampling + FfxFloat16 weight = FFX_DNSR_Reflections_GetLuminanceWeight(radiance.xyz); + radiance.xyz *= weight; + if ( (dispatch_thread_id.x >= screen_size.x) || (dispatch_thread_id.y >= screen_size.y) || any(isinf(radiance)) || any(isnan(radiance)) || (weight > FfxFloat16(1.0e3))) { + radiance = FfxFloat16x3(0.0f, 0.0f, 0.0f); + weight = FfxFloat16(0.0f); + } + + group_thread_id -= 4; // Center threads in FFX_GROUPSHARED memory + + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id, FfxFloat16x4(radiance.xyz, weight)); + FFX_GROUP_MEMORY_BARRIER; + + for (FfxInt32 i = 2; i <= 8; i = i * 2) { + FfxInt32 ox = group_thread_id.x * i; + FfxInt32 oy = group_thread_id.y * i; + FfxInt32 ix = group_thread_id.x * i + i / 2; + FfxInt32 iy = group_thread_id.y * i + i / 2; + if (ix < 8 && iy < 8) { + FfxFloat16x4 rad_weight00 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ox, oy)); + FfxFloat16x4 rad_weight10 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ox, iy)); + FfxFloat16x4 rad_weight01 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ix, oy)); + FfxFloat16x4 rad_weight11 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ix, iy)); + FfxFloat16x4 sum = rad_weight00 + rad_weight01 + rad_weight10 + rad_weight11; + FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2(ox, oy), sum); + } + FFX_GROUP_MEMORY_BARRIER; + } + + if ((group_thread_id.x == 0) && (group_thread_id.y == 0)) { + FfxFloat16x4 sum = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(0, 0)); + FfxFloat16 weight_acc = max(sum.w, FfxFloat16(1.0e-3)); + FfxFloat32x3 radiance_avg = sum.xyz / weight_acc; + FFX_DNSR_Reflections_StoreAverageRadiance(dispatch_thread_id.xy / 8, FfxFloat16x3(radiance_avg)); + } +} + +#else // #if FFX_HALF + +struct FFX_DNSR_Reflections_NeighborhoodSample { + FfxFloat32x3 radiance; +}; + +FFX_DNSR_Reflections_NeighborhoodSample FFX_DNSR_Reflections_LoadFromGroupSharedMemory(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + FfxFloat32x4 unpacked_radiance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance); + + FFX_DNSR_Reflections_NeighborhoodSample neighborSample; + neighborSample.radiance = unpacked_radiance.xyz; + return neighborSample; +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat32x3 radiance) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.zz); +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat32x4 radiance_variance) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance_variance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance_variance.zw); +} + +void FFX_DNSR_Reflections_InitializeGroupSharedMemory(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxInt32x2 screen_size) { + // Load 16x16 region into shared memory using 4 8x8 blocks. + FfxInt32x2 offset[4] = {FfxInt32x2(0, 0), FfxInt32x2(8, 0), FfxInt32x2(0, 8), FfxInt32x2(8, 8)}; + + // Intermediate storage registers to cache the result of all loads + FfxFloat32x3 radiance[4]; + + // Start in the upper left corner of the 16x16 region. + dispatch_thread_id -= 4; + + // First store all loads in registers + for (FfxInt32 i = 0; i < 4; ++i) { + radiance[i] = FFX_DNSR_Reflections_LoadRadiance(dispatch_thread_id + offset[i]); + } + + // Then move all registers to FFX_GROUPSHARED memory + for (FfxInt32 j = 0; j < 4; ++j) { + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id + offset[j], radiance[j]); // X + } +} + +FfxFloat32x4 FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + return FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance); +} + +FfxFloat32 FFX_DNSR_Reflections_GetLuminanceWeight(FfxFloat32x3 val) { + FfxFloat32 luma = FFX_DNSR_Reflections_Luminance(val.xyz); + FfxFloat32 weight = FfxFloat32(max(exp(-luma * FFX_DNSR_REFLECTIONS_AVG_RADIANCE_LUMINANCE_WEIGHT), 1.0e-2)); + return weight; +} + +FfxFloat32x2 FFX_DNSR_Reflections_GetSurfaceReprojection(FfxInt32x2 dispatch_thread_id, FfxFloat32x2 uv, FfxFloat32x2 motion_vector) { + // Reflector position reprojection + FfxFloat32x2 history_uv = uv + motion_vector; + return history_uv; +} + +FfxFloat32x2 FFX_DNSR_Reflections_GetHitPositionReprojection(FfxInt32x2 dispatch_thread_id, FfxFloat32x2 uv, FfxFloat32 reflected_ray_length) { + FfxFloat32 z = FFX_DNSR_Reflections_LoadDepth(dispatch_thread_id); + FfxFloat32x3 view_space_ray = FFX_DNSR_Reflections_ScreenSpaceToViewSpace(FfxFloat32x3(uv, z)); + + // We start out with reconstructing the ray length in view space. + // This includes the portion from the camera to the reflecting surface as well as the portion from the surface to the hit position. + FfxFloat32 surface_depth = length(view_space_ray); + FfxFloat32 ray_length = surface_depth + reflected_ray_length; + + // We then perform a parallax correction by shooting a ray + // of the same length "straight through" the reflecting surface + // and reprojecting the tip of that ray to the previous frame. + view_space_ray /= surface_depth; // == normalize(view_space_ray) + view_space_ray *= ray_length; + FfxFloat32x3 world_hit_position = + FFX_DNSR_Reflections_ViewSpaceToWorldSpace(FfxFloat32x4(view_space_ray, 1)); // This is the "fake" hit position if we would follow the ray straight through the surface. + FfxFloat32x3 prev_hit_position = FFX_DNSR_Reflections_WorldSpaceToScreenSpacePrevious(world_hit_position); + FfxFloat32x2 history_uv = prev_hit_position.xy; + return history_uv; +} + +FfxFloat32 FFX_DNSR_Reflections_GetDisocclusionFactor(FfxFloat32x3 normal, FfxFloat32x3 history_normal, FfxFloat32 linear_depth, FfxFloat32 history_linear_depth) { + FfxFloat32 factor = FfxFloat32(1.0f // + * exp(-abs(1.0f - max(FfxFloat32(0.0f), dot(normal, history_normal))) * FFX_DNSR_REFLECTIONS_DISOCCLUSION_NORMAL_WEIGHT) // + * exp(-abs(history_linear_depth - linear_depth) / linear_depth * FFX_DNSR_REFLECTIONS_DISOCCLUSION_DEPTH_WEIGHT)); + return factor; +} + +struct FFX_DNSR_Reflections_Moments { + FfxFloat32x3 mean; + FfxFloat32x3 variance; +}; + +FFX_DNSR_Reflections_Moments FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(FfxInt32x2 group_thread_id) { + FFX_DNSR_Reflections_Moments estimate; + estimate.mean = FfxFloat32x3(0.0f, 0.0f, 0.0f); + estimate.variance = FfxFloat32x3(0.0f, 0.0f, 0.0f); + FfxFloat32 accumulated_weight = FfxFloat32(0.0f); + for (FfxInt32 j = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; j <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++j) { + for (FfxInt32 i = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; i <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++i) { + FfxInt32x2 new_idx = group_thread_id + FfxInt32x2(i, j); + FfxFloat32x3 radiance = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(new_idx).radiance; + FfxFloat32 weight = FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat32(i)) * FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat32(j)); + accumulated_weight += weight; + estimate.mean += radiance * weight; + estimate.variance += radiance * radiance * weight; + } + } + estimate.mean /= accumulated_weight; + estimate.variance /= accumulated_weight; + + estimate.variance = abs(estimate.variance - estimate.mean * estimate.mean); + return estimate; +} + +FfxFloat32 dot2(FfxFloat32x3 a) { return dot(a, a); } + +void FFX_DNSR_Reflections_PickReprojection(FfxInt32x2 dispatch_thread_id, // + FfxInt32x2 group_thread_id, // + FfxUInt32x2 screen_size, // + FfxFloat32 roughness, // + FfxFloat32 ray_length, // + out FfxFloat32 disocclusion_factor, // + out FfxFloat32x2 reprojection_uv, // + out FfxFloat32x3 reprojection) { + + FFX_DNSR_Reflections_Moments local_neighborhood = FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(group_thread_id); + + FfxFloat32x2 uv = FfxFloat32x2(dispatch_thread_id.x + 0.5, dispatch_thread_id.y + 0.5) / screen_size; + FfxFloat32x3 normal = FFX_DNSR_Reflections_LoadWorldSpaceNormal(dispatch_thread_id); + FfxFloat32x3 history_normal; + FfxFloat32 history_linear_depth; + + { + const FfxFloat32x2 motion_vector = FFX_DNSR_Reflections_LoadMotionVector(dispatch_thread_id); + const FfxFloat32x2 surface_reprojection_uv = FFX_DNSR_Reflections_GetSurfaceReprojection(dispatch_thread_id, uv, motion_vector); + const FfxFloat32x2 hit_reprojection_uv = FFX_DNSR_Reflections_GetHitPositionReprojection(dispatch_thread_id, uv, ray_length); + const FfxFloat32x3 surface_normal = FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(surface_reprojection_uv); + const FfxFloat32x3 hit_normal = FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(hit_reprojection_uv); + const FfxFloat32x3 surface_history = FFX_DNSR_Reflections_SampleRadianceHistory(surface_reprojection_uv); + const FfxFloat32x3 hit_history = FFX_DNSR_Reflections_SampleRadianceHistory(hit_reprojection_uv); + const FfxFloat32 hit_normal_similarity = dot(normalize(FfxFloat32x3(hit_normal)), normalize(FfxFloat32x3(normal))); + const FfxFloat32 surface_normal_similarity = dot(normalize(FfxFloat32x3(surface_normal)), normalize(FfxFloat32x3(normal))); + const FfxFloat32 hit_roughness = FFX_DNSR_Reflections_SampleRoughnessHistory(hit_reprojection_uv); + const FfxFloat32 surface_roughness = FFX_DNSR_Reflections_SampleRoughnessHistory(surface_reprojection_uv); + + // Choose reprojection uv based on similarity to the local neighborhood. + if (hit_normal_similarity > FFX_DNSR_REFLECTIONS_REPROJECTION_NORMAL_SIMILARITY_THRESHOLD // Candidate for mirror reflection parallax + && hit_normal_similarity + 1.0e-3 > surface_normal_similarity // + && abs(hit_roughness - roughness) < abs(surface_roughness - roughness) + 1.0e-3 // + ) { + history_normal = hit_normal; + FfxFloat32 hit_history_depth = FFX_DNSR_Reflections_SampleDepthHistory(hit_reprojection_uv); + FfxFloat32 hit_history_linear_depth = FFX_DNSR_Reflections_GetLinearDepth(hit_reprojection_uv, hit_history_depth); + history_linear_depth = hit_history_linear_depth; + reprojection_uv = hit_reprojection_uv; + reprojection = hit_history; + } else { + // Reject surface reprojection based on simple distance + if (dot2(surface_history - local_neighborhood.mean) < + FFX_DNSR_REFLECTIONS_REPROJECT_SURFACE_DISCARD_VARIANCE_WEIGHT * length(local_neighborhood.variance)) { + history_normal = surface_normal; + FfxFloat32 surface_history_depth = FFX_DNSR_Reflections_SampleDepthHistory(surface_reprojection_uv); + FfxFloat32 surface_history_linear_depth = FFX_DNSR_Reflections_GetLinearDepth(surface_reprojection_uv, surface_history_depth); + history_linear_depth = surface_history_linear_depth; + reprojection_uv = surface_reprojection_uv; + reprojection = surface_history; + } else { + disocclusion_factor = FfxFloat32(0.0f); + return; + } + } + } + FfxFloat32 depth = FFX_DNSR_Reflections_LoadDepth(dispatch_thread_id); + FfxFloat32 linear_depth = FFX_DNSR_Reflections_GetLinearDepth(uv, depth); + // Determine disocclusion factor based on history + disocclusion_factor = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, history_normal, linear_depth, history_linear_depth); + + if (disocclusion_factor > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) // Early out, good enough + return; + + // Try to find the closest sample in the vicinity if we are not convinced of a disocclusion + if (disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) { + FfxFloat32x2 closest_uv = reprojection_uv; + FfxFloat32x2 dudv = 1.0 / FfxFloat32x2(screen_size); + const FfxInt32 search_radius = 1; + for (FfxInt32 y = -search_radius; y <= search_radius; y++) { + for (FfxInt32 x = -search_radius; x <= search_radius; x++) { + FfxFloat32x2 uv = reprojection_uv + FfxFloat32x2(x, y) * dudv; + FfxFloat32x3 history_normal = FFX_DNSR_Reflections_SampleWorldSpaceNormalHistory(uv); + FfxFloat32 history_depth = FFX_DNSR_Reflections_SampleDepthHistory(uv); + FfxFloat32 history_linear_depth = FFX_DNSR_Reflections_GetLinearDepth(uv, history_depth); + FfxFloat32 weight = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, history_normal, linear_depth, history_linear_depth); + if (weight > disocclusion_factor) { + disocclusion_factor = weight; + closest_uv = uv; + reprojection_uv = closest_uv; + } + } + } + reprojection = FFX_DNSR_Reflections_SampleRadianceHistory(reprojection_uv); + } + + // Rare slow path - triggered only on the edges. + // Try to get rid of potential leaks at bilinear interpolation level. + if (disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) { + // If we've got a discarded history, try to construct a better sample out of 2x2 interpolation neighborhood + // Helps quite a bit on the edges in movement + FfxFloat32 uvx = ffxFract(FfxFloat32(screen_size.x) * reprojection_uv.x + 0.5); + FfxFloat32 uvy = ffxFract(FfxFloat32(screen_size.y) * reprojection_uv.y + 0.5); + FfxInt32x2 reproject_texel_coords = FfxInt32x2(screen_size * reprojection_uv - 0.5); + FfxFloat32x3 reprojection00 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(0, 0)); + FfxFloat32x3 reprojection10 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(1, 0)); + FfxFloat32x3 reprojection01 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(0, 1)); + FfxFloat32x3 reprojection11 = FFX_DNSR_Reflections_LoadRadianceHistory(reproject_texel_coords + FfxInt32x2(1, 1)); + FfxFloat32x3 normal00 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(0, 0)); + FfxFloat32x3 normal10 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(1, 0)); + FfxFloat32x3 normal01 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(0, 1)); + FfxFloat32x3 normal11 = FFX_DNSR_Reflections_LoadWorldSpaceNormalHistory(reproject_texel_coords + FfxInt32x2(1, 1)); + FfxFloat32 depth00 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(0, 0))); + FfxFloat32 depth10 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(1, 0))); + FfxFloat32 depth01 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(0, 1))); + FfxFloat32 depth11 = FFX_DNSR_Reflections_GetLinearDepth(reprojection_uv, FFX_DNSR_Reflections_LoadDepthHistory(reproject_texel_coords + FfxInt32x2(1, 1))); + FfxFloat32x4 w = FfxFloat32x4(1.0f, 1.0f, 1.0f, 1.0f); + // Initialize with occlusion weights + w.x = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal00, linear_depth, depth00) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat32(1.0f) : FfxFloat32(0.0f); + w.y = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal10, linear_depth, depth10) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat32(1.0f) : FfxFloat32(0.0f); + w.z = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal01, linear_depth, depth01) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat32(1.0f) : FfxFloat32(0.0f); + w.w = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, normal11, linear_depth, depth11) > FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD / 2.0f ? FfxFloat32(1.0f) : FfxFloat32(0.0f); + // And then mix in bilinear weights + w.x = FfxFloat32(w.x * (1.0 - uvx) * (1.0 - uvy)); + w.y = FfxFloat32(w.y * (uvx) * (1.0 - uvy)); + w.z = FfxFloat32(w.z * (1.0 - uvx) * (uvy)); + w.w = FfxFloat32(w.w * (uvx) * (uvy)); + FfxFloat32 ws = max(w.x + w.y + w.z + w.w, FfxFloat32(1.0e-3)); + // normalize + w /= ws; + + FfxFloat32x3 history_normal; + FfxFloat32 history_linear_depth; + reprojection = reprojection00 * w.x + reprojection10 * w.y + reprojection01 * w.z + reprojection11 * w.w; + history_linear_depth = depth00 * w.x + depth10 * w.y + depth01 * w.z + depth11 * w.w; + history_normal = normal00 * w.x + normal10 * w.y + normal01 * w.z + normal11 * w.w; + disocclusion_factor = FFX_DNSR_Reflections_GetDisocclusionFactor(normal, history_normal, linear_depth, history_linear_depth); + } + disocclusion_factor = disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD ? FfxFloat32(0.0f) : disocclusion_factor; +} + +void FFX_DNSR_Reflections_Reproject(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxUInt32x2 screen_size, FfxFloat32 temporal_stability_factor, FfxInt32 max_samples) { + FFX_DNSR_Reflections_InitializeGroupSharedMemory(dispatch_thread_id, group_thread_id, FfxInt32x2(screen_size)); + FFX_GROUP_MEMORY_BARRIER; + + group_thread_id += 4; // Center threads in FFX_GROUPSHARED memory + + FfxFloat32 variance = FfxFloat32(1.0f); + FfxFloat32 num_samples = FfxFloat32(0.0f); + FfxFloat32 roughness = FFX_DNSR_Reflections_LoadRoughness(dispatch_thread_id); + FfxFloat32x3 normal = FFX_DNSR_Reflections_LoadWorldSpaceNormal(dispatch_thread_id); + FfxFloat32x3 radiance = FFX_DNSR_Reflections_LoadRadiance(dispatch_thread_id); + const FfxFloat32 ray_length = FFX_DNSR_Reflections_LoadRayLength(dispatch_thread_id); + + if (FFX_DNSR_Reflections_IsGlossyReflection(roughness)) { + FfxFloat32 disocclusion_factor; + FfxFloat32x2 reprojection_uv; + FfxFloat32x3 reprojection; + FFX_DNSR_Reflections_PickReprojection(/*in*/ dispatch_thread_id, + /* in */ group_thread_id, + /* in */ screen_size, + /* in */ roughness, + /* in */ ray_length, + /* out */ disocclusion_factor, + /* out */ reprojection_uv, + /* out */ reprojection); + if ( (reprojection_uv.x > 0.0f) && (reprojection_uv.y > 0.0f) && (reprojection_uv.x < 1.0f) && (reprojection_uv.y< 1.0f)) { + FfxFloat32 prev_variance = FFX_DNSR_Reflections_SampleVarianceHistory(reprojection_uv); + num_samples = FFX_DNSR_Reflections_SampleNumSamplesHistory(reprojection_uv) * disocclusion_factor; + FfxFloat32 s_max_samples = FfxFloat32(max(8.0f, max_samples * FFX_DNSR_REFLECTIONS_SAMPLES_FOR_ROUGHNESS(roughness))); + num_samples = min(s_max_samples, num_samples + FfxFloat32(1.0f)); + FfxFloat32 new_variance = FFX_DNSR_Reflections_ComputeTemporalVariance(radiance.xyz, reprojection.xyz); + if (disocclusion_factor < FFX_DNSR_REFLECTIONS_DISOCCLUSION_THRESHOLD) { + FFX_DNSR_Reflections_StoreRadianceReprojected(dispatch_thread_id, FfxFloat32x3(0.0f, 0.0f, 0.0f)); + FFX_DNSR_Reflections_StoreVariance(dispatch_thread_id, FfxFloat32(1.0f)); + FFX_DNSR_Reflections_StoreNumSamples(dispatch_thread_id, FfxFloat32(1.0f)); + } else { + FfxFloat32 variance_mix = ffxLerp(new_variance, prev_variance, FfxFloat32(1.0f / num_samples)); + FFX_DNSR_Reflections_StoreRadianceReprojected(dispatch_thread_id, reprojection); + FFX_DNSR_Reflections_StoreVariance(dispatch_thread_id, variance_mix); + FFX_DNSR_Reflections_StoreNumSamples(dispatch_thread_id, num_samples); + // Mix in reprojection for radiance mip computation + radiance = ffxLerp(radiance, reprojection, FfxFloat32(0.3f)); + } + } else { + FFX_DNSR_Reflections_StoreRadianceReprojected(dispatch_thread_id, FfxFloat32x3(0.0f, 0.0f, 0.0f)); + FFX_DNSR_Reflections_StoreVariance(dispatch_thread_id, FfxFloat32(1.0f)); + FFX_DNSR_Reflections_StoreNumSamples(dispatch_thread_id, FfxFloat32(1.0f)); + } + } + + // Downsample 8x8 -> 1 radiance using FFX_GROUPSHARED memory + // Initialize FFX_GROUPSHARED array for downsampling + FfxFloat32 weight = FFX_DNSR_Reflections_GetLuminanceWeight(radiance.xyz); + radiance.xyz *= weight; + if ( (dispatch_thread_id.x >= screen_size.x) || (dispatch_thread_id.y >= screen_size.y) || any(isinf(radiance)) || any(isnan(radiance)) || (weight > FfxFloat32(1.0e3))) { + radiance = FfxFloat32x3(0.0f, 0.0f, 0.0f); + weight = FfxFloat32(0.0f); + } + + group_thread_id -= 4; // Center threads in FFX_GROUPSHARED memory + + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id, FfxFloat32x4(radiance.xyz, weight)); + FFX_GROUP_MEMORY_BARRIER; + + for (FfxInt32 i = 2; i <= 8; i = i * 2) { + FfxInt32 ox = group_thread_id.x * i; + FfxInt32 oy = group_thread_id.y * i; + FfxInt32 ix = group_thread_id.x * i + i / 2; + FfxInt32 iy = group_thread_id.y * i + i / 2; + if (ix < 8 && iy < 8) { + FfxFloat32x4 rad_weight00 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ox, oy)); + FfxFloat32x4 rad_weight10 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ox, iy)); + FfxFloat32x4 rad_weight01 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ix, oy)); + FfxFloat32x4 rad_weight11 = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(ix, iy)); + FfxFloat32x4 sum = rad_weight00 + rad_weight01 + rad_weight10 + rad_weight11; + FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2(ox, oy), sum); + } + FFX_GROUP_MEMORY_BARRIER; + } + + if ((group_thread_id.x == 0) && (group_thread_id.y == 0)) { + FfxFloat32x4 sum = FFX_DNSR_Reflections_LoadFromGroupSharedMemoryRaw(FfxInt32x2(0, 0)); + FfxFloat32 weight_acc = max(sum.w, FfxFloat32(1.0e-3)); + FfxFloat32x3 radiance_avg = sum.xyz / weight_acc; + FFX_DNSR_Reflections_StoreAverageRadiance(dispatch_thread_id.xy / 8, FfxFloat32x3(radiance_avg)); + } +} + +#endif // #if FFX_HALF + +void Reproject(FfxUInt32 group_index, FfxUInt32 group_id, FfxUInt32x2 group_thread_id) { + FfxUInt32 packed_coords = GetDenoiserTile(group_id); + FfxInt32x2 dispatch_thread_id = FfxInt32x2(packed_coords & 0xffffu, (packed_coords >> 16) & 0xffffu) + FfxInt32x2(group_thread_id); + FfxInt32x2 dispatch_group_id = dispatch_thread_id / 8; + FfxInt32x2 remapped_group_thread_id = FfxInt32x2(ffxRemapForWaveReduction(group_index)); + FfxInt32x2 remapped_dispatch_thread_id = dispatch_group_id * 8 + remapped_group_thread_id; + + FFX_DNSR_Reflections_Reproject(remapped_dispatch_thread_id, remapped_group_thread_id, RenderSize(), TemporalStabilityFactor(), 32); +} + +#endif // FFX_DNSR_REFLECTIONS_REPROJECT diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_resolve_temporal.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_resolve_temporal.h new file mode 100644 index 00000000..bb584254 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_reflections_resolve_temporal.h @@ -0,0 +1,298 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_REFLECTIONS_RESOLVE_TEMPORAL +#define FFX_DNSR_REFLECTIONS_RESOLVE_TEMPORAL + +#define RADIANCE_THRESHOLD 0.0001 + +#define FFX_DNSR_REFLECTIONS_ESTIMATES_LOCAL_NEIGHBORHOOD +#include "ffx_denoiser_reflections_common.h" + +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_0[16][16]; +FFX_GROUPSHARED FfxUInt32 g_ffx_dnsr_shared_1[16][16]; + +#if FFX_HALF + +struct FFX_DNSR_Reflections_NeighborhoodSample { + FfxFloat16x3 radiance; +}; + +FFX_DNSR_Reflections_NeighborhoodSample FFX_DNSR_Reflections_LoadFromGroupSharedMemory(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + FfxFloat16x3 unpacked_radiance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance).xyz; + + FFX_DNSR_Reflections_NeighborhoodSample neighborSample; + neighborSample.radiance = unpacked_radiance; + return neighborSample; +} + +struct FFX_DNSR_Reflections_Moments { + FfxFloat16x3 mean; + FfxFloat16x3 variance; +}; + +FFX_DNSR_Reflections_Moments FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(FfxInt32x2 group_thread_id) { + FFX_DNSR_Reflections_Moments estimate; + estimate.mean = FfxFloat16x3(0.0f, 0.0f, 0.0f); + estimate.variance = FfxFloat16x3(0.0f, 0.0f, 0.0f); + FfxFloat16 accumulated_weight = FfxFloat16(0.0f); + for (FfxInt32 j = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; j <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++j) { + for (FfxInt32 i = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; i <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++i) { + FfxInt32x2 new_idx = group_thread_id + FfxInt32x2(i, j); + FfxFloat16x3 radiance = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(new_idx).radiance; + FfxFloat16 weight = FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat16(i)) * FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat16(j)); + accumulated_weight += weight; + estimate.mean += radiance * weight; + estimate.variance += radiance * radiance * weight; + } + } + estimate.mean /= accumulated_weight; + estimate.variance /= accumulated_weight; + + estimate.variance = abs(estimate.variance - estimate.mean * estimate.mean); + return estimate; +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat16x3 radiance) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.zz); +} + +void FFX_DNSR_Reflections_LoadNeighborhood(FfxInt32x2 pixel_coordinate, out FfxFloat16x3 radiance) { radiance = FFX_DNSR_Reflections_LoadRadiance(pixel_coordinate); } + +void FFX_DNSR_Reflections_InitializeGroupSharedMemory(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxInt32x2 screen_size) { + // Load 16x16 region into shared memory using 4 8x8 blocks. + FfxInt32x2 offset[4] = {FfxInt32x2(0, 0), FfxInt32x2(8, 0), FfxInt32x2(0, 8), FfxInt32x2(8, 8)}; + + // Intermediate storage registers to cache the result of all loads + FfxFloat16x3 radiance[4]; + + // Start in the upper left corner of the 16x16 region. + dispatch_thread_id -= 4; + + // First store all loads in registers + for (FfxInt32 i = 0; i < 4; ++i) { + FFX_DNSR_Reflections_LoadNeighborhood(dispatch_thread_id + offset[i], radiance[i]); + } + + // Then move all registers to FFX_GROUPSHARED memory + for (FfxInt32 j = 0; j < 4; ++j) { + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id + offset[j], radiance[j]); + } +} + +void FFX_DNSR_Reflections_ResolveTemporal(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxUInt32x2 screen_size, FfxFloat32x2 inv_screen_size, FfxFloat32 history_clip_weight) { + FFX_DNSR_Reflections_InitializeGroupSharedMemory(dispatch_thread_id, group_thread_id, FfxInt32x2(screen_size)); + FFX_GROUP_MEMORY_BARRIER; + + group_thread_id += 4; // Center threads in FFX_GROUPSHARED memory + + FfxFloat16x3 radiance = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(group_thread_id).radiance; + FfxFloat32 radianceSum = radiance.x + radiance.y + radiance.z; + if (radianceSum < RADIANCE_THRESHOLD) + { + FFX_DNSR_Reflections_StoreTemporalAccumulation(dispatch_thread_id, FfxFloat16x3(0.0f, 0.0f, 0.0f), FfxFloat16(0.0f)); + return; + } + + FFX_DNSR_Reflections_NeighborhoodSample center = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(group_thread_id); + FfxFloat16x3 new_signal = center.radiance; + FfxFloat16 roughness = FFX_DNSR_Reflections_LoadRoughness(dispatch_thread_id); + FfxFloat16 new_variance = FFX_DNSR_Reflections_LoadVariance(dispatch_thread_id); + + if (FFX_DNSR_Reflections_IsGlossyReflection(roughness)) { + FfxFloat16 num_samples = FFX_DNSR_Reflections_LoadNumSamples(dispatch_thread_id); + FfxFloat32x2 uv8 = (FfxFloat32x2(dispatch_thread_id.xy) + (0.5).xx) / FFX_DNSR_Reflections_RoundUp8(screen_size); + FfxFloat16x3 avg_radiance = FFX_DNSR_Reflections_SampleAverageRadiance(uv8); + + FfxFloat16x3 old_signal = FFX_DNSR_Reflections_LoadRadianceReprojected(dispatch_thread_id); + FFX_DNSR_Reflections_Moments local_neighborhood = FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(group_thread_id); + // Clip history based on the curren local statistics + FfxFloat16x3 color_std = FfxFloat16x3((sqrt(local_neighborhood.variance.xyz) + length(local_neighborhood.mean.xyz - avg_radiance)) * history_clip_weight * 1.4f); + local_neighborhood.mean.xyz = ffxLerp(local_neighborhood.mean.xyz, avg_radiance, FfxFloat16x3(0.2f, 0.2f, 0.2f)); + FfxFloat16x3 radiance_min = local_neighborhood.mean.xyz - color_std; + FfxFloat16x3 radiance_max = local_neighborhood.mean.xyz + color_std; + FfxFloat16x3 clipped_old_signal = FFX_DNSR_Reflections_ClipAABB(radiance_min, radiance_max, old_signal.xyz); + FfxFloat16 accumulation_speed = FfxFloat16(1.0f) / max(num_samples, FfxFloat16(1.0f)); + FfxFloat16 weight = (FfxFloat16(1.0f) - accumulation_speed); + // Blend with average for small sample count + new_signal.xyz = ffxLerp(new_signal.xyz, avg_radiance, FfxFloat16(1.0f) / max(num_samples + FfxFloat16(1.0f), FfxFloat16(1.0f))); + // Clip outliers + { + FfxFloat16x3 radiance_min = avg_radiance.xyz - color_std * FfxFloat16x3(1.0f, 1.0f, 1.0f); + FfxFloat16x3 radiance_max = avg_radiance.xyz + color_std * FfxFloat16x3(1.0f, 1.0f, 1.0f); + new_signal.xyz = FFX_DNSR_Reflections_ClipAABB(radiance_min, radiance_max, new_signal.xyz); + } + // Blend with history +#ifdef FFX_GLSL + new_signal = (FfxFloat16(1.0) - weight) * new_signal + weight * clipped_old_signal; +#else + new_signal = ffxLerp(new_signal, clipped_old_signal, weight); +#endif + new_variance = ffxLerp(FFX_DNSR_Reflections_ComputeTemporalVariance(new_signal.xyz, clipped_old_signal.xyz), new_variance, weight); + if (any(isinf(new_signal)) || any(isnan(new_signal)) || isinf(new_variance) || isnan(new_variance)) { + new_signal = FfxFloat16x3(0.0f, 0.0f, 0.0f); + new_variance = FfxFloat16(0.0f); + } + + } + FFX_DNSR_Reflections_StoreTemporalAccumulation(dispatch_thread_id, new_signal, new_variance); +} + +#else // #if FFX_HALF + +struct FFX_DNSR_Reflections_NeighborhoodSample { + FfxFloat32x3 radiance; +}; + +FFX_DNSR_Reflections_NeighborhoodSample FFX_DNSR_Reflections_LoadFromGroupSharedMemory(FfxInt32x2 idx) { + FfxUInt32x2 packed_radiance = FfxUInt32x2(g_ffx_dnsr_shared_0[idx.y][idx.x], g_ffx_dnsr_shared_1[idx.y][idx.x]); + FfxFloat32x3 unpacked_radiance = FFX_DNSR_Reflections_UnpackFloat16_4(packed_radiance).xyz; + + FFX_DNSR_Reflections_NeighborhoodSample neighborSample; + neighborSample.radiance = unpacked_radiance; + return neighborSample; +} + +struct FFX_DNSR_Reflections_Moments { + FfxFloat32x3 mean; + FfxFloat32x3 variance; +}; + +FFX_DNSR_Reflections_Moments FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(FfxInt32x2 group_thread_id) { + FFX_DNSR_Reflections_Moments estimate; + estimate.mean = FfxFloat32x3(0.0f, 0.0f, 0.0f); + estimate.variance = FfxFloat32x3(0.0f, 0.0f, 0.0f); + FfxFloat32 accumulated_weight = FfxFloat32(0.0f); + for (FfxInt32 j = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; j <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++j) { + for (FfxInt32 i = -FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; i <= FFX_DNSR_REFLECTIONS_LOCAL_NEIGHBORHOOD_RADIUS; ++i) { + FfxInt32x2 new_idx = group_thread_id + FfxInt32x2(i, j); + FfxFloat32x3 radiance = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(new_idx).radiance; + FfxFloat32 weight = FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat32(i)) * FFX_DNSR_Reflections_LocalNeighborhoodKernelWeight(FfxFloat32(j)); + accumulated_weight += weight; + estimate.mean += radiance * weight; + estimate.variance += radiance * radiance * weight; + } + } + estimate.mean /= accumulated_weight; + estimate.variance /= accumulated_weight; + + estimate.variance = abs(estimate.variance - estimate.mean * estimate.mean); + return estimate; +} + +void FFX_DNSR_Reflections_StoreInGroupSharedMemory(FfxInt32x2 group_thread_id, FfxFloat32x3 radiance) { + g_ffx_dnsr_shared_0[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.xy); + g_ffx_dnsr_shared_1[group_thread_id.y][group_thread_id.x] = FFX_DNSR_Reflections_PackFloat16(radiance.zz); +} + +void FFX_DNSR_Reflections_LoadNeighborhood(FfxInt32x2 pixel_coordinate, out FfxFloat32x3 radiance) { radiance = FFX_DNSR_Reflections_LoadRadiance(pixel_coordinate); } + +void FFX_DNSR_Reflections_InitializeGroupSharedMemory(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxInt32x2 screen_size) { + // Load 16x16 region into shared memory using 4 8x8 blocks. + FfxInt32x2 offset[4] = {FfxInt32x2(0, 0), FfxInt32x2(8, 0), FfxInt32x2(0, 8), FfxInt32x2(8, 8)}; + + // Intermediate storage registers to cache the result of all loads + FfxFloat32x3 radiance[4]; + + // Start in the upper left corner of the 16x16 region. + dispatch_thread_id -= 4; + + // First store all loads in registers + for (FfxInt32 i = 0; i < 4; ++i) { + FFX_DNSR_Reflections_LoadNeighborhood(dispatch_thread_id + offset[i], radiance[i]); + } + + // Then move all registers to FFX_GROUPSHARED memory + for (FfxInt32 j = 0; j < 4; ++j) { + FFX_DNSR_Reflections_StoreInGroupSharedMemory(group_thread_id + offset[j], radiance[j]); + } +} + +void FFX_DNSR_Reflections_ResolveTemporal(FfxInt32x2 dispatch_thread_id, FfxInt32x2 group_thread_id, FfxUInt32x2 screen_size, FfxFloat32x2 inv_screen_size, FfxFloat32 history_clip_weight) { + FFX_DNSR_Reflections_InitializeGroupSharedMemory(dispatch_thread_id, group_thread_id, FfxInt32x2(screen_size)); + FFX_GROUP_MEMORY_BARRIER; + + group_thread_id += 4; // Center threads in FFX_GROUPSHARED memory + + FfxFloat32x3 radiance = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(group_thread_id).radiance; + FfxFloat32 radianceSum = radiance.x + radiance.y + radiance.z; + if (radianceSum < RADIANCE_THRESHOLD) + { + FFX_DNSR_Reflections_StoreTemporalAccumulation(dispatch_thread_id, FfxFloat32x3(0.0f, 0.0f, 0.0f), FfxFloat32(0.0f)); + return; + } + + FFX_DNSR_Reflections_NeighborhoodSample center = FFX_DNSR_Reflections_LoadFromGroupSharedMemory(group_thread_id); + FfxFloat32x3 new_signal = center.radiance; + FfxFloat32 roughness = FFX_DNSR_Reflections_LoadRoughness(dispatch_thread_id); + FfxFloat32 new_variance = FFX_DNSR_Reflections_LoadVariance(dispatch_thread_id); + + if (FFX_DNSR_Reflections_IsGlossyReflection(roughness)) { + FfxFloat32 num_samples = FFX_DNSR_Reflections_LoadNumSamples(dispatch_thread_id); + FfxFloat32x2 uv8 = (FfxFloat32x2(dispatch_thread_id.xy) + (0.5).xx) / FFX_DNSR_Reflections_RoundUp8(screen_size); + FfxFloat32x3 avg_radiance = FFX_DNSR_Reflections_SampleAverageRadiance(uv8); + + FfxFloat32x3 old_signal = FFX_DNSR_Reflections_LoadRadianceReprojected(dispatch_thread_id); + FFX_DNSR_Reflections_Moments local_neighborhood = FFX_DNSR_Reflections_EstimateLocalNeighborhoodInGroup(group_thread_id); + // Clip history based on the curren local statistics + FfxFloat32x3 color_std = FfxFloat32x3((sqrt(local_neighborhood.variance.xyz) + length(local_neighborhood.mean.xyz - avg_radiance)) * history_clip_weight * 1.4f); + local_neighborhood.mean.xyz = ffxLerp(local_neighborhood.mean.xyz, avg_radiance, FfxFloat32x3(0.2f, 0.2f, 0.2f)); + FfxFloat32x3 radiance_min = local_neighborhood.mean.xyz - color_std; + FfxFloat32x3 radiance_max = local_neighborhood.mean.xyz + color_std; + FfxFloat32x3 clipped_old_signal = FFX_DNSR_Reflections_ClipAABB(radiance_min, radiance_max, old_signal.xyz); + FfxFloat32 accumulation_speed = FfxFloat32(1.0f) / max(num_samples, FfxFloat32(1.0f)); + FfxFloat32 weight = (FfxFloat32(1.0f) - accumulation_speed); + // Blend with average for small sample count + new_signal.xyz = ffxLerp(new_signal.xyz, avg_radiance, FfxFloat32(1.0f) / max(num_samples + FfxFloat32(1.0f), FfxFloat32(1.0f))); + // Clip outliers + { + FfxFloat32x3 radiance_min = avg_radiance.xyz - color_std * FfxFloat32x3(1.0f, 1.0f, 1.0f); + FfxFloat32x3 radiance_max = avg_radiance.xyz + color_std * FfxFloat32x3(1.0f, 1.0f, 1.0f); + new_signal.xyz = FFX_DNSR_Reflections_ClipAABB(radiance_min, radiance_max, new_signal.xyz); + } + // Blend with history + new_signal = ffxLerp(new_signal, clipped_old_signal, weight); + new_variance = ffxLerp(FFX_DNSR_Reflections_ComputeTemporalVariance(new_signal.xyz, clipped_old_signal.xyz), new_variance, weight); + if (any(isinf(new_signal)) || any(isnan(new_signal)) || isinf(new_variance) || isnan(new_variance)) { + new_signal = FfxFloat32x3(0.0f, 0.0f, 0.0f); + new_variance = FfxFloat32(0.0f); + } + + } + FFX_DNSR_Reflections_StoreTemporalAccumulation(dispatch_thread_id, new_signal, new_variance); +} + +#endif // #if FFX_HALF + +void ResolveTemporal(FfxUInt32 group_index, FfxUInt32 group_id, FfxUInt32x2 group_thread_id) { + FfxUInt32 packed_coords = GetDenoiserTile(group_id); + FfxInt32x2 dispatch_thread_id = FfxInt32x2(packed_coords & 0xffffu, (packed_coords >> 16) & 0xffffu) + FfxInt32x2(group_thread_id); + FfxInt32x2 dispatch_group_id = dispatch_thread_id / 8; + FfxInt32x2 remapped_group_thread_id = FfxInt32x2(ffxRemapForWaveReduction(group_index)); + FfxInt32x2 remapped_dispatch_thread_id = dispatch_group_id * 8 + remapped_group_thread_id; + + FFX_DNSR_Reflections_ResolveTemporal(remapped_dispatch_thread_id, remapped_group_thread_id, RenderSize(), InverseRenderSize(), TemporalStabilityFactor()); +} + +#endif // FFX_DNSR_REFLECTIONS_RESOLVE_TEMPORAL diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_resources.h new file mode 100644 index 00000000..390ba15a --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_resources.h @@ -0,0 +1,94 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_SHADOWS_DENOISER_RESOURCES_H +#define FFX_SHADOWS_DENOISER_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) +#define FFX_DENOISER_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_HIT_MASK_RESULTS 1 + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_TILE_BUFFER 2 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_SHADOW_MASK 3 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_RAYTRACER_RESULT 4 + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_DEPTH 5 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_VELOCITY 6 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_NORMAL 7 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_NORMAL_FP16 8 //same resource as NORMAL + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_PREVIOUS_DEPTH 9 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_TILE_META_DATA 10 + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_MOMENTS0 11 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_MOMENTS1 12 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_PREVIOUS_MOMENTS 13 //same resource as MOMENT0 & MOMENT1 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_CURRENT_MOMENTS 14 //same resource as MOMENT0 & MOMENT1 + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_SCRATCH0 15 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_SCRATCH1 16 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_HISTORY 17 //same resource as SCRATCH1 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_REPROJECTION_RESULTS 18 //same resource as SCRATCH0 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_FILTER_INPUT 19 //same resource as SCRATCH0 & SCRATCH1 + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_FILTER_OUTPUT 20 + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_INPUT_DEPTH_HIERARCHY 21 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS 22 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_INPUT_NORMAL 23 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_OUTPUT 24 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_RADIANCE 25 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_RADIANCE_HISTORY 26 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_VARIANCE 27 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_SAMPLE_COUNT 28 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_AVERAGE_RADIANCE 29 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_DENOISER_TILE_LIST 10 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_EXTRACTED_ROUGHNESS 31 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_DEPTH_HISTORY 32 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_NORMAL_HISTORY 33 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_ROUGHNESS_HISTORY 34 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_RADIANCE_0 35 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_RADIANCE_1 36 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_VARIANCE_0 37 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_VARIANCE_1 38 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_SAMPLE_COUNT_0 39 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_SAMPLE_COUNT_1 40 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_AVERAGE_RADIANCE_0 41 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_AVERAGE_RADIANCE_1 42 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_REPROJECTED_RADIANCE 43 +#define FFX_DENOISER_RESOURCE_IDENTIFIER_INDIRECT_ARGS 44 + +#define FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT 45 + +// CBV resource definitions +#define FFX_DENOISER_SHADOWS_CONSTANTBUFFER_IDENTIFIER_DENOISER_SHADOWS0 0 +#define FFX_DENOISER_SHADOWS_CONSTANTBUFFER_IDENTIFIER_DENOISER_SHADOWS1 1 +#define FFX_DENOISER_SHADOWS_CONSTANTBUFFER_IDENTIFIER_DENOISER_SHADOWS2 2 +#define FFX_DENOISER_SHADOWS_CONSTANTBUFFER_IDENTIFIER_DENOISER_SHADOWS_COUNT 3 + +// CBV resource definitions +#define FFX_DENOISER_REFLECTIONS_CONSTANTBUFFER_IDENTIFIER 0 +#define FFX_DENOISER_REFLECTIONS_CONSTANTBUFFER_IDENTIFIER_COUNT 1 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif // FFX_SHADOWS_DENOISER_RESOURCES_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_callbacks_glsl.h new file mode 100644 index 00000000..d8316a5b --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_callbacks_glsl.h @@ -0,0 +1,378 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_denoiser_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#if defined(DENOISER_SHADOWS_BIND_CB0_DENOISER_SHADOWS) + layout (set = 0, binding = DENOISER_SHADOWS_BIND_CB0_DENOISER_SHADOWS, std140) uniform cb0DenoiserShadows_t + { + FfxInt32x2 iBufferDimensions; + } cb0DenoiserShadows; +#endif + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + layout (set = 0, binding = DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS, std140) uniform cb1DenoiserShadows_t + { + FfxFloat32x3 fEye; + FfxInt32 iFirstFrame; + FfxInt32x2 iBufferDimensions; + FfxFloat32x2 fInvBufferDimensions; + FfxFloat32x2 fMotionVectorScale; + FfxFloat32x2 normalsUnpackMul_unpackAdd; + FfxFloat32Mat4 fProjectionInverse; + FfxFloat32Mat4 fReprojectionMatrix; + FfxFloat32Mat4 fViewProjectionInverse; + } cb1DenoiserShadows; +#endif + +#if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + layout (set = 0, binding = DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS, std140) uniform cb2DenoiserShadows_t + { + FfxFloat32Mat4 fProjectionInverse; + FfxFloat32x2 fInvBufferDimensions; + FfxFloat32x2 normalsUnpackMul_unpackAdd; + FfxInt32x2 iBufferDimensions; + FfxFloat32 fDepthSimilaritySigma; + } cb2DenoiserShadows; +#endif + +FfxInt32x2 BufferDimensions() +{ +#if defined(DENOISER_SHADOWS_BIND_CB0_DENOISER_SHADOWS) + return cb0DenoiserShadows.iBufferDimensions; +#elif defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + return cb1DenoiserShadows.iBufferDimensions; +#elif defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + return cb2DenoiserShadows.iBufferDimensions; +#endif + + return FfxInt32x2(0, 0); +} + +FfxFloat32x2 MotionVectorScale() +{ +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + return cb1DenoiserShadows.fMotionVectorScale; +#endif + return FfxFloat32x2(0, 0); +} + +// SRVs +#if defined DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS) + uniform utexture2D r_hit_mask_results; +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_DEPTH + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_DEPTH) + uniform texture2D r_depth; +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_VELOCITY + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_VELOCITY) + uniform texture2D r_velocity; +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_NORMAL + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_NORMAL) + uniform texture2D r_normal; +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_HISTORY + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_HISTORY) + uniform texture2D r_history; +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH) + uniform texture2D r_previous_depth; +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS) + uniform texture2D r_previous_moments; +#endif +#if FFX_HALF + #if defined DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT + layout (set = 0, binding = DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT) + uniform texture2D r_filter_input; + #endif +#endif + +// UAV declarations +#if defined DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK + layout (set = 0, binding = DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK, std430) buffer rw_shadow_mask_t + { + FfxUInt32 data[]; + } rw_shadow_mask; +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT + layout (set = 0, binding = DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT, std430) buffer rw_raytracer_result_t + { + FfxUInt32 data[]; + } rw_raytracer_result; +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_TILE_METADATA + layout (set = 0, binding = DENOISER_SHADOWS_BIND_UAV_TILE_METADATA, std430) buffer rw_tile_metadata_t + { + FfxUInt32 data[]; + } rw_tile_metadata; +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS + layout (set = 0, binding = DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS, rg32f) + uniform image2D rw_reprojection_results; +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS + layout (set = 0, binding = DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS, rgba32f) + uniform image2D rw_current_moments; +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_HISTORY + layout (set = 0, binding = DENOISER_SHADOWS_BIND_UAV_HISTORY, rg32f) + uniform image2D rw_history; +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT + layout (set = 0, binding = DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT) writeonly + uniform image2D rw_filter_output; +#endif + +#define TILE_SIZE_X 8 +#define TILE_SIZE_Y 4 + +FfxUInt32 LaneIdToBitShift(FfxUInt32x2 localID) +{ + return localID.y * TILE_SIZE_X + localID.x; +} + +FfxBoolean WaveMaskToBool(FfxUInt32 mask, FfxUInt32x2 localID) +{ + return FfxBoolean((FfxUInt32(1) << LaneIdToBitShift(localID.xy)) & mask); +} + + +#if defined(DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS) +FfxBoolean HitsLight(FfxUInt32x2 did, FfxUInt32x2 gtid, FfxUInt32x2 gid) +{ + FfxUInt32 mask = texelFetch(r_hit_mask_results, ivec2(gid), 0).r; + return !WaveMaskToBool(mask, gtid); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS) + +FfxFloat32 NormalsUnpackMul() +{ +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + return cb1DenoiserShadows.normalsUnpackMul_unpackAdd[0]; +#endif +#if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + return cb2DenoiserShadows.normalsUnpackMul_unpackAdd[0]; +#endif + return 0; +} + +FfxFloat32 NormalsUnpackAdd() +{ +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + return cb1DenoiserShadows.normalsUnpackMul_unpackAdd[1]; +#endif +#if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + return cb2DenoiserShadows.normalsUnpackMul_unpackAdd[1]; +#endif + return 0; +} + +#if defined(DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK) +void StoreShadowMask(FfxUInt32 offset, FfxUInt32 value) +{ + rw_shadow_mask.data[offset] = value; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxFloat32Mat4 ViewProjectionInverse() +{ + return cb1DenoiserShadows.fViewProjectionInverse; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxFloat32Mat4 ReprojectionMatrix() +{ + return cb1DenoiserShadows.fReprojectionMatrix; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +FfxFloat32Mat4 ProjectionInverse() +{ +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + return cb1DenoiserShadows.fProjectionInverse; +#endif +#if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + return cb2DenoiserShadows.fProjectionInverse; +#else + return FfxFloat32Mat4(0); +#endif +} + + +FfxFloat32x2 InvBufferDimensions() +{ +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + return cb1DenoiserShadows.fInvBufferDimensions; +#elif defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + return cb2DenoiserShadows.fInvBufferDimensions; +#else + return FfxFloat32x2(0, 0); +#endif +} + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxInt32 IsFirstFrame() +{ + return cb1DenoiserShadows.iFirstFrame; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxFloat32x3 Eye() +{ + return cb1DenoiserShadows.fEye; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +FfxFloat32 LoadDepth(FfxInt32x2 p) +{ +#if defined(DENOISER_SHADOWS_BIND_SRV_DEPTH) + return texelFetch(r_depth, ivec2(p), 0).x; +#else + return 0.f; +#endif +} + +#if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH) +FfxFloat32 LoadPreviousDepth(FfxInt32x2 p) +{ + return texelFetch(r_previous_depth, ivec2(p), 0).x; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH) + +#if defined(DENOISER_SHADOWS_BIND_SRV_NORMAL) +FfxFloat32x3 LoadNormals(FfxUInt32x2 p) +{ + FfxFloat32x3 normal = texelFetch(r_normal, ivec2(p), 0).xyz; + normal = normal * NormalsUnpackMul().xxx + NormalsUnpackAdd().xxx; + return normalize(normal); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_NORMAL) + +#if defined(DENOISER_SHADOWS_BIND_SRV_VELOCITY) +FfxFloat32x2 LoadVelocity(FfxInt32x2 p) +{ + FfxFloat32x2 velocity = texelFetch(r_velocity, ivec2(p), 0).rg; + return velocity * MotionVectorScale(); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_VELOCITY) + +#if defined(DENOISER_SHADOWS_BIND_SRV_HISTORY) +layout (set = 0, binding = 1000) uniform sampler s_trilinerClamp; +FfxFloat32 LoadHistory(FfxFloat32x2 p) +{ + return FfxFloat32(textureLod(sampler2D(r_history, s_trilinerClamp), p, 0.0f).x); +} +#endif + +#if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS) +FfxFloat32x3 LoadPreviousMomentsBuffer(FfxInt32x2 p) +{ + return texelFetch(r_previous_moments, ivec2(p), 0).xyz; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS) + +#if defined(DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT) +FfxUInt32 LoadRaytracedShadowMask(FfxUInt32 p) +{ + return rw_raytracer_result.data[p]; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT) + +#if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) +void StoreMetadata(FfxUInt32 p, FfxUInt32 val) +{ + rw_tile_metadata.data[p] = val; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) + +#if defined(DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS) +void StoreMoments(FfxUInt32x2 p, FfxFloat32x3 val) +{ + imageStore(rw_current_moments, ivec2(p), FfxFloat32x4(val, 0)); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS) + +#if defined(DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS) +void StoreReprojectionResults(FfxUInt32x2 p, FfxFloat32x2 val) +{ + imageStore(rw_reprojection_results, ivec2(p), FfxFloat32x4(val, 0, 0)); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS) + +#if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) +FfxFloat32 DepthSimilaritySigma() +{ + return cb2DenoiserShadows.fDepthSimilaritySigma; +} +#endif + +#if FFX_HALF + +#if defined(DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT) + FfxFloat16x2 LoadFilterInput(FfxUInt32x2 p) + { + return FfxFloat16x2(texelFetch(r_filter_input, ivec2(p), 0).xy); + } +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT) + +#endif // #if FFX_HALF + +FfxBoolean IsShadowReciever(FfxUInt32x2 p) +{ + FfxFloat32 depth = LoadDepth(FfxInt32x2(p)); + return (depth > 0.0f) && (depth < 1.0f); +} + +#if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) +FfxUInt32 LoadTileMetaData(FfxUInt32 p) +{ + return rw_tile_metadata.data[p]; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) + +void StoreHistory(FfxUInt32x2 p, FfxFloat32x2 val) +{ + #if defined(DENOISER_SHADOWS_BIND_UAV_HISTORY) + imageStore(rw_history, ivec2(p), FfxFloat32x4(val, 0, 0)); + #endif // #if defined(DENOISER_SHADOWS_BIND_UAV_HISTORY) +} + +void StoreFilterOutput(FfxUInt32x2 p, FfxFloat32 val) +{ + #if defined(DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT) + imageStore(rw_filter_output, ivec2(p), FfxFloat32x4(val, 0, 0, 0)); + #endif // #if defined(DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT) +} + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_callbacks_hlsl.h new file mode 100644 index 00000000..875fa2ba --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_callbacks_hlsl.h @@ -0,0 +1,392 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_denoiser_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define FFX_DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define FFX_DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define FFX_DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_DENOISER_SHADOWS_DECLARE_SRV(regIndex) register(FFX_DECLARE_SRV_REGISTER(regIndex)) +#define FFX_DENOISER_SHADOWS_DECLARE_UAV(regIndex) register(FFX_DECLARE_UAV_REGISTER(regIndex)) +#define FFX_DENOISER_SHADOWS_DECLARE_CB(regIndex) register(FFX_DECLARE_CB_REGISTER(regIndex)) + +#if defined(DENOISER_SHADOWS_BIND_CB0_DENOISER_SHADOWS) + cbuffer cb0DenoiserShadows : FFX_DENOISER_SHADOWS_DECLARE_CB(DENOISER_SHADOWS_BIND_CB0_DENOISER_SHADOWS) + { + FfxInt32x2 iBufferDimensions; +#define FFX_DENOISER_SHADOWS_CONSTANT_BUFFER_0_SIZE 2 + } +#endif + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + cbuffer cb1DenoiserShadows : FFX_DENOISER_SHADOWS_DECLARE_CB(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + { + FfxFloat32x3 fEye; + FfxInt32 iFirstFrame; + FfxInt32x2 iBufferDimensions; + FfxFloat32x2 fInvBufferDimensions; + FfxFloat32x2 fMotionVectorScale; + FfxFloat32x2 normalsUnpackMul_unpackAdd; + FfxFloat32Mat4 fProjectionInverse; + FfxFloat32Mat4 fReprojectionMatrix; + FfxFloat32Mat4 fViewProjectionInverse; +#define FFX_DENOISER_SHADOWS_CONSTANT_BUFFER_1_SIZE 56 + } +#endif + +#if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + cbuffer cb2DenoiserShadows : FFX_DENOISER_SHADOWS_DECLARE_CB(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + { + FfxFloat32Mat4 fProjectionInverse; + FfxFloat32x2 fInvBufferDimensions; + FfxFloat32x2 normalsUnpackMul_unpackAdd; + FfxInt32x2 iBufferDimensions; + FfxFloat32 fDepthSimilaritySigma; +#define FFX_DENOISER_SHADOWS_CONSTANT_BUFFER_2_SIZE 24 + } +#endif + +#if defined(FFX_GPU) +#define FFX_DENOISER_SHADOWS_ROOTSIG_STRINGIFY(p) FFX_DENOISER_SHADOWS_ROOTSIG_STR(p) +#define FFX_DENOISER_SHADOWS_ROOTSIG_STR(p) #p +#define FFX_DENOISER_SHADOWS_PREPARE_SHADOW_MASK_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_DENOISER_SHADOWS_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_DENOISER_SHADOWS_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0)")] + +#define FFX_DENOISER_SHADOWS_TILE_CLASSIFICATION_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_DENOISER_SHADOWS_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_DENOISER_SHADOWS_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "MinLOD = 0, " \ + "MaxLOD = 3.402823466e+38f, " \ + "mipLODBias = 0, " \ + "comparisonFunc = COMPARISON_LESS_EQUAL, " \ + "maxAnisotropy = 16, " \ + "borderColor = STATIC_BORDER_COLOR_OPAQUE_WHITE)")] + +#define FFX_DENOISER_SHADOWS_FILTER_SOFT_SHADOWS_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_DENOISER_SHADOWS_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_DENOISER_SHADOWS_ROOTSIG_STRINGIFY(FFX_DENOISER_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0)")] + +#if defined(FFX_DENOISER_SHADOWS_EMBED_ROOTSIG) +#define FFX_DENOISER_SHADOWS_EMBED_PREPARE_SHADOW_MASK_ROOTSIG_CONTENT FFX_DENOISER_SHADOWS_PREPARE_SHADOW_MASK_ROOTSIG +#define FFX_DENOISER_SHADOWS_EMBED_TILE_CLASSIFICATION_ROOTSIG_CONTENT FFX_DENOISER_SHADOWS_TILE_CLASSIFICATION_ROOTSIG +#define FFX_DENOISER_SHADOWS_EMBED_FILTER_SOFT_SHADOWS_ROOTSIG_CONTENT FFX_DENOISER_SHADOWS_FILTER_SOFT_SHADOWS_ROOTSIG +#else +#define FFX_DENOISER_SHADOWS_EMBED_PREPARE_SHADOW_MASK_ROOTSIG_CONTENT +#define FFX_DENOISER_SHADOWS_EMBED_TILE_CLASSIFICATION_ROOTSIG_CONTENT +#define FFX_DENOISER_SHADOWS_EMBED_FILTER_SOFT_SHADOWS_ROOTSIG_CONTENT +#endif // #if FFX_DENOISER_SHADOWS_EMBED_ROOTSIG +#endif // #if defined(FFX_GPU) + +// Sampler +#if defined(DENOISER_SHADOWS_BIND_SRV_HISTORY) + SamplerState s_trilinerClamp : register(s0); +#endif + +// SRVs +#if defined DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS + Texture2D r_hit_mask_results : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS); +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_DEPTH + Texture2D r_depth : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_DEPTH); +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_VELOCITY + Texture2D r_velocity : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_VELOCITY); +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_NORMAL + Texture2D r_normal : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_NORMAL); +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_HISTORY + Texture2D r_history : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_HISTORY); +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH + Texture2D r_previous_depth : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH); +#endif +#if defined DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS + Texture2D r_previous_moments : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS); +#endif + +#if FFX_HALF + #if defined DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT + Texture2D r_filter_input : FFX_DENOISER_SHADOWS_DECLARE_SRV(DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT); + #endif +#endif + +// UAV declarations +#if defined DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK + RWStructuredBuffer rw_shadow_mask : FFX_DENOISER_SHADOWS_DECLARE_UAV(DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK); +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT + RWStructuredBuffer rw_raytracer_result : FFX_DENOISER_SHADOWS_DECLARE_UAV(DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT); +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_TILE_METADATA + RWStructuredBuffer rw_tile_metadata : FFX_DENOISER_SHADOWS_DECLARE_UAV(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA); +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS + RWTexture2D rw_reprojection_results : FFX_DENOISER_SHADOWS_DECLARE_UAV(DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS); +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS + RWTexture2D rw_current_moments : FFX_DENOISER_SHADOWS_DECLARE_UAV(DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS); +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_HISTORY + RWTexture2D rw_history : FFX_DENOISER_SHADOWS_DECLARE_UAV(DENOISER_SHADOWS_BIND_UAV_HISTORY); +#endif +#if defined DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT + RWTexture2D rw_filter_output : FFX_DENOISER_SHADOWS_DECLARE_UAV(DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT); +#endif + +#define TILE_SIZE_X 8 +#define TILE_SIZE_Y 4 + +FfxUInt32 LaneIdToBitShift(FfxUInt32x2 localID) +{ + return localID.y * TILE_SIZE_X + localID.x; +} + +FfxBoolean WaveMaskToBool(FfxUInt32 mask, FfxUInt32x2 localID) +{ + return (1 << LaneIdToBitShift(localID.xy)) & mask; +} + +#if defined(DENOISER_SHADOWS_BIND_CB0_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) +FfxInt32x2 BufferDimensions() +{ + return iBufferDimensions; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB0_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS) +FfxBoolean HitsLight(FfxUInt32x2 did, FfxUInt32x2 gtid, FfxUInt32x2 gid) +{ + return !WaveMaskToBool(r_hit_mask_results[gid], gtid); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_INPUT_HIT_MASK_RESULTS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) +FfxFloat32 NormalsUnpackMul() +{ + return normalsUnpackMul_unpackAdd[0]; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) +FfxFloat32 NormalsUnpackAdd() +{ + return normalsUnpackMul_unpackAdd[1]; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK) +void StoreShadowMask(FfxUInt32 offset, FfxUInt32 value) +{ + rw_shadow_mask[offset] = value; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_SHADOW_MASK) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxFloat32Mat4 ViewProjectionInverse() +{ + return fViewProjectionInverse; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxFloat32Mat4 ReprojectionMatrix() +{ + return fReprojectionMatrix; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) +FfxFloat32Mat4 ProjectionInverse() +{ + return fProjectionInverse; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) +FfxFloat32x2 InvBufferDimensions() +{ + return fInvBufferDimensions; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) || defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxFloat32x2 MotionVectorScale() +{ + return fMotionVectorScale; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxInt32 IsFirstFrame() +{ + return iFirstFrame; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +#if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) +FfxFloat32x3 Eye() +{ + return fEye; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB1_DENOISER_SHADOWS) + +FfxFloat32 LoadDepth(FfxInt32x2 p) +{ + #if defined(DENOISER_SHADOWS_BIND_SRV_DEPTH) + return r_depth.Load(FfxInt32x3(p, 0)).x; + #else + return 0.f; + #endif // #if defined(DENOISER_SHADOWS_BIND_SRV_DEPTH) +} + +#if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH) +FfxFloat32 LoadPreviousDepth(FfxInt32x2 p) +{ + return r_previous_depth.Load(FfxInt32x3(p, 0)).x; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_DEPTH) + +#if defined(DENOISER_SHADOWS_BIND_SRV_NORMAL) +FfxFloat32x3 LoadNormals(FfxInt32x2 p) +{ + FfxFloat32x3 normal = r_normal.Load(FfxInt32x3(p, 0)).xyz; + normal = normal * NormalsUnpackMul().xxx + NormalsUnpackAdd().xxx; + return normalize(normal); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_NORMAL) + +#if defined(DENOISER_SHADOWS_BIND_SRV_VELOCITY) +FfxFloat32x2 LoadVelocity(FfxInt32x2 p) +{ + FfxFloat32x2 velocity = r_velocity.Load(FfxInt32x3(p, 0)).rg; + return velocity * MotionVectorScale(); +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_VELOCITY) + +#if defined(DENOISER_SHADOWS_BIND_SRV_HISTORY) +FfxFloat32 LoadHistory(FfxFloat32x2 p) +{ + return r_history.SampleLevel(s_trilinerClamp, p, 0).x; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_HISTORY) + +#if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS) +FfxFloat32x3 LoadPreviousMomentsBuffer(FfxInt32x2 p) +{ + return r_previous_moments.Load(FfxInt32x3(p, 0)).xyz; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_SRV_PREVIOUS_MOMENTS) + +#if defined(DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT) +FfxUInt32 LoadRaytracedShadowMask(FfxUInt32 p) +{ + return rw_raytracer_result[p]; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_RAYTRACER_RESULT) + +#if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) +void StoreMetadata(FfxUInt32 p, FfxUInt32 val) +{ + rw_tile_metadata[p] = val; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) + +#if defined(DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS) +void StoreMoments(FfxUInt32x2 p, FfxFloat32x3 val) +{ + rw_current_moments[p] = val; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_CURRENT_MOMENTS) + +#if defined(DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS) +void StoreReprojectionResults(FfxUInt32x2 p, FfxFloat32x2 val) +{ + rw_reprojection_results[p] = val; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_REPROJECTION_RESULTS) + +#if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) +FfxFloat32 DepthSimilaritySigma() +{ + return fDepthSimilaritySigma; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_CB2_DENOISER_SHADOWS) + +#if FFX_HALF + #if defined(DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT) + FfxFloat16x2 LoadFilterInput(FfxUInt32x2 p) + { + return (FfxFloat16x2)r_filter_input.Load(FfxInt32x3(p, 0)).xy; + } + #endif // #if defined(DENOISER_SHADOWS_BIND_SRV_FILTER_INPUT) +#endif + +FfxBoolean IsShadowReciever(FfxUInt32x2 p) +{ + FfxFloat32 depth = LoadDepth(p); + return (depth > 0.0f) && (depth < 1.0f); +} + +#if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) +FfxUInt32 LoadTileMetaData(FfxUInt32 p) +{ + return rw_tile_metadata[p]; +} +#endif // #if defined(DENOISER_SHADOWS_BIND_UAV_TILE_METADATA) + +void StoreHistory(FfxUInt32x2 p, FfxFloat32x2 val) +{ + #if defined(DENOISER_SHADOWS_BIND_UAV_HISTORY) + rw_history[p] = val; + #endif // #if defined(DENOISER_SHADOWS_BIND_UAV_HISTORY) +} + +void StoreFilterOutput(FfxUInt32x2 p, FfxFloat32 val) +{ + #if defined(DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT) + rw_filter_output[p].x = val; + #endif // #if defined(DENOISER_SHADOWS_BIND_UAV_FILTER_OUTPUT) +} + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_filter.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_filter.h new file mode 100644 index 00000000..6b3137d6 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_filter.h @@ -0,0 +1,331 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_SHADOWS_FILTER_HLSL +#define FFX_DNSR_SHADOWS_FILTER_HLSL + +#include "ffx_denoiser_shadows_util.h" + +FFX_GROUPSHARED FfxUInt32 g_FFX_DNSR_Shadows_shared_input[16][16]; +FFX_GROUPSHARED FfxFloat32 g_FFX_DNSR_Shadows_shared_depth[16][16]; +FFX_GROUPSHARED FfxUInt32 g_FFX_DNSR_Shadows_shared_normals_xy[16][16]; +FFX_GROUPSHARED FfxUInt32 g_FFX_DNSR_Shadows_shared_normals_zw[16][16]; + +#if FFX_HALF +FfxUInt32 FFX_DNSR_Shadows_PackFloat16(FfxFloat16x2 v) +{ + return ffxPackHalf2x16(FfxFloat32x2(v)); +} + +FfxFloat16x2 FFX_DNSR_Shadows_UnpackFloat16(FfxUInt32 a) +{ + return ffxUnpackF16(a); +} + +FfxFloat16x2 FFX_DNSR_Shadows_LoadInputFromGroupSharedMemory(FfxInt32x2 idx) +{ + return FFX_DNSR_Shadows_UnpackFloat16(g_FFX_DNSR_Shadows_shared_input[idx.y][idx.x]); +} +#endif + +FfxFloat32 FFX_DNSR_Shadows_LoadDepthFromGroupSharedMemory(FfxInt32x2 idx) +{ + return g_FFX_DNSR_Shadows_shared_depth[idx.y][idx.x]; +} + +#if FFX_HALF +FfxFloat16x3 FFX_DNSR_Shadows_LoadNormalsFromGroupSharedMemory(FfxInt32x2 idx) +{ + FfxFloat16x3 normals; + normals.xy = FFX_DNSR_Shadows_UnpackFloat16(g_FFX_DNSR_Shadows_shared_normals_xy[idx.y][idx.x]); + normals.z = FFX_DNSR_Shadows_UnpackFloat16(g_FFX_DNSR_Shadows_shared_normals_zw[idx.y][idx.x]).x; + return normals; +} + +void FFX_DNSR_Shadows_StoreInGroupSharedMemory(FfxInt32x2 idx, FfxFloat16x3 normals, FfxFloat16x2 inp, FfxFloat32 depth) +{ + g_FFX_DNSR_Shadows_shared_input[idx.y][idx.x] = FFX_DNSR_Shadows_PackFloat16(inp); + g_FFX_DNSR_Shadows_shared_depth[idx.y][idx.x] = depth; + g_FFX_DNSR_Shadows_shared_normals_xy[idx.y][idx.x] = FFX_DNSR_Shadows_PackFloat16(normals.xy); + g_FFX_DNSR_Shadows_shared_normals_zw[idx.y][idx.x] = FFX_DNSR_Shadows_PackFloat16(FfxFloat16x2(normals.z, 0)); +} + +void FFX_DNSR_Shadows_LoadWithOffset(FfxInt32x2 did, FfxInt32x2 offset, out FfxFloat16x3 normals, out FfxFloat16x2 inp, out FfxFloat32 depth) +{ + did += offset; + + const FfxInt32x2 p = clamp(did, FfxInt32x2(0, 0), BufferDimensions() - 1); + normals = FfxFloat16x3(LoadNormals(p)); + inp = LoadFilterInput(p); + depth = LoadDepth(p); +} + +void FFX_DNSR_Shadows_StoreWithOffset(FfxInt32x2 gtid, FfxInt32x2 offset, FfxFloat16x3 normals, FfxFloat16x2 inp, FfxFloat32 depth) +{ + gtid += offset; + FFX_DNSR_Shadows_StoreInGroupSharedMemory(gtid, normals, inp, depth); +} + +void FFX_DNSR_Shadows_InitializeGroupSharedMemory(FfxInt32x2 did, FfxInt32x2 gtid) +{ + FfxInt32x2 offset_0 = FfxInt32x2(0, 0); + FfxInt32x2 offset_1 = FfxInt32x2(8, 0); + FfxInt32x2 offset_2 = FfxInt32x2(0, 8); + FfxInt32x2 offset_3 = FfxInt32x2(8, 8); + + FfxFloat16x3 normals_0; + FfxFloat16x2 input_0; + FfxFloat32 depth_0; + + FfxFloat16x3 normals_1; + FfxFloat16x2 input_1; + FfxFloat32 depth_1; + + FfxFloat16x3 normals_2; + FfxFloat16x2 input_2; + FfxFloat32 depth_2; + + FfxFloat16x3 normals_3; + FfxFloat16x2 input_3; + FfxFloat32 depth_3; + + /// XA + /// BC + + did -= 4; + FFX_DNSR_Shadows_LoadWithOffset(did, offset_0, normals_0, input_0, depth_0); // X + FFX_DNSR_Shadows_LoadWithOffset(did, offset_1, normals_1, input_1, depth_1); // A + FFX_DNSR_Shadows_LoadWithOffset(did, offset_2, normals_2, input_2, depth_2); // B + FFX_DNSR_Shadows_LoadWithOffset(did, offset_3, normals_3, input_3, depth_3); // C + + FFX_DNSR_Shadows_StoreWithOffset(gtid, offset_0, normals_0, input_0, depth_0); // X + FFX_DNSR_Shadows_StoreWithOffset(gtid, offset_1, normals_1, input_1, depth_1); // A + FFX_DNSR_Shadows_StoreWithOffset(gtid, offset_2, normals_2, input_2, depth_2); // B + FFX_DNSR_Shadows_StoreWithOffset(gtid, offset_3, normals_3, input_3, depth_3); // C +} +#else +// Not used, defined to make sure f32 path compiles +FfxUInt32 FFX_DNSR_Shadows_PackFloat16(FfxFloat32x2 v){return 0;} +FfxFloat32x2 FFX_DNSR_Shadows_UnpackFloat16(FfxUInt32 a){return FfxFloat32x2(0,0);} +FfxFloat32x2 FFX_DNSR_Shadows_LoadInputFromGroupSharedMemory(FfxInt32x2 idx){return FfxFloat32x2(0,0);} +FfxFloat32x3 FFX_DNSR_Shadows_LoadNormalsFromGroupSharedMemory(FfxInt32x2 idx){return FfxFloat32x3(0,0,0);} +void FFX_DNSR_Shadows_StoreInGroupSharedMemory(FfxInt32x2 idx, FfxFloat32x3 normals, FfxFloat32x2 inp, FfxFloat32 depth){} +void FFX_DNSR_Shadows_LoadWithOffset(FfxInt32x2 did, FfxInt32x2 offset, out FfxFloat32x3 normals, out FfxFloat32x2 inp, out FfxFloat32 depth){depth = 0;} +void FFX_DNSR_Shadows_StoreWithOffset(FfxInt32x2 gtid, FfxInt32x2 offset, FfxFloat32x3 normals, FfxFloat32x2 inp, FfxFloat32 depth){} +void FFX_DNSR_Shadows_InitializeGroupSharedMemory(FfxInt32x2 did, FfxInt32x2 gtid){} +#endif + +FfxFloat32 FFX_DNSR_Shadows_GetShadowSimilarity(FfxFloat32 x1, FfxFloat32 x2, FfxFloat32 sigma) +{ + return exp(-abs(x1 - x2) / sigma); +} + +FfxFloat32 FFX_DNSR_Shadows_GetDepthSimilarity(FfxFloat32 x1, FfxFloat32 x2, FfxFloat32 sigma) +{ + return exp(-abs(x1 - x2) / sigma); +} + +FfxFloat32 FFX_DNSR_Shadows_GetNormalSimilarity(FfxFloat32x3 x1, FfxFloat32x3 x2) +{ + return ffxPow(ffxSaturate(dot(x1, x2)), 32.0f); +} + +FfxFloat32 FFX_DNSR_Shadows_GetLinearDepth(FfxUInt32x2 did, FfxFloat32 depth) +{ + const FfxFloat32x2 uv = (did + 0.5f) * InvBufferDimensions(); + const FfxFloat32x2 ndc = 2.0f * FfxFloat32x2(uv.x, 1.0f - uv.y) - 1.0f; + + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(ProjectionInverse(), FfxFloat32x4(ndc, depth, 1)); + + return abs(projected.z / projected.w); +} + +FfxFloat32 FFX_DNSR_Shadows_FetchFilteredVarianceFromGroupSharedMemory(FfxInt32x2 pos) +{ + const FfxInt32 k = 1; + FfxFloat32 variance = 0.0f; + const FfxFloat32 kernel[2][2] = + { + { 1.0f / 4.0f, 1.0f / 8.0f }, + { 1.0f / 8.0f, 1.0f / 16.0f } + }; + for (FfxInt32 y = -k; y <= k; ++y) + { + for (FfxInt32 x = -k; x <= k; ++x) + { + const FfxFloat32 w = kernel[abs(x)][abs(y)]; + variance += w * FFX_DNSR_Shadows_LoadInputFromGroupSharedMemory(pos + FfxInt32x2(x, y)).y; + } + } + return variance; +} + +void FFX_DNSR_Shadows_DenoiseFromGroupSharedMemory(FfxUInt32x2 did, FfxUInt32x2 gtid, inout FfxFloat32 weight_sum, inout FfxFloat32x2 shadow_sum, FfxFloat32 depth, FfxUInt32 stepsize) +{ + // Load our center sample + const FfxFloat32x2 shadow_center = FFX_DNSR_Shadows_LoadInputFromGroupSharedMemory(FfxInt32x2(gtid)); + const FfxFloat32x3 normal_center = FFX_DNSR_Shadows_LoadNormalsFromGroupSharedMemory(FfxInt32x2(gtid)); + + weight_sum = 1.0f; + shadow_sum = shadow_center; + + const FfxFloat32 variance = FFX_DNSR_Shadows_FetchFilteredVarianceFromGroupSharedMemory(FfxInt32x2(gtid)); + const FfxFloat32 std_deviation = sqrt(max(variance + 1e-9f, 0.0f)); + const FfxFloat32 depth_center = FFX_DNSR_Shadows_GetLinearDepth(did, depth); // linearize the depth value + + // Iterate filter kernel + const FfxInt32 k = 1; + const FfxFloat32 kernel[3] = { 1.0f, 2.0f / 3.0f, 1.0f / 6.0f }; + + for (FfxInt32 y = -k; y <= k; ++y) + { + for (FfxInt32 x = -k; x <= k; ++x) + { + // Should we process this sample? + const FfxInt32x2 step = FfxInt32x2(x, y) * FfxInt32x2(stepsize, stepsize); + const FfxInt32x2 gtid_idx = FfxInt32x2(gtid) + step; + const FfxInt32x2 did_idx = FfxInt32x2(did) + step; + + FfxFloat32 depth_neigh = FFX_DNSR_Shadows_LoadDepthFromGroupSharedMemory(gtid_idx); + FfxFloat32x3 normal_neigh = FFX_DNSR_Shadows_LoadNormalsFromGroupSharedMemory(gtid_idx); + FfxFloat32x2 shadow_neigh = FFX_DNSR_Shadows_LoadInputFromGroupSharedMemory(gtid_idx); + + FfxFloat32 sky_pixel_multiplier = ((x == 0 && y == 0) || depth_neigh >= 1.0f || depth_neigh <= 0.0f) ? 0 : 1; // Zero weight for sky pixels + + // Fetch our filtering values + depth_neigh = FFX_DNSR_Shadows_GetLinearDepth(did_idx, depth_neigh); + + // Evaluate the edge-stopping function + FfxFloat32 w = kernel[abs(x)] * kernel[abs(y)]; // kernel weight + w *= FFX_DNSR_Shadows_GetShadowSimilarity(shadow_center.x, shadow_neigh.x, std_deviation); + w *= FFX_DNSR_Shadows_GetDepthSimilarity(depth_center, depth_neigh, DepthSimilaritySigma()); + w *= FFX_DNSR_Shadows_GetNormalSimilarity(normal_center, normal_neigh); + w *= sky_pixel_multiplier; + + // Accumulate the filtered sample + shadow_sum += FfxFloat32x2(w, w * w) * shadow_neigh; + weight_sum += w; + } + } +} + +FfxFloat32x2 FFX_DNSR_Shadows_ApplyFilterWithPrecache(FfxUInt32x2 did, FfxUInt32x2 gtid, FfxUInt32 stepsize) +{ + FfxFloat32 weight_sum = 1.0; + FfxFloat32x2 shadow_sum = FfxFloat32x2(0, 0); + + FFX_DNSR_Shadows_InitializeGroupSharedMemory(FfxInt32x2(did), FfxInt32x2(gtid)); + FfxBoolean needs_denoiser = IsShadowReciever(did); + FFX_GROUP_MEMORY_BARRIER; + if (needs_denoiser) + { + FfxFloat32 depth = LoadDepth(FfxInt32x2(did)); + gtid += 4; // Center threads in groupshared memory + FFX_DNSR_Shadows_DenoiseFromGroupSharedMemory(did, gtid, weight_sum, shadow_sum, depth, stepsize); + } + + FfxFloat32 mean = shadow_sum.x / weight_sum; + FfxFloat32 variance = shadow_sum.y / (weight_sum * weight_sum); + return FfxFloat32x2(mean, variance); +} + +void FFX_DNSR_Shadows_ReadTileMetaData(FfxUInt32x2 gid, out FfxBoolean is_cleared, out FfxBoolean all_in_light) +{ + FfxUInt32 meta_data = LoadTileMetaData(gid.y * FFX_DNSR_Shadows_RoundedDivide(BufferDimensions().x, 8) + gid.x); + is_cleared = FfxBoolean(meta_data & FfxUInt32(TILE_META_DATA_CLEAR_MASK)); + all_in_light = FfxBoolean(meta_data & FfxUInt32(TILE_META_DATA_LIGHT_MASK)); +} + + +FfxFloat32x2 FFX_DNSR_Shadows_FilterSoftShadowsPass(FfxUInt32x2 gid, FfxUInt32x2 gtid, FfxUInt32x2 did, out FfxBoolean bWriteResults, const FfxUInt32 pass, const FfxUInt32 stepsize) +{ + FfxBoolean is_cleared; + FfxBoolean all_in_light; + FFX_DNSR_Shadows_ReadTileMetaData(gid, is_cleared, all_in_light); + + bWriteResults = FFX_FALSE; + FfxFloat32x2 results = FfxFloat32x2(0, 0); + + if (is_cleared) + { + if (pass != 1) + { + results.x = all_in_light ? 1.0 : 0.0; + bWriteResults = FFX_TRUE; + } + } + else + { + results = FFX_DNSR_Shadows_ApplyFilterWithPrecache(did, gtid, stepsize); + bWriteResults = FFX_TRUE; + } + + return results; +} + +void DenoiserShadowsFilterPass0(FfxUInt32x2 gid, FfxUInt32x2 gtid, FfxUInt32x2 did) +{ + const uint PASS_INDEX = 0; + const uint STEP_SIZE = 1; + + FfxBoolean bWriteOutput = FFX_FALSE; + const FfxFloat32x2 results = FFX_DNSR_Shadows_FilterSoftShadowsPass(gid, gtid, did, bWriteOutput, PASS_INDEX, STEP_SIZE); + + if (bWriteOutput) + { + StoreHistory(did, results); + } +} + +void DenoiserShadowsFilterPass1(FfxUInt32x2 gid, FfxUInt32x2 gtid, FfxUInt32x2 did) +{ + const uint PASS_INDEX = 1; + const uint STEP_SIZE = 2; + + FfxBoolean bWriteOutput = FFX_FALSE; + const FfxFloat32x2 results = FFX_DNSR_Shadows_FilterSoftShadowsPass(gid, gtid, did, bWriteOutput, PASS_INDEX, STEP_SIZE); + + if (bWriteOutput) + { + StoreHistory(did, results); + } +} + +void DenoiserShadowsFilterPass2(FfxUInt32x2 gid, FfxUInt32x2 gtid, FfxUInt32x2 did) +{ + const uint PASS_INDEX = 2; + const uint STEP_SIZE = 4; + + FfxBoolean bWriteOutput = FFX_FALSE; + const FfxFloat32x2 results = FFX_DNSR_Shadows_FilterSoftShadowsPass(gid, gtid, did, bWriteOutput, PASS_INDEX, STEP_SIZE); + + // Recover some of the contrast lost during denoising + const FfxFloat32 shadow_remap = max(1.2f - results.y, 1.0f); + const FfxFloat32 mean = pow(abs(results.x), shadow_remap); + + if (bWriteOutput) + { + StoreFilterOutput(did, mean); + } +} + +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_prepare.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_prepare.h new file mode 100644 index 00000000..c61276cf --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_prepare.h @@ -0,0 +1,53 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_SHADOWS_PREPARESHADOWMASK_HLSL +#define FFX_DNSR_SHADOWS_PREPARESHADOWMASK_HLSL + +#include "ffx_denoiser_shadows_util.h" + +void FFX_DNSR_Shadows_CopyResult(FfxUInt32x2 gtid, FfxUInt32x2 gid) +{ + const FfxUInt32x2 did = gid * FfxUInt32x2(8, 4) + gtid; + const FfxUInt32 linear_tile_index = FFX_DNSR_Shadows_LinearTileIndex(gid, BufferDimensions().x); + const FfxBoolean hit_light = HitsLight(did, gtid, gid); + const FfxUInt32 lane_mask = hit_light ? FFX_DNSR_Shadows_GetBitMaskFromPixelPosition(did) : 0; + StoreShadowMask(linear_tile_index, ffxWaveOr(lane_mask)); +} + +void FFX_DNSR_Shadows_PrepareShadowMask(FfxUInt32x2 gtid, FfxUInt32x2 gid) +{ + gid *= 4; + FfxUInt32x2 tile_dimensions = (BufferDimensions() + FfxUInt32x2(7, 3)) / FfxUInt32x2(8, 4); + + for (FfxInt32 i = 0; i < 4; ++i) + { + for (FfxInt32 j = 0; j < 4; ++j) + { + FfxUInt32x2 tile_id = FfxUInt32x2(gid.x + i, gid.y + j); + tile_id = clamp(tile_id, FfxUInt32x2(0, 0), tile_dimensions - FfxUInt32x2(1,1)); + FFX_DNSR_Shadows_CopyResult(gtid, tile_id); + } + } +} + +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_tileclassification.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_tileclassification.h new file mode 100644 index 00000000..c3729e72 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_tileclassification.h @@ -0,0 +1,430 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_SHADOWS_TILECLASSIFICATION_HLSL +#define FFX_DNSR_SHADOWS_TILECLASSIFICATION_HLSL + +#include "ffx_denoiser_shadows_util.h" + +FFX_GROUPSHARED FfxInt32 g_FFX_DNSR_Shadows_false_count; +FfxBoolean FFX_DNSR_Shadows_ThreadGroupAllTrue(FfxBoolean val) +{ + const FfxUInt32 lane_count_in_thread_group = 64; + if (ffxWaveLaneCount() == lane_count_in_thread_group) + { + return ffxWaveAllTrue(val); + } + else + { + FFX_GROUP_MEMORY_BARRIER; + g_FFX_DNSR_Shadows_false_count = 0; + FFX_GROUP_MEMORY_BARRIER; + if (!val) g_FFX_DNSR_Shadows_false_count = 1; + FFX_GROUP_MEMORY_BARRIER; + return g_FFX_DNSR_Shadows_false_count == 0; + } +} + +void FFX_DNSR_Shadows_SearchSpatialRegion(FfxUInt32x2 gid, out FfxBoolean all_in_light, out FfxBoolean all_in_shadow) +{ + // The spatial passes can reach a total region of 1+2+4 = 7x7 around each block. + // The masks are 8x4, so we need a larger vertical stride + + // Visualization - each x represents a 4x4 block, xx is one entire 8x4 mask as read from the raytracer result + // Same for yy, these are the ones we are working on right now + + // xx xx xx + // xx xx xx + // xx yy xx <-- yy here is the base_tile below + // xx yy xx + // xx xx xx + // xx xx xx + + // All of this should result in scalar ops + FfxUInt32x2 base_tile = FFX_DNSR_Shadows_GetTileIndexFromPixelPosition(gid * FfxInt32x2(8, 8)); + + // Load the entire region of masks in a scalar fashion + FfxUInt32 combined_or_mask = 0; + FfxUInt32 combined_and_mask = 0xFFFFFFFF; + for (FfxInt32 j = -2; j <= 3; ++j) + { + for (FfxInt32 i = -1; i <= 1; ++i) + { + FfxInt32x2 tile_index = FfxInt32x2(base_tile) + FfxInt32x2(i, j); + tile_index = clamp(tile_index, FfxInt32x2(0,0), FfxInt32x2(FFX_DNSR_Shadows_RoundedDivide(BufferDimensions().x, 8), FFX_DNSR_Shadows_RoundedDivide(BufferDimensions().y, 4)) - 1); + const FfxUInt32 linear_tile_index = FFX_DNSR_Shadows_LinearTileIndex(tile_index, BufferDimensions().x); + const FfxUInt32 shadow_mask = LoadRaytracedShadowMask(linear_tile_index); + + combined_or_mask = combined_or_mask | shadow_mask; + combined_and_mask = combined_and_mask & shadow_mask; + } + } + + all_in_light = combined_and_mask == 0xFFFFFFFFu; + all_in_shadow = combined_or_mask == 0u; +} + +FfxFloat32 FFX_DNSR_Shadows_GetLinearDepth(FfxUInt32x2 did, FfxFloat32 depth) +{ + const FfxFloat32x2 uv = (did + 0.5f) * InvBufferDimensions(); + const FfxFloat32x2 ndc = 2.0f * FfxFloat32x2(uv.x, 1.0f - uv.y) - 1.0f; + + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(ProjectionInverse(), FfxFloat32x4(ndc, depth, 1)); + + return abs(projected.z / projected.w); +} + +FfxBoolean FFX_DNSR_Shadows_IsDisoccluded(FfxUInt32x2 did, FfxFloat32 depth, FfxFloat32x2 velocity) +{ + const FfxInt32x2 dims = BufferDimensions(); + const FfxFloat32x2 texel_size = InvBufferDimensions(); + const FfxFloat32x2 uv = (did + 0.5f) * texel_size; + const FfxFloat32x2 ndc = (2.0f * uv - 1.0f) * FfxFloat32x2(1.0f, -1.0f); + const FfxFloat32x2 previous_uv = uv + velocity; + + FfxBoolean is_disoccluded = FFX_TRUE; + + if (all(FFX_GREATER_THAN(previous_uv, FfxFloat32x2(0,0))) && all(FFX_LESS_THAN(previous_uv, FfxFloat32x2(1,1)))) + { + // Read the center values + FfxFloat32x3 normal = LoadNormals(did); + + FfxFloat32x4 clip_space = FFX_MATRIX_MULTIPLY(ReprojectionMatrix(), FfxFloat32x4(ndc, depth, 1.0f)); + + clip_space.z /= clip_space.w; // perspective divide + + // How aligned with the view vector? (the more Z aligned, the higher the depth errors) + const FfxFloat32x4 homogeneous = FFX_MATRIX_MULTIPLY(ViewProjectionInverse(), FfxFloat32x4(ndc, depth, 1.0f)); + const FfxFloat32x3 world_position = FfxFloat32x3(homogeneous.xyz / homogeneous.w); // perspective divide + const FfxFloat32x3 view_direction = normalize(Eye().xyz - world_position); + FfxFloat32 z_alignment = 1.0f - dot(view_direction, normal); + z_alignment = pow(z_alignment, 8); + + // Calculate the depth difference + FfxFloat32 linear_depth = FFX_DNSR_Shadows_GetLinearDepth(did, clip_space.z); // get linear depth + + FfxInt32x2 idx = FfxInt32x2(previous_uv * FfxFloat32x2(dims)); + const FfxFloat32 previous_depth = FFX_DNSR_Shadows_GetLinearDepth(idx, LoadPreviousDepth(idx)); + const FfxFloat32 depth_difference = abs(previous_depth - linear_depth) / linear_depth; + + // Resolve into the disocclusion mask + const FfxFloat32 depth_tolerance = ffxLerp(1e-2f, 1e-1f, z_alignment); + is_disoccluded = depth_difference >= depth_tolerance; + } + + return is_disoccluded; +} + +FfxFloat32x2 FFX_DNSR_Shadows_GetClosestVelocity(FfxInt32x2 did, FfxFloat32 depth) +{ + FfxFloat32x2 closest_velocity = LoadVelocity(did); + FfxFloat32 closest_depth = depth; + + FfxFloat32 new_depth = ffxQuadReadX(closest_depth); + FfxFloat32x2 new_velocity = ffxQuadReadX(closest_velocity); + +#if FFX_DENOISER_OPTION_INVERTED_DEPTH + if (new_depth > closest_depth) +#else + if (new_depth < closest_depth) +#endif + { + closest_depth = new_depth; + closest_velocity = new_velocity; + } + + new_depth = ffxQuadReadY(closest_depth); + new_velocity = ffxQuadReadY(closest_velocity); + +#if FFX_DENOISER_OPTION_INVERTED_DEPTH + if (new_depth > closest_depth) +#else + if (new_depth < closest_depth) +#endif + { + closest_depth = new_depth; + closest_velocity = new_velocity; + } + + return closest_velocity; +} + +#define KERNEL_RADIUS 8 +FfxFloat32 FFX_DNSR_Shadows_KernelWeight(FfxFloat32 i) +{ +#define KERNEL_WEIGHT(i) (exp(-3.0 * FfxFloat32(i * i) / ((KERNEL_RADIUS + 1.0) * (KERNEL_RADIUS + 1.0)))) + + // Statically initialize kernel_weights_sum + FfxFloat32 kernel_weights_sum = 0; + kernel_weights_sum += KERNEL_WEIGHT(0); + for (FfxInt32 c = 1; c <= KERNEL_RADIUS; ++c) + { + kernel_weights_sum += 2 * KERNEL_WEIGHT(c); // Add other half of the kernel to the sum + } + FfxFloat32 inv_kernel_weights_sum = ffxReciprocal(kernel_weights_sum); + + // The only runtime code in this function + return KERNEL_WEIGHT(i) * inv_kernel_weights_sum; +} + +void FFX_DNSR_Shadows_AccumulateMoments(FfxFloat32 value, FfxFloat32 weight, inout FfxFloat32 moments) +{ + // We get value from the horizontal neighborhood calculations. Thus, it's both mean and variance due to using one sample per pixel + moments += value * weight; +} + +// The horizontal part of a 17x17 local neighborhood kernel +FfxFloat32 FFX_DNSR_Shadows_HorizontalNeighborhood(FfxInt32x2 did) +{ + const FfxInt32x2 base_did = did; + + // Prevent vertical out of bounds access + if ((base_did.y < 0) || (base_did.y >= BufferDimensions().y)) return 0; + + const FfxUInt32x2 tile_index = FFX_DNSR_Shadows_GetTileIndexFromPixelPosition(base_did); + const FfxUInt32 linear_tile_index = FFX_DNSR_Shadows_LinearTileIndex(tile_index, BufferDimensions().x); + + const FfxUInt32 left_tile_index = linear_tile_index - 1; + const FfxUInt32 center_tile_index = linear_tile_index; + const FfxUInt32 right_tile_index = linear_tile_index + 1; + + FfxBoolean is_first_tile_in_row = tile_index.x == 0; + FfxBoolean is_last_tile_in_row = tile_index.x == (FFX_DNSR_Shadows_RoundedDivide(BufferDimensions().x, 8) - 1); + + FfxUInt32 left_tile = 0; + if (!is_first_tile_in_row) left_tile = LoadRaytracedShadowMask(left_tile_index); + FfxUInt32 center_tile = LoadRaytracedShadowMask(center_tile_index); + FfxUInt32 right_tile = 0; + if (!is_last_tile_in_row) right_tile = LoadRaytracedShadowMask(right_tile_index); + + // Construct a single FfxUInt32 with the lowest 17bits containing the horizontal part of the local neighborhood. + + // First extract the 8 bits of our row in each of the neighboring tiles + const FfxUInt32 row_base_index = (did.y % 4) * 8; + const FfxUInt32 left = (left_tile >> row_base_index) & 0xFF; + const FfxUInt32 center = (center_tile >> row_base_index) & 0xFF; + const FfxUInt32 right = (right_tile >> row_base_index) & 0xFF; + + // Combine them into a single mask containting [left, center, right] from least significant to most significant bit + FfxUInt32 neighborhood = left | (center << 8) | (right << 16); + + // Make sure our pixel is at bit position 9 to get the highest contribution from the filter kernel + const FfxUInt32 bit_index_in_row = (did.x % 8); + neighborhood = neighborhood >> bit_index_in_row; // Shift out bits to the right, so the center bit ends up at bit 9. + + FfxFloat32 moment = 0.0; // For one sample per pixel this is both, mean and variance + + // First 8 bits up to the center pixel + FfxUInt32 mask; + FfxInt32 i; + for (i = 0; i < 8; ++i) + { + mask = 1u << i; + moment += FfxBoolean(mask & neighborhood) ? FFX_DNSR_Shadows_KernelWeight(8 - i) : 0; + } + + // Center pixel + mask = 1u << 8; + moment += FfxBoolean(mask & neighborhood) ? FFX_DNSR_Shadows_KernelWeight(0) : 0; + + // Last 8 bits + for (i = 1; i <= 8; ++i) + { + mask = 1u << (8 + i); + moment += FfxBoolean(mask & neighborhood) ? FFX_DNSR_Shadows_KernelWeight(i) : 0; + } + + return moment; +} + +FFX_GROUPSHARED FfxFloat32 g_FFX_DNSR_Shadows_neighborhood[8][24]; + +FfxFloat32 FFX_DNSR_Shadows_ComputeLocalNeighborhood(FfxInt32x2 did, FfxInt32x2 gtid) +{ + FfxFloat32 local_neighborhood = 0; + + FfxFloat32 upper = FFX_DNSR_Shadows_HorizontalNeighborhood(FfxInt32x2(did.x, did.y - 8)); + FfxFloat32 center = FFX_DNSR_Shadows_HorizontalNeighborhood(FfxInt32x2(did.x, did.y)); + FfxFloat32 lower = FFX_DNSR_Shadows_HorizontalNeighborhood(FfxInt32x2(did.x, did.y + 8)); + + g_FFX_DNSR_Shadows_neighborhood[gtid.x][gtid.y] = upper; + g_FFX_DNSR_Shadows_neighborhood[gtid.x][gtid.y + 8] = center; + g_FFX_DNSR_Shadows_neighborhood[gtid.x][gtid.y + 16] = lower; + + FFX_GROUP_MEMORY_BARRIER; + + // First combine the own values. + // KERNEL_RADIUS pixels up is own upper and KERNEL_RADIUS pixels down is own lower value + FFX_DNSR_Shadows_AccumulateMoments(center, FFX_DNSR_Shadows_KernelWeight(0), local_neighborhood); + FFX_DNSR_Shadows_AccumulateMoments(upper, FFX_DNSR_Shadows_KernelWeight(KERNEL_RADIUS), local_neighborhood); + FFX_DNSR_Shadows_AccumulateMoments(lower, FFX_DNSR_Shadows_KernelWeight(KERNEL_RADIUS), local_neighborhood); + + // Then read the neighboring values. + for (FfxInt32 i = 1; i < KERNEL_RADIUS; ++i) + { + FfxFloat32 upper_value = g_FFX_DNSR_Shadows_neighborhood[gtid.x][8 + gtid.y - i]; + FfxFloat32 lower_value = g_FFX_DNSR_Shadows_neighborhood[gtid.x][8 + gtid.y + i]; + FfxFloat32 weight = FFX_DNSR_Shadows_KernelWeight(i); + FFX_DNSR_Shadows_AccumulateMoments(upper_value, weight, local_neighborhood); + FFX_DNSR_Shadows_AccumulateMoments(lower_value, weight, local_neighborhood); + } + + return local_neighborhood; +} + +void FFX_DNSR_Shadows_WriteTileMetaData(FfxUInt32x2 gid, FfxUInt32x2 gtid, FfxBoolean is_cleared, FfxBoolean all_in_light) +{ + if (all(FFX_EQUAL(gtid, FfxUInt32x2(0,0)))) + { + FfxUInt32 light_mask = all_in_light ? TILE_META_DATA_LIGHT_MASK : 0; + FfxUInt32 clear_mask = is_cleared ? TILE_META_DATA_CLEAR_MASK : 0; + FfxUInt32 mask = FfxUInt32(light_mask | clear_mask); + StoreMetadata(gid.y * FFX_DNSR_Shadows_RoundedDivide(BufferDimensions().x, 8) + gid.x, mask); + } +} + +void FFX_DNSR_Shadows_ClearTargets(FfxUInt32x2 did, FfxUInt32x2 gtid, FfxUInt32x2 gid, FfxFloat32 shadow_value, FfxBoolean is_shadow_receiver, FfxBoolean all_in_light) +{ + FFX_DNSR_Shadows_WriteTileMetaData(gid, gtid, FFX_TRUE, all_in_light); + StoreReprojectionResults(did, FfxFloat32x2(shadow_value, 0)); // mean, variance + + FfxFloat32 temporal_sample_count = is_shadow_receiver ? 1 : 0; + StoreMoments(did, FfxFloat32x3(shadow_value, 0, temporal_sample_count));// mean, variance, temporal sample count +} + +void FFX_DNSR_Shadows_TileClassification(FfxUInt32 group_index, FfxUInt32x2 gid) +{ + FfxUInt32x2 gtid = ffxRemapForWaveReduction(group_index); // Make sure we can use the QuadReadAcross intrinsics to access a 2x2 region. + FfxUInt32x2 did = gid * 8 + gtid; + + FfxBoolean is_shadow_receiver = IsShadowReciever(did); + + FfxBoolean skip_sky = FFX_DNSR_Shadows_ThreadGroupAllTrue(!is_shadow_receiver); + if (skip_sky) + { + // We have to set all resources of the tile we skipped to sensible values as neighboring active denoiser tiles might want to read them. + FFX_DNSR_Shadows_ClearTargets(did, gtid, gid, 0, is_shadow_receiver, FFX_FALSE); + return; + } + + FfxBoolean all_in_light = FFX_FALSE; + FfxBoolean all_in_shadow = FFX_FALSE; + FFX_DNSR_Shadows_SearchSpatialRegion(gid, all_in_light, all_in_shadow); + FfxFloat32 shadow_value = all_in_light ? 1 : 0; // Either all_in_light or all_in_shadow must be true, otherwise we would not skip the tile. + + FfxBoolean can_skip = all_in_light || all_in_shadow; + // We have to append the entire tile if there is a single lane that we can't skip + FfxBoolean skip_tile = FFX_DNSR_Shadows_ThreadGroupAllTrue(can_skip); + if (skip_tile) + { + // We have to set all resources of the tile we skipped to sensible values as neighboring active denoiser tiles might want to read them. + FFX_DNSR_Shadows_ClearTargets(did, gtid, gid, shadow_value, is_shadow_receiver, all_in_light); + return; + } + + FFX_DNSR_Shadows_WriteTileMetaData(gid, gtid, FFX_FALSE, FFX_FALSE); + + FfxFloat32 depth = LoadDepth(FfxInt32x2(did)); + const FfxFloat32x2 velocity = FFX_DNSR_Shadows_GetClosestVelocity(FfxInt32x2(did), depth); // Must happen before we deactivate lanes + const FfxFloat32 local_neighborhood = FFX_DNSR_Shadows_ComputeLocalNeighborhood(FfxInt32x2(did), FfxInt32x2(gtid)); + + const FfxFloat32x2 texel_size = InvBufferDimensions(); + const FfxFloat32x2 uv = (did.xy + 0.5f) * texel_size; + const FfxFloat32x2 history_uv = uv + velocity; + const FfxInt32x2 history_pos = FfxInt32x2(history_uv * BufferDimensions()); + + const FfxUInt32x2 tile_index = FFX_DNSR_Shadows_GetTileIndexFromPixelPosition(FfxInt32x2(did)); + const FfxUInt32 linear_tile_index = FFX_DNSR_Shadows_LinearTileIndex(tile_index, BufferDimensions().x); + + const FfxUInt32 shadow_tile = LoadRaytracedShadowMask(linear_tile_index); + + FfxFloat32x3 moments_current = FfxFloat32x3(0,0,0); + FfxFloat32 variance = 0; + FfxFloat32 shadow_clamped = 0; + if (is_shadow_receiver) // do not process sky pixels + { + FfxBoolean hit_light = FfxBoolean(shadow_tile & FFX_DNSR_Shadows_GetBitMaskFromPixelPosition(did)); + const FfxFloat32 shadow_current = hit_light ? 1.0 : 0.0; + + // Perform moments and variance calculations + { + FfxBoolean is_disoccluded = FFX_DNSR_Shadows_IsDisoccluded(did, depth, velocity); + const FfxFloat32x3 previous_moments = is_disoccluded ? FfxFloat32x3(0.0f, 0.0f, 0.0f) // Can't trust previous moments on disocclusion + : LoadPreviousMomentsBuffer(history_pos); + + const FfxFloat32 old_m = previous_moments.x; + const FfxFloat32 old_s = previous_moments.y; + const FfxFloat32 sample_count = previous_moments.z + 1.0f; + const FfxFloat32 new_m = old_m + (shadow_current - old_m) / sample_count; + const FfxFloat32 new_s = old_s + (shadow_current - old_m) * (shadow_current - new_m); + + variance = (sample_count > 1.0f ? new_s / (sample_count - 1.0f) : 1.0f); + moments_current = FfxFloat32x3(new_m, new_s, sample_count); + } + + // Retrieve local neighborhood and reproject + { + FfxFloat32 mean = local_neighborhood; + FfxFloat32 spatial_variance = local_neighborhood; + + spatial_variance = max(spatial_variance - mean * mean, 0.0f); + + // Compute the clamping bounding box + const FfxFloat32 std_deviation = sqrt(spatial_variance); + const FfxFloat32 nmin = mean - 0.5f * std_deviation; + const FfxFloat32 nmax = mean + 0.5f * std_deviation; + + // Clamp reprojected sample to local neighborhood + FfxFloat32 shadow_previous = shadow_current; + if (IsFirstFrame() == 0) + { + shadow_previous = LoadHistory(history_uv); + } + + shadow_clamped = clamp(shadow_previous, nmin, nmax); + + // Reduce history weighting + const FfxFloat32 sigma = 20.0f; + const FfxFloat32 temporal_discontinuity = (shadow_previous - mean) / max(0.5f * std_deviation, 0.001f); + const FfxFloat32 sample_counter_damper = exp(-temporal_discontinuity * temporal_discontinuity / sigma); + moments_current.z *= sample_counter_damper; + + // Boost variance on first frames + if (moments_current.z < 16.0f) + { + const FfxFloat32 variance_boost = max(16.0f - moments_current.z, 1.0f); + variance = max(variance, spatial_variance); + variance *= variance_boost; + } + } + + // Perform the temporal blend + const FfxFloat32 history_weight = sqrt(max(8.0f - moments_current.z, 0.0f) / 8.0f); + shadow_clamped = ffxLerp(shadow_clamped, shadow_current, ffxLerp(0.05f, 1.0f, history_weight)); + } + + // Output the results of the temporal pass + StoreReprojectionResults(did.xy, FfxFloat32x2(shadow_clamped, variance)); + StoreMoments(did.xy, moments_current); +} + +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_util.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_util.h new file mode 100644 index 00000000..51f861a4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/denoiser/ffx_denoiser_shadows_util.h @@ -0,0 +1,50 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DNSR_SHADOWS_UTILS_HLSL +#define FFX_DNSR_SHADOWS_UTILS_HLSL + +FfxUInt32 FFX_DNSR_Shadows_RoundedDivide(FfxUInt32 value, FfxUInt32 divisor) +{ + return (value + divisor - 1) / divisor; +} + +FfxUInt32x2 FFX_DNSR_Shadows_GetTileIndexFromPixelPosition(FfxUInt32x2 pixel_pos) +{ + return FfxUInt32x2(pixel_pos.x / 8, pixel_pos.y / 4); +} + +FfxUInt32 FFX_DNSR_Shadows_LinearTileIndex(FfxUInt32x2 tile_index, FfxUInt32 screen_width) +{ + return tile_index.y * FFX_DNSR_Shadows_RoundedDivide(screen_width, 8) + tile_index.x; +} + +FfxUInt32 FFX_DNSR_Shadows_GetBitMaskFromPixelPosition(FfxUInt32x2 pixel_pos) +{ + FfxUInt32 lane_index = (pixel_pos.y % 4) * 8 + (pixel_pos.x % 8); + return (1u << lane_index); +} + +#define TILE_META_DATA_CLEAR_MASK 1 +#define TILE_META_DATA_LIGHT_MASK 2 + +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/CMakeCompileDOFShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/CMakeCompileDOFShaders.txt new file mode 100644 index 00000000..4ab2f1c1 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/CMakeCompileDOFShaders.txt @@ -0,0 +1,51 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(DOF_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(DOF_PERMUTATION_ARGS + -DFFX_DOF_OPTION_MAX_RING_MERGE_LOG={0,1} + -DFFX_DOF_OPTION_COMBINE_IN_PLACE={0,1} + -DFFX_DOF_OPTION_REVERSE_DEPTH={0,1}) + +set(DOF_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/dof") + +if (NOT DOF_SHADER_EXT) + set(DOF_SHADER_EXT *) +endif() + +file(GLOB DOF_SHADERS + "shaders/dof/ffx_dof_downsample_depth_pass.${DOF_SHADER_EXT}" + "shaders/dof/ffx_dof_downsample_color_pass.${DOF_SHADER_EXT}" + "shaders/dof/ffx_dof_dilate_pass.${DOF_SHADER_EXT}" + "shaders/dof/ffx_dof_blur_pass.${DOF_SHADER_EXT}" + "shaders/dof/ffx_dof_composite_pass.${DOF_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${DOF_BASE_ARGS}" "${DOF_API_BASE_ARGS}" "${DOF_PERMUTATION_ARGS}" "${DOF_INCLUDE_ARGS}" + "${DOF_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" DOF_PERMUTATION_OUTPUTS) + +add_shader_output("${DOF_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_blur.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_blur.h new file mode 100644 index 00000000..9c6ab536 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_blur.h @@ -0,0 +1,714 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" +#include "ffx_dof_common.h" + +// Factor applied to a distance value before checking that it is in range of the blur kernel. +FFX_STATIC const FfxFloat32 FFX_DOF_RANGE_TOLERANCE_FACTOR = 0.98; + +// Accumulators for one ring. Used for ring occlusion. +struct FfxDofBucket +{ + FfxFloat32x4 color; // rgb=color sum, a=weight sum + FfxFloat32 ringCovg; // radius of the ring coverage (average of tileCoc/coc with some clamping) + FfxFloat32 radius; // radius of the ring center + FfxUInt32 sampleCount; // number of samples counted +}; + +// One sample of the input and related variables +struct FfxDofSample +{ + FfxFloat32 coc; // signed circle of confusion in pixels. negative values are far-field. + FfxFloat32x3 color; // color value of the sample +}; + +// Helper struct to contain all input variables +struct FfxDofInputState +{ + FfxUInt32x2 imageSize; // input pixel size (half res) + FfxFloat32x2 pxCoord; // pixel coordinates of the kernel center + FfxFloat32 tileCoc; // coc value bilinearly interpolated from the tile map + FfxFloat32 centerCoc; // signed coc value at the kernel center + FfxFloat32 ringGap; // undersampling factor. ringGap * nRings = tileCoc. + FfxUInt32 mipLevel; // mip level to use based on coc and MAX_RINGS + FfxBoolean nearField; // whether the center pixel is in the near field + FfxUInt32 nSamples, // number of actual samples taken + nRings; // number of rings to sample (<= MAX_RINGS) + FfxFloat32 covgFactor, covgBias; // coverage parameters +}; + +// Helper struct to contain accumulation variables +struct FfxDofAccumulators +{ + FfxDofBucket prevBucket, currBucket; + FfxFloat32x4 ringColor; + FfxFloat32 ringCovg; + FfxFloat32x4 nearColor, fillColor; +}; + +// Merges currBucket into prevBucket. Opacity is ratio of hit/total samples in current ring. +void FfxDofMergeBuckets(inout FfxDofAccumulators acc, FfxFloat32 opacity) +{ + // averaging + FfxFloat32 prevRC = ffxSaturate(acc.prevBucket.ringCovg / acc.prevBucket.sampleCount); + FfxFloat32 currRC = ffxSaturate(acc.currBucket.ringCovg / acc.currBucket.sampleCount); + + // occlusion term is calculated as the ratio of the area of intersection of both buckets + // (being viewed as rings with a radius (centered on the samples) and ring width (=avg coverage)) + // divided by the area of the previous bucket ring. + FfxFloat32 prevOuter = ffxSaturate(acc.prevBucket.radius + prevRC); + FfxFloat32 prevInner = (acc.prevBucket.radius - prevRC); + FfxFloat32 currOuter = ffxSaturate(acc.currBucket.radius + currRC); + FfxFloat32 currInner = (acc.currBucket.radius - currRC); + // intersection is between min(outer) and max(inner) + FfxFloat32 insOuter = min(prevOuter, currOuter); + FfxFloat32 insInner = max(prevInner, currInner); + // intersection area formula. + // ffxSaturate here fixes edge case where prev area = 0 -> ffxSaturate(0/0)=ffxSaturate(nan) = 0 + // The value does not matter in that case, since the previous values will be all zero, but it must be finite. + FfxFloat32 occlusion = insOuter < insInner ? 0 : ffxSaturate((insOuter * insOuter - sign(insInner) * insInner * insInner) / (prevOuter * prevOuter - sign(prevInner) * prevInner * prevInner)); + + FfxFloat32 factor = 1 - opacity * occlusion; + acc.prevBucket.color = acc.prevBucket.color * factor + acc.currBucket.color; + // select new radius so that (roughly) covers both rings, so in the middle of the combined ring + FfxFloat32 newRadius = 0.5 * (max(prevOuter, currOuter) + min(prevInner, currInner)); + // the new coverage should then be the difference between the radius and either bound + FfxFloat32 newCovg = 0.5 * (max(prevOuter, currOuter) - min(prevInner, currInner)); + acc.prevBucket.sampleCount = FfxUInt32(acc.prevBucket.sampleCount * factor) + acc.currBucket.sampleCount; + acc.prevBucket.ringCovg = acc.prevBucket.sampleCount * newCovg; + acc.prevBucket.radius = newRadius; +} + +FfxFloat32 FfxDofWeight(FfxDofInputState ins, FfxFloat32 coc) +{ + // Weight is inverse coc area (1 / pi*r^2). Use pi~=4 for perf reasons. + // Saturate to avoid explosion of weight close to zero. If coc < 0.5, the coc is contained + // within this pixel and the weight should be 1. + FfxFloat32 invRad = 1.0 / coc; + return ffxSaturate(invRad * invRad / 4); +} + +FfxFloat32 FfxDofCoverage(FfxDofInputState ins, FfxFloat32 coc) +{ + // Coverage is essentially the radius of the sample's projection to the lens aperture. + // The radius is normalized to the tile CoC and kernel diameter in samples. + // Add a small bias to account for gaps between sample rings. + // Clamped to avoid infinity near zero. + return ffxSaturate(ins.covgFactor / coc + ins.covgBias); +} + +#ifdef FFX_DOF_CUSTOM_SAMPLES + +// declarations only + +// *MUST DEFINE* own struct SampleStreamState ! See below #else for example. + +/// Callback for custom blur kernels. Gets the sample offset and advances the iterator. +/// @param state Mutable state for the sample stream. +/// @return The sample location in normalized uv coordinates. The default implementation approximates a circle using a combination of rotation and translation in an affine transform. +/// @ingroup FfxGPUDof +FfxFloat32x2 FfxDofAdvanceSampleStream(inout SampleStreamState state); + +/// Callback for custom blur kernels. Gets the number of samples in a ring and initalizes iteration state. +/// @param state Mutable state for the sample stream. +/// @param ins Input parameters for the blur kernel. Contains the full number of rings. +/// @param ri Index of the current ring. If rings are being merged, this is the center of the indices. +/// @param mergeRingsCount The number of rings being merged. 1 if the current ring is not merged with any other. +/// @return The number of samples in the ring, assuming no merging. This is divided by the mergeRingsCount to get the actual number of samples. +/// @ingroup FfxGPUDof +FfxUInt32 FfxDofInitSampleStream(out SampleStreamState state, FfxDofInputState ins, FfxFloat32 ri, FfxUInt32 mergeRingsCount); + +#else + +struct SampleStreamState { + // represents an affine 2d transform to go from one sample position to the next. + FfxFloat32 cosTheta; // top-left and bottom-right element of rotation matrix + FfxFloat32 sinThetaXAspect; // bottom-left element of rotation matrix + FfxFloat32 mSinThetaXrAspect; // top-right element of rotation matrix + FfxFloat32x2 translation; // additive part of affine transform + FfxFloat32x2 position; // next sample position +}; + +FfxFloat32x2 FfxDofAdvanceSampleStream(inout SampleStreamState state) +{ + FfxFloat32x2 pos = state.position; + // affine transformation. + FfxFloat32 x = state.cosTheta * pos.x + state.mSinThetaXrAspect * pos.y; + FfxFloat32 y = state.sinThetaXAspect * pos.x + state.cosTheta * pos.y; + state.position = FfxFloat32x2(x, y) + state.translation; + return pos; +} + +FfxUInt32 FfxDofInitSampleStream(out SampleStreamState state, FfxDofInputState ins, FfxFloat32 ri, FfxUInt32 merge) +{ +#if FFX_DOF_MAX_RING_MERGE > 1 + FfxUInt32 n = FfxUInt32(6.25 * (ins.nRings - ri)); // approx. pi/asin(1/(2*(nR-ri))) +#else + // using fixed-point version of above allows scalar alu to do the same operation. Equivalent if merge == 1 (=> ri is integer). + FfxUInt32 n = (27 * FfxUInt32(ins.nRings - ri)) >> 2; +#endif + FfxFloat32 r = ins.tileCoc * ffxReciprocal(ins.nRings) * FfxFloat32(ins.nRings - ri); + state.position = InputSizeHalfRcp() * (ins.pxCoord + FfxFloat32x2(r, 0)); + FfxFloat32 theta = 6.2831853 * ffxReciprocal(n) * merge; + FfxFloat32 s = sin(theta), c = cos(theta); + FfxFloat32x2 aspect = InputSizeHalf() * InputSizeHalfRcp().yx; + + state.cosTheta = c; + state.sinThetaXAspect = s * aspect.x; + state.mSinThetaXrAspect = -s * aspect.y; + state.translation = InputSizeHalfRcp() * (ins.pxCoord - ins.pxCoord.x * FfxFloat32x2(c, s) - ins.pxCoord.y * FfxFloat32x2(-s, c)); + return n; +} + +#endif // #ifdef FFX_DOF_CUSTOM_SAMPLES + +struct FfxDofRingParams { + FfxFloat32 distance; // distance to center in pixels / radius of ring + FfxFloat32 bucketBorder; // (far field) border between curr/prev bucket + FfxFloat32 rangeThreshNear; // threshold for in-range determination in near field + FfxFloat32 rangeThreshFar; // same for far field + FfxFloat32 rangeThreshFill; // threshold for main or fallback fill selection + FfxFloat32 fillQuality; // bg-fill contribution quality +}; + +FfxDofSample FfxDofFetchSample(FfxDofInputState ins, inout SampleStreamState streamState, FfxUInt32 mipBias) +{ + FfxFloat32x2 samplePos = FfxDofAdvanceSampleStream(streamState); + FfxUInt32 mipLevel = ins.mipLevel + mipBias; + FfxFloat32x4 texval = FfxDofSampleInput(samplePos, mipLevel); + FfxDofSample result; + result.coc = texval.a; + result.color = texval.rgb; + return result; +} + +void FfxDofProcessNearSample(FfxDofInputState ins, FfxDofSample s, inout FfxDofAccumulators acc, FfxDofRingParams ring) +{ + // feather the range slightly (1px) + FfxFloat32 inRangeWeight = ffxSaturate(s.coc - ring.rangeThreshNear); + FfxFloat32 weight = FfxDofWeight(ins, abs(s.coc)); + + // fill background behind center using farther away samples. + if (ins.nearField) + { + // Try to reject same-surface samples using using a slope of 1px radius per px distance. + // But use the rejected pixels if no others are available. + FfxFloat32 rejectionWeight = (s.coc < ring.rangeThreshFill) ? 1.0 : (1.0/2048.0); + // prefer nearest (in image space) samples + // Contribution decreases quadratically with sample distance. + acc.fillColor += FfxFloat32x4(s.color, 1) * weight * ring.fillQuality * rejectionWeight; + } + + acc.nearColor += FfxFloat32x4(s.color, 1) * weight * inRangeWeight; +} + +void FfxDofProcessFarSample(FfxDofInputState ins, FfxDofSample s, inout FfxDofAccumulators acc, FfxDofRingParams ring) +{ + FfxFloat32 clampedFarCoc = max(0, -s.coc); + FfxFloat32 inRangeWeight = ffxSaturate(-s.coc - ring.rangeThreshFar); + + FfxFloat32 covg = FfxDofCoverage(ins, abs(s.coc)); + FfxFloat32x4 color = FfxFloat32x4(s.color, 1) * FfxDofWeight(ins, abs(s.coc)) * inRangeWeight; + + if (-s.coc >= ring.bucketBorder) + { + acc.prevBucket.ringCovg += covg; + acc.prevBucket.color += color; + acc.prevBucket.sampleCount++; + } + else + { + acc.currBucket.ringCovg += covg; + acc.currBucket.color += color; + acc.currBucket.sampleCount++; + } +} + +void FfxDofProcessNearFar(FfxDofInputState ins, inout FfxDofAccumulators acc) +{ + // base case: both near and far-field are processed. + // scan outside-in for far-field occlusion + for (FfxUInt32 ri = 0; ri < ins.nRings; ri++) + { + acc.currBucket.color = FFX_BROADCAST_FLOAT32X4(0); + acc.currBucket.ringCovg = 0; + acc.currBucket.radius = ffxReciprocal(ins.nRings) * FfxFloat32(ins.nRings - ri); + acc.currBucket.sampleCount = 0; + + SampleStreamState streamState; + FfxUInt32 ringSamples = FfxDofInitSampleStream(streamState, ins, ri, 1); + FfxDofRingParams ring; + ring.distance = ins.tileCoc * ffxReciprocal(ins.nRings) * FfxFloat32(ins.nRings - ri); + ring.bucketBorder = (ins.nRings - 1 - ri + 2.5) * ins.tileCoc * ffxReciprocal(0.5 + ins.nRings); + ring.rangeThreshNear = max(0, ring.distance - ins.ringGap - 0.5); + ring.rangeThreshFar = max(0, ring.distance - ins.ringGap); + ring.rangeThreshFill = ins.centerCoc - ring.distance; + ring.fillQuality = (1 / ring.distance) * (1 / ring.distance); + + // partially unrolled loop + const FfxUInt32 UNROLL_CNT = 2; + FfxUInt32 iunr = 0; + for (iunr = 0; iunr + UNROLL_CNT <= ringSamples; iunr += UNROLL_CNT) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < UNROLL_CNT; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, 0); + FfxDofProcessFarSample(ins, s, acc, ring); + FfxDofProcessNearSample(ins, s, acc, ring); + } + } + for (FfxUInt32 i = iunr; i < ringSamples; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, 0); + FfxDofProcessFarSample(ins, s, acc, ring); + FfxDofProcessNearSample(ins, s, acc, ring); + } + + FfxFloat32 opacity = FfxFloat32(acc.currBucket.sampleCount) / FfxFloat32(ringSamples); + FfxDofMergeBuckets(acc, opacity); + } +} + +void FfxDofProcessNearOnly(FfxDofInputState ins, inout FfxDofAccumulators acc) +{ + // variant with the assumption that all samples are near field + for (FfxUInt32 ri = 0; ri < ins.nRings; ri++) + { + SampleStreamState streamState; + FfxUInt32 ringSamples = FfxDofInitSampleStream(streamState, ins, ri, 1); + FfxDofRingParams ring; + ring.distance = ins.tileCoc * ffxReciprocal(ins.nRings) * FfxFloat32(ins.nRings - ri); + ring.rangeThreshNear = max(0, ring.distance - ins.ringGap - 0.5); + ring.rangeThreshFill = ins.centerCoc - ring.distance; + ring.fillQuality = (1 / ring.distance) * (1 / ring.distance); + + // partially unrolled loop + const FfxUInt32 UNROLL_CNT = 4; + FfxUInt32 iunr = 0; + for (iunr = 0; iunr + UNROLL_CNT <= ringSamples; iunr += UNROLL_CNT) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < UNROLL_CNT; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, 0); + FfxDofProcessNearSample(ins, s, acc, ring); + } + } + for (FfxUInt32 i = iunr; i < ringSamples; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, 0); + FfxDofProcessNearSample(ins, s, acc, ring); + } + } +} + +void FfxDofProcessFarOnly(FfxDofInputState ins, inout FfxDofAccumulators acc) +{ + // variant with the assumption that all samples are far field + // scan outside-in for far-field occlusion + for (FfxUInt32 ri = 0; ri < ins.nRings; ri++) + { + acc.currBucket.color = FFX_BROADCAST_FLOAT32X4(0); + acc.currBucket.ringCovg = 0; + acc.currBucket.radius = ffxReciprocal(ins.nRings) * FfxFloat32(ins.nRings - ri); + acc.currBucket.sampleCount = 0; + + SampleStreamState streamState; + FfxUInt32 ringSamples = FfxDofInitSampleStream(streamState, ins, ri, 1); + FfxDofRingParams ring; + ring.distance = ins.tileCoc * ffxReciprocal(ins.nRings) * FfxFloat32(ins.nRings - ri); + ring.bucketBorder = (ins.nRings - 1 - ri + 2.5) * ins.tileCoc * ffxReciprocal(0.5 + ins.nRings); + ring.rangeThreshFar = max(0, ring.distance - ins.ringGap); + + // partially unrolled loop + const FfxUInt32 UNROLL_CNT = 3; + FfxUInt32 iunr = 0; + for (iunr = 0; iunr + UNROLL_CNT <= ringSamples; iunr += UNROLL_CNT) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < UNROLL_CNT; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, 0); + FfxDofProcessFarSample(ins, s, acc, ring); + } + } + for (FfxUInt32 i = iunr; i < ringSamples; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, 0); + FfxDofProcessFarSample(ins, s, acc, ring); + } + + FfxFloat32 opacity = FfxFloat32(acc.currBucket.sampleCount) / FfxFloat32(ringSamples); + FfxDofMergeBuckets(acc, opacity); + } +} + +void FfxDofProcessNearColorOnly(FfxDofInputState ins, inout FfxDofAccumulators acc) +{ + // variant with the assumption that all samples are near and equally weighed + for (FfxUInt32 ri = 0; ri < ins.nRings;) + { + // merge inner rings if possible + FfxUInt32 merge = min(min(1 << ri, FFX_DOF_MAX_RING_MERGE), ins.nRings - ri); + FfxFloat32 rif = ri + 0.5 * merge - 0.5; + FfxUInt32 weight = merge * merge; + SampleStreamState streamState; + FfxUInt32 ringSamples = FfxDofInitSampleStream(streamState, ins, rif, merge) / merge; + FfxUInt32 mipBias = 2 * FfxUInt32(log2(merge)); + FfxFloat32 sampleDist = ins.tileCoc * ffxReciprocal(ins.nRings) * (FfxFloat32(ins.nRings) - rif); + FfxHalfOpt rangeThresh = FfxHalfOpt(max(0, sampleDist - ins.ringGap - 0.5)); + + FfxHalfOpt3 nearColorAcc = FfxHalfOpt3(0, 0, 0); + FfxHalfOpt weightSum = FfxHalfOpt(0); + // We presume that all samples are in range + // partially unrolled loop (x6) + const FfxUInt32 UNROLL_CNT = 6; + FfxUInt32 iunr = 0; + for (iunr = 0; iunr + UNROLL_CNT <= ringSamples; iunr += UNROLL_CNT) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < UNROLL_CNT; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + FfxHalfOpt rangeWeight = ffxSaturate(FfxHalfOpt(s.coc) - rangeThresh); + nearColorAcc += FfxHalfOpt3(s.color) * rangeWeight; + weightSum += rangeWeight; + } + } + for (FfxUInt32 i = iunr; i < ringSamples; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + FfxHalfOpt rangeWeight = ffxSaturate(FfxHalfOpt(s.coc) - rangeThresh); + nearColorAcc += FfxHalfOpt3(s.color) * rangeWeight; + weightSum += rangeWeight; + } + acc.nearColor.rgb += nearColorAcc * FfxHalfOpt(weight); + acc.nearColor.a += weightSum * FfxHalfOpt(weight); + ri += merge; + } +} + +void FfxDofProcessFarColorOnly(FfxDofInputState ins, inout FfxDofAccumulators acc) +{ + FfxFloat32 nSamples = 0; + FfxUInt32 ri = 0; + // peel first iteration + if (ri < ins.nRings) + { + // merge inner rings if possible + FfxUInt32 merge = min(min(1 << ri, FFX_DOF_MAX_RING_MERGE), ins.nRings - ri); + FfxFloat32 rif = ri + 0.5 * merge - 0.5; + FfxUInt32 weight = merge * merge; + SampleStreamState streamState; + FfxUInt32 ringSamples = FfxDofInitSampleStream(streamState, ins, rif, merge) / merge; + FfxUInt32 mipBias = 2 * FfxUInt32(log2(merge)); + FfxFloat32 sampleDist = ins.tileCoc * ffxReciprocal(ins.nRings) * (FfxFloat32(ins.nRings) - rif); + FfxHalfOpt rangeThresh = FfxHalfOpt(max(0, sampleDist - ins.ringGap)); + + FfxHalfOpt3 colorAcc = FfxHalfOpt3(0, 0, 0); + FfxHalfOpt weightSum = FfxHalfOpt(0); + // partially unrolled loop (x8, then x4) + FfxUInt32 iunr = 0; + for (; iunr + 8 <= ringSamples; iunr += 8) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < 8; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + FfxHalfOpt rangeWeight = ffxSaturate(FfxHalfOpt(-s.coc) - rangeThresh); + colorAcc += FfxHalfOpt3(s.color) * rangeWeight; + weightSum += rangeWeight; + } + } + for (; iunr + 4 <= ringSamples; iunr += 4) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < 4; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + FfxHalfOpt rangeWeight = ffxSaturate(FfxHalfOpt(-s.coc) - rangeThresh); + colorAcc += FfxHalfOpt3(s.color) * rangeWeight; + weightSum += rangeWeight; + } + } + for (FfxUInt32 i = iunr; i < ringSamples; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + FfxHalfOpt rangeWeight = ffxSaturate(FfxHalfOpt(-s.coc) - rangeThresh); + colorAcc += FfxHalfOpt3(s.color) * rangeWeight; + weightSum += rangeWeight; + } + acc.prevBucket.color.rgb += colorAcc * FfxHalfOpt(weight); + nSamples += weightSum * FfxHalfOpt(weight); + ri += merge; + } + while (ri < ins.nRings) + { + // merge inner rings if possible + FfxUInt32 merge = min(min(1 << ri, FFX_DOF_MAX_RING_MERGE), ins.nRings - ri); + FfxFloat32 rif = ri + 0.5 * merge - 0.5; + FfxUInt32 weight = merge * merge; + SampleStreamState streamState; + FfxUInt32 ringSamples = FfxDofInitSampleStream(streamState, ins, rif, merge) / merge; + FfxUInt32 mipBias = 2 * FfxUInt32(log2(merge)); + + FfxHalfOpt3 colorAcc = FfxHalfOpt3(0, 0, 0); + // partially unrolled loop (x12, then x4) + FfxUInt32 iunr = 0; + for (; iunr + 12 <= ringSamples; iunr += 12) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < 12; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + // Max difference between sample coc and tile coc is 0.5px (see PrepareTile). + // Max radius of any ring after first (ri>0) is 1 less than tile coc. + // rangeWeight = 1 + colorAcc += FfxHalfOpt3(s.color); + } + } + for (; iunr + 4 <= ringSamples; iunr += 4) + { + FFX_DOF_UNROLL + for (FfxUInt32 i = 0; i < 4; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + colorAcc += FfxHalfOpt3(s.color); + } + } + for (FfxUInt32 i = iunr; i < ringSamples; i++) + { + FfxDofSample s = FfxDofFetchSample(ins, streamState, mipBias); + colorAcc += FfxHalfOpt3(s.color); + } + acc.prevBucket.color.rgb += colorAcc * FfxHalfOpt(weight); + nSamples += ringSamples * weight; + ri += merge; + } + acc.prevBucket.color.a = nSamples; + acc.prevBucket.ringCovg = nSamples; + acc.prevBucket.sampleCount = FfxUInt32(nSamples); +} + +struct FfxDofTileClass +{ + FfxBoolean colorOnly, needsNear, needsFar; +}; + +// prepare values for the tile. Return classification. +FfxDofTileClass FfxDofPrepareTile(FfxUInt32x2 id, out FfxDofInputState ins) +{ + FfxDofTileClass tileClass; + FfxFloat32x2 dilatedCocSigned = FfxDofSampleDilatedRadius(id); + FfxFloat32x2 dilatedCoc = abs(dilatedCocSigned); + FfxFloat32 tileRad = max(dilatedCoc.x, dilatedCoc.y); + + // check if copying the tile is good enough +#if FFX_HLSL + if (WaveActiveAllTrue(tileRad < 0.5)) +#elif FFX_GLSL + if (subgroupAll(tileRad < 0.5)) +#endif + { + tileClass.needsNear = false; + tileClass.needsFar = false; + tileClass.colorOnly = false; + return tileClass; + } + + FfxFloat32 idealRingCount = // kernel radius in pixels -> one sample per pixel +#if FFX_HLSL + WaveActiveMax(ceil(tileRad)); +#elif FFX_GLSL + subgroupMax(ceil(tileRad)); +#endif + ins.nRings = FfxUInt32(idealRingCount); + ins.mipLevel = 0; + if (idealRingCount > MaxRings()) + { + ins.nRings = MaxRings(); + // use a higher mip to cover the missing rings. + // for every factor 2 decrease of the rings, increase mips by 1. + ins.mipLevel = FfxUInt32(log2(idealRingCount * ffxReciprocal(MaxRings()))); + } + // Gap = number of pixels between rings that are not sampled. + ins.ringGap = idealRingCount / ins.nRings - 1.0; + ins.tileCoc = tileRad; + + FfxFloat32x2 texcoord = FfxFloat32x2(id) + FfxFloat32x2(0.25, 0.25); // shift to center of top-left pixel in quad + // Add noise to reduce banding (if too noisy, this could be disabled) + { + /* hash22 adapted from https://www.shadertoy.com/view/4djSRW + Copyright (c)2014 David Hoskins. + +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.*/ + FfxFloat32x3 p3 = ffxFract(texcoord.xyx * FfxFloat32x3(0.1031, 0.1030, 0.0973)); + p3 += dot(p3, p3.yzx + 33.33); + texcoord += ffxFract((p3.xx+p3.yz)*p3.zy) * 0.5 - 0.25; + } + ins.pxCoord = texcoord; + + FfxFloat32 centerCoc = FfxDofLoadInput(id).a; + ins.nearField = centerCoc > 0; + ins.centerCoc = abs(centerCoc); + + ins.nSamples = 0; +#ifdef FFX_DOF_CUSTOM_SAMPLES + for (FfxUInt32 ri = 0; ri < ins.nRings; ri++) + { + SampleStreamState streamState; + ins.nSamples += FfxDofInitSampleStream(streamState, ins, ri, 1); + } +#else + // due to rounding this will likely over-approximate, but that should be okay. + ins.nSamples = FfxUInt32(6.25 * 0.5 * (ins.nRings * (ins.nRings + 1))); +#endif + + // read first lane to force using a scalar register. + ins.covgFactor = ffxWaveReadLaneFirst(0.5 * ffxReciprocal(ins.nRings) * ins.tileCoc); + ins.covgBias = ffxWaveReadLaneFirst(0.5 * ffxReciprocal(ins.nRings)); + +#if FFX_HLSL + // simple check: is there even any near/far that we would sample? + // See ProcessNearSample: No relevant code is executed if the center is not near and no sample is near + // (use the CoC of the dilated tile minimum depth as the proxy for any sample) + tileClass.needsNear = WaveActiveAnyTrue(dilatedCocSigned.x > -1); + // See ProcessFarSample: All weights will be 0 if no sample is in the far field. + // (use the CoC of dilated tile max depth as proxy) + tileClass.needsFar = WaveActiveAnyTrue(dilatedCocSigned.y < 1); + + tileClass.colorOnly = WaveActiveAllTrue(dilatedCocSigned.x - dilatedCocSigned.y < 0.5); +#elif FFX_GLSL + // as above + tileClass.needsNear = subgroupAny(dilatedCocSigned.x > -1); + tileClass.needsFar = subgroupAny(dilatedCocSigned.y < 1); + tileClass.colorOnly = subgroupAll(dilatedCocSigned.x - dilatedCocSigned.y < 0.5); +#endif + + return tileClass; +} + +/// Blur pass entry point. Runs in 8x8x1 thread groups and computes transient near and far outputs. +/// +/// @param pixel Coordinate of the pixel (SV_DispatchThreadID) +/// @param halfImageSize Resolution of the source image (half resolution) in pixels +/// @ingroup FfxGPUDof +void FfxDofBlur(FfxUInt32x2 pixel, FfxUInt32x2 halfImageSize) +{ + FfxDofResetMaxTileRadius(); + + FfxDofInputState ins; + FfxDofTileClass tileClass = FfxDofPrepareTile(pixel, ins); + ins.imageSize = halfImageSize; + + // initialize accumulators + FfxDofAccumulators acc; + acc.prevBucket.color = FfxFloat32x4(0, 0, 0, 0); + acc.prevBucket.ringCovg = 0; + acc.prevBucket.radius = 0; + acc.prevBucket.sampleCount = 0; + + FfxFloat32 centerWeight = FfxDofWeight(ins, ins.centerCoc); + FfxFloat32 centerCovg = FfxDofCoverage(ins, ins.centerCoc); + + FfxFloat32x4 centerColor = FfxFloat32x4(FfxDofLoadInput(pixel).rgb, 1); + acc.nearColor = FfxFloat32x4(0, 0, 0, 0); + acc.fillColor = FfxFloat32x4(0, 0, 0, 0); + + if (ins.nearField) + { + // for near field: adjust center weight to cover everything beyond innermost ring + // radius of innermost ring: + FfxFloat32 innerRingRad = max(1, ins.tileCoc * ffxReciprocal(ins.nRings) - pow(2, ins.mipLevel)); + FfxFloat32 nearCenterWeight = innerRingRad * innerRingRad; + + // if center radius < 1px, split the center color between near and fill + FfxFloat32 nearPart = ffxSaturate(ins.centerCoc), fillPart = 1 - nearPart; + acc.nearColor = centerColor * centerWeight * nearCenterWeight * nearPart; + acc.fillColor = centerColor * fillPart; + } + + if (tileClass.needsNear && tileClass.needsFar) + { + FfxDofProcessNearFar(ins, acc); + } + else if (tileClass.needsNear) + { + if (tileClass.colorOnly) + FfxDofProcessNearColorOnly(ins, acc); + else + FfxDofProcessNearOnly(ins, acc); + } + else if (tileClass.needsFar) + { + if (tileClass.colorOnly) + FfxDofProcessFarColorOnly(ins, acc); + else + FfxDofProcessFarOnly(ins, acc); + } + else // if (!tileClass.needsFar && !tileClass.needsNear) + { + FfxDofStoreFar(pixel, FfxHalfOpt4(FfxDofLoadInput(pixel).rgb, 1)); + FfxDofStoreNear(pixel, FfxHalfOpt4(0, 0, 0, 0)); + return; + } + + // process center + acc.currBucket.ringCovg = ins.nearField ? 0 : centerCovg; + acc.currBucket.color = ins.nearField ? FfxFloat32x4(0, 0, 0, 0) : centerColor * centerWeight; + acc.currBucket.radius = 0; + acc.currBucket.sampleCount = 1; + FfxDofMergeBuckets(acc, 1); + + if (ins.nearField) + { + acc.prevBucket.color += acc.fillColor; + } + FfxFloat32 fgOpacity = (!tileClass.needsFar && tileClass.colorOnly) ? 1.0 : + ffxSaturate(acc.nearColor.a / (FfxDofWeight(ins, ins.tileCoc) * ins.nSamples)); + + FfxFloat32x4 ffTarget = acc.prevBucket.color / acc.prevBucket.color.a; + FfxFloat32x4 ffOutput = !any(isnan(ffTarget)) ? ffTarget : FfxFloat32x4(0, 0, 0, 0); + FfxFloat32x3 nfTarget = acc.nearColor.rgb / acc.nearColor.a; + FfxFloat32x4 nfOutput = FfxFloat32x4(!any(isnan(nfTarget)) ? nfTarget : FfxFloat32x3(0, 0, 0), fgOpacity); + + FfxDofStoreFar(pixel, FfxHalfOpt4(ffOutput)); + FfxDofStoreNear(pixel, FfxHalfOpt4(nfOutput)); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_callbacks_glsl.h new file mode 100644 index 00000000..d74e84e5 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_callbacks_glsl.h @@ -0,0 +1,282 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_dof_resources.h" +#include "ffx_core.h" + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(FFX_DOF_BIND_CB_DOF) + layout (set = 0, binding = FFX_DOF_BIND_CB_DOF, std140) uniform cbDOF_t + { + FfxFloat32 cocScale; + FfxFloat32 cocBias; + FfxUInt32x2 inputSizeHalf; + FfxUInt32x2 inputSize; + FfxFloat32x2 inputSizeHalfRcp; + FfxFloat32 cocLimit; + FfxUInt32 maxRings; + #define FFX_DOF_CONSTANT_BUFFER_1_SIZE 10 // Number of 32-bit values. This must be kept in sync with the cbDOF size. + } cbDOF; +#endif + +FfxFloat32 CocScale() +{ + return cbDOF.cocScale; +} + +FfxFloat32 CocBias() +{ + return cbDOF.cocBias; +} + +FfxUInt32x2 InputSizeHalf() +{ + return cbDOF.inputSizeHalf; +} + +FfxUInt32x2 InputSize() +{ + return cbDOF.inputSize; +} + +FfxFloat32x2 InputSizeHalfRcp() +{ + return cbDOF.inputSizeHalfRcp; +} + +FfxFloat32 CocLimit() +{ + return cbDOF.cocLimit; +} + +FfxUInt32 MaxRings() +{ + return cbDOF.maxRings; +} + +layout (set = 0, binding = 1000) +uniform sampler LinearSampler; +layout (set = 0, binding = 1001) +uniform sampler PointSampler; + +#if FFX_HALF +#define FFX_DOF_HALF_OPT_LAYOUT rgba16f +#else // #if FFX_HALF +#define FFX_DOF_HALF_OPT_LAYOUT rgba32f +#endif // #if FFX_HALF #else + +// SRVs +#if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) + layout (set = 0, binding = FFX_DOF_BIND_SRV_INPUT_DEPTH) + uniform texture2D r_input_depth; +#endif +#if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) + layout (set = 0, binding = FFX_DOF_BIND_SRV_INPUT_COLOR) + uniform texture2D r_input_color; +#endif +#if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) + layout (set = 0, binding = FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) + uniform texture2D r_internal_bilat_color; +#endif +#if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) + layout (set = 0, binding = FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) + uniform texture2D r_internal_dilated_radius; +#endif + +// UAVs +#if defined(FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR) + layout (set = 0, binding = FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR, FFX_DOF_HALF_OPT_LAYOUT) + uniform image2D rw_internal_bilat_color[4]; +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) + layout (set = 0, binding = FFX_DOF_BIND_UAV_INTERNAL_RADIUS, rg32f) + uniform image2D rw_internal_radius; +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS) + layout (set = 0, binding = FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS, rg32f) + uniform image2D rw_internal_dilated_radius; +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) + layout (set = 0, binding = FFX_DOF_BIND_UAV_INTERNAL_NEAR, FFX_DOF_HALF_OPT_LAYOUT) + uniform image2D rw_internal_near; +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) + layout (set = 0, binding = FFX_DOF_BIND_UAV_INTERNAL_FAR, FFX_DOF_HALF_OPT_LAYOUT) + uniform image2D rw_internal_far; +#endif +#if defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR) + layout (set = 0, binding = FFX_DOF_BIND_UAV_OUTPUT_COLOR, rgba32f) + uniform image2D rw_output_color; +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) + layout (set = 0, binding = FFX_DOF_BIND_UAV_INTERNAL_GLOBALS, std430) + coherent buffer DofGlobalVars_t { uint maxTileRad; } rw_internal_globals; +#endif + +#include "ffx_dof_common.h" + +#if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) +FfxHalfOpt4 FfxDofLoadSource(FfxInt32x2 tex) +{ + return FfxHalfOpt4(texelFetch(sampler2D(r_input_color, LinearSampler), tex, 0)); +} +#endif // #if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR) +void FfxDofStoreBilatMip(FfxUInt32 mip, FfxInt32x2 tex, FfxHalfOpt4 value) +{ + imageStore(rw_internal_bilat_color[mip], tex, value); +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR) + +#if defined(FFX_DOF_BIND_CB_DOF) +FfxFloat32 FfxDofGetCoc(FfxFloat32 depth) +{ + // clamped for perf reasons + return clamp(CocScale() * depth + CocBias(), -CocLimit(), CocLimit()); +} +#endif // #if defined(FFX_DOF_BIND_CB_DOF) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS) +void FfxDofStoreDilatedRadius(FfxUInt32x2 coord, FfxFloat32x2 dilatedMinMax) +{ + imageStore(rw_internal_dilated_radius, ivec2(coord), vec4(dilatedMinMax, 0, 0)); +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS) + +#if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) +#if defined(FFX_DOF_BIND_CB_DOF) +FfxFloat32x2 FfxDofSampleDilatedRadius(FfxUInt32x2 coord) +{ + return textureLod(sampler2D(r_internal_dilated_radius, LinearSampler), vec2(coord) * InputSizeHalfRcp(), 0).rg; +} +#endif // #if defined(FFX_DOF_BIND_CB_DOF) + +FfxFloat32x2 FfxDofLoadDilatedRadius(FfxUInt32x2 coord) +{ + return texelFetch(sampler2D(r_internal_dilated_radius, LinearSampler), ivec2(coord), 0).rg; +} +#endif // #if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) + +#if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) +FfxHalfOpt4 FfxDofLoadInput(FfxUInt32x2 coord) +{ + return FfxHalfOpt4(texelFetch(sampler2D(r_internal_bilat_color, LinearSampler), ivec2(coord), 0)); +} + +#if defined(FFX_DOF_BIND_CB_DOF) +FfxHalfOpt4 FfxDofSampleInput(FfxFloat32x2 coord, FfxUInt32 mip) +{ + return FfxHalfOpt4(textureLod(sampler2D(r_internal_bilat_color, PointSampler), coord, mip)); +} +#endif // #if defined(FFX_DOF_BIND_CB_DOF) +#endif // #if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) + +#if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) +FfxFloat32x4 FfxDofGatherDepth(FfxFloat32x2 coord) +{ + return textureGather(sampler2D(r_input_depth, LinearSampler), coord); +} + +FfxFloat32 FfxDofLoadFullDepth(FfxUInt32x2 coord) +{ + return texelFetch(sampler2D(r_input_depth, LinearSampler), ivec2(coord), 0).r; +} +#endif // #if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) +void FfxDofStoreNear(FfxUInt32x2 coord, FfxHalfOpt4 color) +{ + imageStore(rw_internal_near, ivec2(coord), color); +} + +FfxHalfOpt4 FfxDofLoadNear(FfxUInt32x2 coord) +{ + return FfxHalfOpt4(imageLoad(rw_internal_near, ivec2(coord))); +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) +void FfxDofStoreFar(FfxUInt32x2 coord, FfxHalfOpt4 color) +{ + imageStore(rw_internal_far, ivec2(coord), color); +} + +FfxHalfOpt4 FfxDofLoadFar(FfxUInt32x2 coord) +{ + return FfxHalfOpt4(imageLoad(rw_internal_far, ivec2(coord))); +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) +void FfxDofAccumMaxTileRadius(FfxUInt32 radius) +{ + atomicMax(rw_internal_globals.maxTileRad, radius); +} + +FfxUInt32 FfxDofGetMaxTileRadius() +{ + return rw_internal_globals.maxTileRad; +} + +void FfxDofResetMaxTileRadius() +{ + rw_internal_globals.maxTileRad = 0; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) +void FfxDofStoreTileRadius(FfxUInt32x2 tile, FfxFloat32x2 radius) +{ + imageStore(rw_internal_radius, ivec2(tile), vec4(radius, 0, 0)); +} + +FfxFloat32x2 FfxDofLoadTileRadius(FfxUInt32x2 tile) +{ + return imageLoad(rw_internal_radius, ivec2(tile)).rg; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) + +#if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) +FfxFloat32x4 FfxDofLoadFullInput(FfxUInt32x2 coord) +{ + return texelFetch(sampler2D(r_input_color, LinearSampler), ivec2(coord), 0); +} +#elif (defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR)) && FFX_DOF_OPTION_COMBINE_IN_PLACE +FfxFloat32x4 FfxDofLoadFullInput(FfxUInt32x2 coord) +{ + return imageLoad(rw_output_color, ivec2(coord)); +} +#endif // #if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) + +#if defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR) +void FfxDofStoreOutput(FfxUInt32x2 coord, FfxFloat32x4 color) +{ + imageStore(rw_output_color, ivec2(coord), color); +} +#endif // #if defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_callbacks_hlsl.h new file mode 100644 index 00000000..4e3dd94e --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_callbacks_hlsl.h @@ -0,0 +1,322 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_dof_resources.h" +#include "ffx_core.h" +#include "ffx_dof_common.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_DOF_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_DOF_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_DOF_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(FFX_DOF_BIND_CB_DOF) + cbuffer cbDOF : FFX_DOF_DECLARE_CB(FFX_DOF_BIND_CB_DOF) + { + FfxFloat32 cocScale; + FfxFloat32 cocBias; + FfxUInt32x2 inputSizeHalf; + FfxUInt32x2 inputSize; + FfxFloat32x2 inputSizeHalfRcp; + FfxFloat32 cocLimit; + FfxUInt32 maxRings; + #define FFX_DOF_CONSTANT_BUFFER_1_SIZE 10 // Number of 32-bit values. This must be kept in sync with the cbDOF size. + }; +#else +#define cocScale 0 +#define cocBias 0 +#define inputSizeHalf 0 +#define inputSize 0 +#define inputSizeHalfRcp 0 +#define cocLimit 0 +#define maxRings 0 +#endif + +#define FFX_DOF_ROOTSIG_STRINGIFY(p) FFX_DOF_ROOTSIG_STR(p) +#define FFX_DOF_ROOTSIG_STR(p) #p +#define FFX_DOF_ROOTSIG [RootSignature("DescriptorTable(UAV(u0, numDescriptors = " FFX_DOF_ROOTSIG_STRINGIFY(FFX_DOF_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_DOF_ROOTSIG_STRINGIFY(FFX_DOF_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_NEVER, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK), " \ + "StaticSampler(s1, filter = FILTER_MIN_MAG_MIP_POINT, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_NEVER, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK)" )] + +#if defined(FFX_DOF_EMBED_ROOTSIG) +#define FFX_DOF_EMBED_ROOTSIG_CONTENT FFX_DOF_ROOTSIG +#else +#define FFX_DOF_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_SPD_EMBED_ROOTSIG + +FfxFloat32 CocScale() +{ + return cocScale; +} + +FfxFloat32 CocBias() +{ + return cocBias; +} + +FfxUInt32x2 InputSizeHalf() +{ + return inputSizeHalf; +} + +FfxUInt32x2 InputSize() +{ + return inputSize; +} + +FfxFloat32x2 InputSizeHalfRcp() +{ + return inputSizeHalfRcp; +} + +FfxFloat32 CocLimit() +{ + return cocLimit; +} + +FfxUInt32 MaxRings() +{ + return maxRings; +} + +SamplerState LinearSampler : register(s0); +SamplerState PointSampler : register(s1); + +// SRVs +#if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) + Texture2D r_input_depth : FFX_DOF_DECLARE_SRV(FFX_DOF_BIND_SRV_INPUT_DEPTH); +#endif +#if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) + Texture2D r_input_color : FFX_DOF_DECLARE_SRV(FFX_DOF_BIND_SRV_INPUT_COLOR); +#endif +#if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) + Texture2D r_internal_bilat_color : FFX_DOF_DECLARE_SRV(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR); +#endif +#if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) + Texture2D r_internal_dilated_radius : FFX_DOF_DECLARE_SRV(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS); +#endif + +// UAVs +#if defined(FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR) + RWTexture2D rw_internal_bilat_color[4] : FFX_DOF_DECLARE_UAV(FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR); +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) + RWTexture2D rw_internal_radius : FFX_DOF_DECLARE_UAV(FFX_DOF_BIND_UAV_INTERNAL_RADIUS); +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS) + RWTexture2D rw_internal_dilated_radius : FFX_DOF_DECLARE_UAV(FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS); +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) + RWTexture2D rw_internal_near : FFX_DOF_DECLARE_UAV(FFX_DOF_BIND_UAV_INTERNAL_NEAR); +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) + RWTexture2D rw_internal_far : FFX_DOF_DECLARE_UAV(FFX_DOF_BIND_UAV_INTERNAL_FAR); +#endif +#if defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR) + RWTexture2D rw_output_color : FFX_DOF_DECLARE_UAV(FFX_DOF_BIND_UAV_OUTPUT_COLOR); +#endif +#if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) + struct DofGlobalVars { uint maxTileRad; }; + globallycoherent RWStructuredBuffer rw_internal_globals : FFX_DOF_DECLARE_UAV(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS); +#endif + +#if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) +FfxHalfOpt4 FfxDofLoadSource(FfxInt32x2 tex) +{ + return FfxHalfOpt4(r_input_color[tex]); +} +#endif // #if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR) +void FfxDofStoreBilatMip(FfxUInt32 mip, FfxInt32x2 tex, FfxHalfOpt4 value) +{ + rw_internal_bilat_color[mip][tex] = value; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_BILAT_COLOR) + +FfxFloat32 FfxDofGetCoc(FfxFloat32 depth) +{ + // clamped for perf reasons + return clamp(CocScale() * depth + CocBias(), -CocLimit(), CocLimit()); +} + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS) +void FfxDofStoreDilatedRadius(FfxUInt32x2 coord, FfxFloat32x2 dilatedMinMax) +{ + rw_internal_dilated_radius[coord] = dilatedMinMax; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_DILATED_RADIUS) + +#if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) +FfxFloat32x2 FfxDofSampleDilatedRadius(FfxUInt32x2 coord) +{ + return r_internal_dilated_radius.SampleLevel(LinearSampler, float2(coord) * InputSizeHalfRcp(), 0); +} +#endif // #if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) + +#if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) +FfxFloat32x2 FfxDofLoadDilatedRadius(FfxUInt32x2 coord) +{ + return r_internal_dilated_radius[coord]; +} +#endif // #if defined(FFX_DOF_BIND_SRV_INTERNAL_DILATED_RADIUS) + +#if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) +FfxHalfOpt4 FfxDofLoadInput(FfxUInt32x2 coord) +{ + return r_internal_bilat_color[coord]; +} +#endif // #if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) + +#if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) +FfxHalfOpt4 FfxDofSampleInput(FfxFloat32x2 coord, FfxUInt32 mip) +{ + return r_internal_bilat_color.SampleLevel(PointSampler, coord, mip); +} +#endif // #if defined(FFX_DOF_BIND_SRV_INTERNAL_BILAT_COLOR) + +#if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) +FfxFloat32x4 FfxDofGatherDepth(FfxFloat32x2 coord) +{ + return r_input_depth.GatherRed(LinearSampler, coord); +} +#endif // #if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) + +#if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) +FfxFloat32 FfxDofLoadFullDepth(FfxUInt32x2 coord) +{ + return r_input_depth[coord]; +} +#endif // #if defined(FFX_DOF_BIND_SRV_INPUT_DEPTH) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) +void FfxDofStoreNear(FfxUInt32x2 coord, FfxHalfOpt4 color) +{ + rw_internal_near[coord] = color; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) +FfxHalfOpt4 FfxDofLoadNear(FfxUInt32x2 coord) +{ + return rw_internal_near[coord]; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_NEAR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) +void FfxDofStoreFar(FfxUInt32x2 coord, FfxHalfOpt4 color) +{ + rw_internal_far[coord] = color; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) +FfxHalfOpt4 FfxDofLoadFar(FfxUInt32x2 coord) +{ + return rw_internal_far[coord]; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_FAR) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) +void FfxDofAccumMaxTileRadius(FfxUInt32 radius) +{ + uint dummy; + InterlockedMax(rw_internal_globals[0].maxTileRad, radius, dummy); +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) +FfxUInt32 FfxDofGetMaxTileRadius() +{ + return rw_internal_globals[0].maxTileRad; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) +void FfxDofResetMaxTileRadius() +{ + rw_internal_globals[0].maxTileRad = 0; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_GLOBALS) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) +void FfxDofStoreTileRadius(FfxUInt32x2 tile, FfxFloat32x2 radius) +{ + rw_internal_radius[tile] = radius; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) + +#if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) +FfxFloat32x2 FfxDofLoadTileRadius(FfxUInt32x2 tile) +{ + return rw_internal_radius[tile]; +} +#endif // #if defined(FFX_DOF_BIND_UAV_INTERNAL_RADIUS) + +FfxFloat32x4 FfxDofLoadFullInput(FfxUInt32x2 coord) +{ +#if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) + return r_input_color[coord]; +#elif (defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR)) && FFX_DOF_OPTION_COMBINE_IN_PLACE + return rw_output_color[coord]; +#endif // #if defined(FFX_DOF_BIND_SRV_INPUT_COLOR) + return 0; +} + +#if defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR) +void FfxDofStoreOutput(FfxUInt32x2 coord, FfxFloat32x4 color) +{ + rw_output_color[coord] = color; +} +#endif // #if defined(FFX_DOF_BIND_UAV_OUTPUT_COLOR) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_common.h new file mode 100644 index 00000000..f95585e9 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_common.h @@ -0,0 +1,142 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DOF_COMMON_H +#define FFX_DOF_COMMON_H + +/// @defgroup FfxGPUDof FidelityFX DOF +/// FidelityFX Depth of Field GPU documentation +/// +/// @ingroup FfxGPUEffects + +// Constants - these are fixed magic numbers. Changes likely require changing code. + +/// The width/height of tiles storing per-tile min and max CoC. The blur pass needs to run +/// at a compatible tile size, so that the assumption that min/max CoC is uniform for all threads in +/// a thread group holds. +/// +/// @ingroup FfxGPUDof +FFX_STATIC const FfxUInt32 FFX_DOF_DEPTH_TILE_SIZE = 8; + +// Default settings +#ifndef FFX_DOF_OPTION_MAX_MIP +/// The number of mips that should be generated in the color downsample pass +/// +/// @ingroup FfxGPUDof +#define FFX_DOF_OPTION_MAX_MIP 4 +#endif + +#ifndef FFX_DOF_OPTION_MAX_RING_MERGE_LOG +/// The base-2 logarithm of the number of blur kernel rings that may be merged, if possible. +/// +/// Setting this to zero disables ring merging. +/// +/// Values above 1 are technically valid, but are known to cause a visible quality drop. +/// +/// @ingroup FfxGPUDof +#define FFX_DOF_OPTION_MAX_RING_MERGE_LOG 1 +#endif + +#define FFX_DOF_MAX_RING_MERGE (1 << FFX_DOF_OPTION_MAX_RING_MERGE_LOG) + +// optional 16-bit types +#if FFX_HLSL +#if FFX_HALF +typedef FfxFloat16 FfxHalfOpt; +typedef FfxFloat16x2 FfxHalfOpt2; +typedef FfxFloat16x3 FfxHalfOpt3; +typedef FfxFloat16x4 FfxHalfOpt4; +#else +typedef FfxFloat32 FfxHalfOpt; +typedef FfxFloat32x2 FfxHalfOpt2; +typedef FfxFloat32x3 FfxHalfOpt3; +typedef FfxFloat32x4 FfxHalfOpt4; +#endif +#elif FFX_GLSL +#if FFX_HALF +#define FfxHalfOpt FfxFloat16 +#define FfxHalfOpt2 FfxFloat16x2 +#define FfxHalfOpt3 FfxFloat16x3 +#define FfxHalfOpt4 FfxFloat16x4 +#else +#define FfxHalfOpt FfxFloat32 +#define FfxHalfOpt2 FfxFloat32x2 +#define FfxHalfOpt3 FfxFloat32x3 +#define FfxHalfOpt4 FfxFloat32x4 +#endif +#endif + +// unroll macros with count argument +#if FFX_HLSL +#define FFX_DOF_UNROLL_N(_n) [unroll(_n)] +#define FFX_DOF_UNROLL [unroll] +#elif FFX_GLSL // #if FFX_HLSL +#define FFX_DOF_UNROLL_N(_n) +// enable unrolling loops +#extension GL_EXT_control_flow_attributes : enable + +#if GL_EXT_control_flow_attributes +#define FFX_DOF_UNROLL [[unroll]] +#else +#define FFX_DOF_UNROLL +#endif // #if GL_EXT_control_flow_attributes +#endif // #if FFX_HLSL #elif FFX_GLSL + +// ReadLaneFirst +#if FFX_HLSL +#define ffxWaveReadLaneFirst WaveReadLaneFirst +#elif FFX_GLSL +#define ffxWaveReadLaneFirst subgroupBroadcastFirst +#endif // #if FFX_GLSL + +// Callback declarations +FfxFloat32 FfxDofGetCoc(FfxFloat32 depth); // returns circle of confusion radius in pixels (at half-res). Sign indicates near-field (positive) or far-field (negative). +void FfxDofStoreDilatedRadius(FfxUInt32x2 coord, FfxFloat32x2 dilatedMinMax); +FfxFloat32x2 FfxDofSampleDilatedRadius(FfxUInt32x2 coord); // returns the dilated min and max depth for a pixel coordinate. Should be bilinearly interpolated! +FfxFloat32x2 FfxDofLoadDilatedRadius(FfxUInt32x2 coord); // returns the dilated depth for a *tile* coordinate without interpolation +FfxHalfOpt4 FfxDofLoadInput(FfxUInt32x2 coord); // returns input rgb and (in alpha) CoC in pixels from the most detailed mip (which is half-res) +FfxHalfOpt4 FfxDofSampleInput(FfxFloat32x2 coord, FfxUInt32 mip); // returns input rgb and (in alpha) CoC in pixels. +FfxFloat32x4 FfxDofGatherDepth(FfxFloat32x2 coord); // returns 4 input depth values in a quad, must use sampler with coordinate clamping +void FfxDofStoreNear(FfxUInt32x2 coord, FfxHalfOpt4 color); // stores the near color output from the blur pass +void FfxDofStoreFar(FfxUInt32x2 coord, FfxHalfOpt4 color); // stores the far color output from the blur pass +FfxHalfOpt4 FfxDofLoadNear(FfxUInt32x2 coord); // loads the near color value +FfxHalfOpt4 FfxDofLoadFar(FfxUInt32x2 coord); // loads the far color value +void FfxDofAccumMaxTileRadius(FfxUInt32 radius); // stores the global maximum dilation radius using an atomic max operation +FfxUInt32 FfxDofGetMaxTileRadius(); // gets the global maximum dilation radius +void FfxDofResetMaxTileRadius(); // sets max dilation radius back to zero +void FfxDofStoreTileRadius(FfxUInt32x2 tile, FfxFloat32x2 radius); // stores the min/max signed radius for a tile in the tile map +FfxFloat32x2 FfxDofLoadTileRadius(FfxUInt32x2 tile); // loads the min/max depth for a tile +FfxFloat32x4 FfxDofLoadFullInput(FfxUInt32x2 coord); // returns full resultion input rgba (alpha is ignored) +FfxFloat32 FfxDofLoadFullDepth(FfxUInt32x2 coord); // returns full resolution depth +void FfxDofStoreOutput(FfxUInt32x2 coord, FfxFloat32x4 color); // writes the final output + +// Common helper functions +FfxUInt32x2 FfxDofPxRadToTiles(FfxFloat32x2 rPx) +{ + return FfxUInt32x2(ceil(rPx / (FFX_DOF_DEPTH_TILE_SIZE / 2))) + 1; // +1 to handle diagonals & bilinear +} + +FfxFloat32x2 FfxDofGetCoc2(FfxFloat32x2 depths) +{ + return FfxFloat32x2(FfxDofGetCoc(depths.x), FfxDofGetCoc(depths.y)); +} +#endif // #ifndef FFX_DOF_COMMON_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_composite.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_composite.h new file mode 100644 index 00000000..c3402cc4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_composite.h @@ -0,0 +1,629 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" +#include "ffx_dof_common.h" + +#if FFX_HALF +FfxFloat16 FfxMed9(FfxFloat16 a, FfxFloat16 b, FfxFloat16 c, + FfxFloat16 d, FfxFloat16 e, FfxFloat16 f, + FfxFloat16 g, FfxFloat16 h, FfxFloat16 i) +{ + // TODO (perf): compiler does not use med3 at all for these + FfxFloat16 hi_lo = ffxMax3Half(ffxMin3Half(a, b, c), ffxMin3Half(d, e, f), ffxMin3Half(g, h, i)); + FfxFloat16 mi_mi = ffxMed3Half(ffxMed3Half(a, b, c), ffxMed3Half(d, e, f), ffxMed3Half(g, h, i)); + FfxFloat16 lo_hi = ffxMin3Half(ffxMax3Half(a, b, c), ffxMax3Half(d, e, f), ffxMax3Half(g, h, i)); + return ffxMed3Half(hi_lo, mi_mi, lo_hi); +} +#endif + +FfxFloat32 FfxMed9(FfxFloat32 a, FfxFloat32 b, FfxFloat32 c, + FfxFloat32 d, FfxFloat32 e, FfxFloat32 f, + FfxFloat32 g, FfxFloat32 h, FfxFloat32 i) +{ + // TODO (perf): compiler does not use med3 at all for these + FfxFloat32 hi_lo = ffxMax3(ffxMin3(a, b, c), ffxMin3(d, e, f), ffxMin3(g, h, i)); + FfxFloat32 mi_mi = ffxMed3(ffxMed3(a, b, c), ffxMed3(d, e, f), ffxMed3(g, h, i)); + FfxFloat32 lo_hi = ffxMin3(ffxMax3(a, b, c), ffxMax3(d, e, f), ffxMax3(g, h, i)); + return ffxMed3(hi_lo, mi_mi, lo_hi); +} + +FfxFloat32 FfxCubicSpline(FfxFloat32 x) +{ + // evaluate cubic spline -2x^3 + 3x^2 + return x * x * (3 - 2 * x); +} + +FFX_STATIC const FfxUInt32 FFX_DOF_COMBINE_TILE_SIZE = 8; +FFX_STATIC const FfxUInt32 FFX_DOF_COMBINE_ROW_PITCH = FFX_DOF_COMBINE_TILE_SIZE + 3; // Add +2 for 3x3 filter margin, +1 on one side for bilinear filter. +FFX_STATIC const FfxUInt32 FFX_DOF_COMBINE_AREA = FFX_DOF_COMBINE_ROW_PITCH * FFX_DOF_COMBINE_ROW_PITCH; + +#if FFX_HALF +FFX_GROUPSHARED FfxUInt32 FfxDofLDSLuma[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxUInt32 FfxDofLDSNearRG[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxUInt32 FfxDofLDSNearBA[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxUInt32 FfxDofLDSFarRG[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxUInt32 FfxDofLDSFarBA[FFX_DOF_COMBINE_AREA]; + +FFX_GROUPSHARED FfxUInt32 FfxDofLDSFullColorRG[18*18]; +FFX_GROUPSHARED FfxFloat16 FfxDofLDSFullColorB[18*18]; +#else // #if FFX_HALF +FFX_GROUPSHARED FfxFloat32 FfxDofLDSNearLuma[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFarLuma[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSNearR[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSNearG[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSNearB[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSNearA[FFX_DOF_COMBINE_AREA]; + +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFarR[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFarG[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFarB[FFX_DOF_COMBINE_AREA]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFarA[FFX_DOF_COMBINE_AREA]; + +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFullColorR[18*18]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFullColorG[18*18]; +FFX_GROUPSHARED FfxFloat32 FfxDofLDSFullColorB[18*18]; +#endif // #if FFX_HALF #else + +#if FFX_HALF +FfxFloat16x4 FfxDofGetIntermediateNearColor(FfxUInt32 idx) +{ + FfxFloat16x2 rg = FFX_UINT32_TO_FLOAT16X2(FfxDofLDSNearRG[idx]); + FfxFloat16x2 ba = FFX_UINT32_TO_FLOAT16X2(FfxDofLDSNearBA[idx]); + return FfxFloat16x4(rg, ba); +} +FfxFloat16x4 FfxDofGetIntermediateFarColor(FfxUInt32 idx) +{ + FfxFloat16x2 rg = FFX_UINT32_TO_FLOAT16X2(FfxDofLDSFarRG[idx]); + FfxFloat16x2 ba = FFX_UINT32_TO_FLOAT16X2(FfxDofLDSFarBA[idx]); + return FfxFloat16x4(rg, ba); +} +FfxFloat16x3 FfxDofGetIntFullColor(FfxUInt32 idx) +{ + FfxFloat16x2 rg = FFX_UINT32_TO_FLOAT16X2(FfxDofLDSFullColorRG[idx]); + FfxFloat16 b = FfxDofLDSFullColorB[idx]; + return FfxFloat16x3(rg, b); +} +void FfxDofSetIntNearLuma(FfxUInt32 idx, FfxFloat16 luma) +{ + FfxFloat16x2 unpacked = FFX_UINT32_TO_FLOAT16X2(FfxDofLDSLuma[idx]); + unpacked.x = luma; + FfxDofLDSLuma[idx] = FFX_FLOAT16X2_TO_UINT32(unpacked); +} +void FfxDofSetIntFarLuma(FfxUInt32 idx, FfxFloat16 luma) +{ + FfxFloat16x2 unpacked = FFX_UINT32_TO_FLOAT16X2(FfxDofLDSLuma[idx]); + unpacked.y = luma; + FfxDofLDSLuma[idx] = FFX_FLOAT16X2_TO_UINT32(unpacked); +} + +void FfxDofSetIntermediateNearColor(FfxUInt32 idx, FfxFloat16x4 col) +{ + FfxDofLDSNearRG[idx] = FFX_FLOAT16X2_TO_UINT32(col.rg); + FfxDofLDSNearBA[idx] = FFX_FLOAT16X2_TO_UINT32(col.ba); +} +void FfxDofSetIntermediateFarColor(FfxUInt32 idx, FfxFloat16x4 col) +{ + FfxDofLDSFarRG[idx] = FFX_FLOAT16X2_TO_UINT32(col.rg); + FfxDofLDSFarBA[idx] = FFX_FLOAT16X2_TO_UINT32(col.ba); +} +void FfxDofSetIntFullColor(FfxUInt32 idx, FfxFloat16x3 col) +{ + FfxDofLDSFullColorRG[idx] = FFX_FLOAT16X2_TO_UINT32(col.rg); + FfxDofLDSFullColorB[idx] = col.b; +} +FfxFloat16 FfxDofGetIntermediateNearAlpha(FfxUInt32 idx, FfxUInt32 offX, FfxUInt32 offY) +{ + return FfxDofGetIntermediateNearColor(idx + offX + FFX_DOF_COMBINE_ROW_PITCH * offY).a; +} +FfxFloat16 FfxDofGetIntermediateFarAlpha(FfxUInt32 idx) +{ + return FfxDofGetIntermediateFarColor(idx).a; +} +#else // #if FFX_HALF +FfxFloat32x4 FfxDofGetIntermediateNearColor(FfxUInt32 idx) +{ + return FfxFloat32x4(FfxDofLDSNearR[idx], FfxDofLDSNearG[idx], FfxDofLDSNearB[idx], FfxDofLDSNearA[idx]); +} +FfxFloat32x4 FfxDofGetIntermediateFarColor(FfxUInt32 idx) +{ + return FfxFloat32x4(FfxDofLDSFarR[idx], FfxDofLDSFarG[idx], FfxDofLDSFarB[idx], FfxDofLDSFarA[idx]); +} +FfxFloat32x3 FfxDofGetIntFullColor(FfxUInt32 idx) +{ + return FfxFloat32x3(FfxDofLDSFullColorR[idx], FfxDofLDSFullColorG[idx], FfxDofLDSFullColorB[idx]); +} +void FfxDofSetIntNearLuma(FfxUInt32 idx, FfxFloat32 luma) +{ + FfxDofLDSNearLuma[idx] = luma; +} +void FfxDofSetIntFarLuma(FfxUInt32 idx, FfxFloat32 luma) +{ + FfxDofLDSFarLuma[idx] = luma; +} + +void FfxDofSetIntermediateNearColor(FfxUInt32 idx, FfxFloat32x4 col) +{ + FfxDofLDSNearR[idx] = col.r; + FfxDofLDSNearG[idx] = col.g; + FfxDofLDSNearB[idx] = col.b; + FfxDofLDSNearA[idx] = col.a; +} +void FfxDofSetIntermediateFarColor(FfxUInt32 idx, FfxFloat32x4 col) +{ + FfxDofLDSFarR[idx] = col.r; + FfxDofLDSFarG[idx] = col.g; + FfxDofLDSFarB[idx] = col.b; + FfxDofLDSFarA[idx] = col.a; +} +void FfxDofSetIntFullColor(FfxUInt32 idx, FfxFloat32x3 col) +{ + FfxDofLDSFullColorR[idx] = col.r; + FfxDofLDSFullColorG[idx] = col.g; + FfxDofLDSFullColorB[idx] = col.b; +} +FfxFloat32 FfxDofGetIntermediateNearAlpha(FfxUInt32 idx, FfxUInt32 offX, FfxUInt32 offY) +{ + return FfxDofGetIntermediateNearColor(idx + offX + FFX_DOF_COMBINE_ROW_PITCH * offY).a; +} +FfxFloat32 FfxDofGetIntermediateFarAlpha(FfxUInt32 idx) +{ + return FfxDofGetIntermediateFarColor(idx).a; +} +#endif // #if FFX_HALF #else + +FfxHalfOpt3 FfxDofBlur3x3(FfxUInt32 baseIdx) +{ + // kernel coefficients based on coverage of a circle in a 3x3 grid + const FfxHalfOpt CORNER = FfxHalfOpt(0.5453); + const FfxHalfOpt SIDE = FfxHalfOpt(0.9717); + + // accumulate convolution + const FfxHalfOpt weights_sum = FfxHalfOpt(1) + FfxHalfOpt(4) * CORNER + FfxHalfOpt(4) * SIDE; + FfxHalfOpt3 sum = FfxDofGetIntFullColor(baseIdx + 19) + + CORNER * (FfxDofGetIntFullColor(baseIdx) + FfxDofGetIntFullColor(baseIdx + 2) + FfxDofGetIntFullColor(baseIdx + 36) + FfxDofGetIntFullColor(baseIdx + 38)) + + SIDE * (FfxDofGetIntFullColor(baseIdx + 1) + FfxDofGetIntFullColor(baseIdx + 18) + FfxDofGetIntFullColor(baseIdx + 20) + FfxDofGetIntFullColor(baseIdx + 37)); + + return sum / weights_sum; +} + +FfxHalfOpt4 FfxDofFinalCombineColors(FfxUInt32x2 coord, FfxUInt32x2 relCoord, FfxHalfOpt4 bg, FfxHalfOpt4 fg, FfxHalfOpt minFgW) +{ + FfxFloat32 d = FfxDofLoadFullDepth(coord); + FfxUInt32 baseIdx = relCoord.x + 18 * relCoord.y; + FfxHalfOpt3 full = FfxHalfOpt3(FfxDofGetIntFullColor(baseIdx + 19)); + FfxHalfOpt3 fixBlurred = FfxHalfOpt3(FfxDofBlur3x3(baseIdx)); + + // expand background around edges + if (bg.a > FfxHalfOpt(0)) bg.rgb /= bg.a; + // if any FG sample has zero weight, the interpolation is invalid. + if (minFgW == FfxHalfOpt(0)) fg.a = FfxHalfOpt(0); + FfxHalfOpt c = FfxHalfOpt(2) * FfxHalfOpt(abs(FfxDofGetCoc(d))); // double it for full-res pixels + FfxHalfOpt c1 = ffxSaturate(c - FfxHalfOpt(0.5)); // lerp factor for full vs. fixed 1.5px blur + FfxHalfOpt c2 = ffxSaturate(c - FfxHalfOpt(1.5)); // lerp factor for prev vs. quarter res + if (bg.a == FfxHalfOpt(0)) c2 = FfxHalfOpt(0); + FfxHalfOpt3 combinedColor = ffxLerp(full, fixBlurred, c1); + combinedColor = ffxLerp(combinedColor, bg.rgb, c2); + + combinedColor = ffxLerp(combinedColor, fg.rgb, FfxHalfOpt(FfxCubicSpline(fg.a))); + return FfxHalfOpt4(combinedColor, 1); +} + +#if FFX_HALF +FfxFloat16 FfxDofGetLDSNearLuma(FfxUInt32 idx, FfxUInt32 offX, FfxUInt32 offY) +{ + return FFX_UINT32_TO_FLOAT16X2(FfxDofLDSLuma[idx + offX + FFX_DOF_COMBINE_ROW_PITCH * offY]).x; +} +FfxFloat16 FfxDofGetLDSFarLuma(FfxUInt32 idx, FfxUInt32 offX, FfxUInt32 offY) +{ + return FFX_UINT32_TO_FLOAT16X2(FfxDofLDSLuma[idx + offX + FFX_DOF_COMBINE_ROW_PITCH * offY]).y; +} +#else // #if FFX_HALF +FfxFloat32 FfxDofGetLDSNearLuma(FfxUInt32 idx, FfxUInt32 offX, FfxUInt32 offY) +{ + return FfxDofLDSNearLuma[idx + offX + FFX_DOF_COMBINE_ROW_PITCH * offY]; +} +FfxFloat32 FfxDofGetLDSFarLuma(FfxUInt32 idx, FfxUInt32 offX, FfxUInt32 offY) +{ + return FfxDofLDSFarLuma[idx + offX + FFX_DOF_COMBINE_ROW_PITCH * offY]; +} +#endif // #if FFX_HALF #else + +FfxHalfOpt4 FfxDofFilterFF(FfxUInt32 baseIdx) +{ + // get the median of the surrounding 3x3 area of luma values + FfxHalfOpt med_luma = FfxMed9( + FfxDofGetLDSFarLuma(baseIdx, 0, 0), FfxDofGetLDSFarLuma(baseIdx, 1, 0), FfxDofGetLDSFarLuma(baseIdx, 2, 0), + FfxDofGetLDSFarLuma(baseIdx, 0, 1), FfxDofGetLDSFarLuma(baseIdx, 1, 1), FfxDofGetLDSFarLuma(baseIdx, 2, 1), + FfxDofGetLDSFarLuma(baseIdx, 0, 2), FfxDofGetLDSFarLuma(baseIdx, 1, 2), FfxDofGetLDSFarLuma(baseIdx, 2, 2)); + + FfxUInt32 idx = baseIdx + FFX_DOF_COMBINE_ROW_PITCH + 1; + FfxHalfOpt3 col = FfxDofGetIntermediateFarColor(idx).rgb; + FfxHalfOpt lumaFactor = clamp(med_luma / FfxDofGetLDSFarLuma(idx, 0, 0), FfxHalfOpt(0), FfxHalfOpt(2)); + // corner fix: if color pixel is on a corner (has 5 black pixels as neighbor), don't reduce color. + if (med_luma == FfxHalfOpt(0)) lumaFactor = FfxHalfOpt(1); + return FfxHalfOpt4(col * lumaFactor, FfxDofGetIntermediateFarAlpha(idx)); +} + +FfxHalfOpt4 FfxDofFilterNF(FfxUInt32 baseIdx) +{ + // Get 3x3 median luma + FfxHalfOpt med_luma = FfxMed9( + FfxDofGetLDSNearLuma(baseIdx, 0, 0), FfxDofGetLDSNearLuma(baseIdx, 1, 0), FfxDofGetLDSNearLuma(baseIdx, 2, 0), + FfxDofGetLDSNearLuma(baseIdx, 0, 1), FfxDofGetLDSNearLuma(baseIdx, 1, 1), FfxDofGetLDSNearLuma(baseIdx, 2, 1), + FfxDofGetLDSNearLuma(baseIdx, 0, 2), FfxDofGetLDSNearLuma(baseIdx, 1, 2), FfxDofGetLDSNearLuma(baseIdx, 2, 2)); + FfxHalfOpt avg_alpha = FfxHalfOpt(ffxReciprocal(9.0)) * ( + FfxDofGetIntermediateNearAlpha(baseIdx, 0, 0) + FfxDofGetIntermediateNearAlpha(baseIdx, 1, 0) + FfxDofGetIntermediateNearAlpha(baseIdx, 2, 0) + + FfxDofGetIntermediateNearAlpha(baseIdx, 0, 1) + FfxDofGetIntermediateNearAlpha(baseIdx, 1, 1) + FfxDofGetIntermediateNearAlpha(baseIdx, 2, 1) + + FfxDofGetIntermediateNearAlpha(baseIdx, 0, 2) + FfxDofGetIntermediateNearAlpha(baseIdx, 1, 2) + FfxDofGetIntermediateNearAlpha(baseIdx, 2, 2)); + + FfxUInt32 idx = baseIdx + FFX_DOF_COMBINE_ROW_PITCH + 1; + if (FfxDofGetIntermediateNearAlpha(idx, 0, 0) < 0.01) + { + // center has zero weight, grab one of the corner colors + FfxUInt32 maxIdx = baseIdx; + if (FfxDofGetLDSNearLuma(baseIdx, 2, 0) > FfxDofGetLDSNearLuma(maxIdx, 0, 0)) maxIdx = baseIdx + 2; + if (FfxDofGetLDSNearLuma(baseIdx, 0, 2) > FfxDofGetLDSNearLuma(maxIdx, 0, 0)) maxIdx = baseIdx + 2 * FFX_DOF_COMBINE_ROW_PITCH; + if (FfxDofGetLDSNearLuma(baseIdx, 2, 2) > FfxDofGetLDSNearLuma(maxIdx, 0, 0)) maxIdx = baseIdx + 2 * FFX_DOF_COMBINE_ROW_PITCH + 2; + idx = maxIdx; + } + FfxHalfOpt3 col = FfxDofGetIntermediateNearColor(idx).rgb; + FfxHalfOpt lumaFactor = med_luma > FfxHalfOpt(0) ? clamp(med_luma / FfxDofGetLDSNearLuma(idx, 0, 0), FfxHalfOpt(0), FfxHalfOpt(2)) : FfxHalfOpt(1.0); + return FfxHalfOpt4(col.rgb * lumaFactor, avg_alpha); +} + +FfxFloat32x2 FfxDofGetTileRadius(FfxUInt32x2 group) +{ + // need to read 4 values + FfxUInt32x2 tile = group * 2; + FfxFloat32x2 a = FfxDofLoadDilatedRadius(tile); + FfxFloat32x2 b = FfxDofLoadDilatedRadius(tile + FfxUInt32x2(0, 1)); + FfxFloat32x2 c = FfxDofLoadDilatedRadius(tile + FfxUInt32x2(1, 0)); + FfxFloat32x2 d = FfxDofLoadDilatedRadius(tile + FfxUInt32x2(1, 1)); + FfxFloat32 near = max(a.x, ffxMax3(b.x, c.x, d.x)); + FfxFloat32 far = min(a.y, ffxMin3(b.y, c.y, d.y)); + return FfxFloat32x2(near, far); +} + +void FfxDofCombineSharpOnly(FfxUInt32x2 group, FfxUInt32x2 thread) +{ +#if !defined(FFX_DOF_OPTION_COMBINE_IN_PLACE) || !FFX_DOF_OPTION_COMBINE_IN_PLACE + FfxUInt32x2 base = 16 * group; + FfxDofStoreOutput(base + thread + FfxUInt32x2(0, 0), FfxDofLoadFullInput(base + thread + FfxUInt32x2(0, 0))); + FfxDofStoreOutput(base + thread + FfxUInt32x2(8, 0), FfxDofLoadFullInput(base + thread + FfxUInt32x2(8, 0))); + FfxDofStoreOutput(base + thread + FfxUInt32x2(0, 8), FfxDofLoadFullInput(base + thread + FfxUInt32x2(0, 8))); + FfxDofStoreOutput(base + thread + FfxUInt32x2(8, 8), FfxDofLoadFullInput(base + thread + FfxUInt32x2(8, 8))); +#endif +} + +void FfxDofFetchFullColor(FfxUInt32x2 gid, FfxUInt32 gix, FfxUInt32x2 imageSize) +{ + FFX_DOF_UNROLL + for (FfxUInt32 iter = 0; iter < 6; iter++) + { + FfxUInt32 iFetch = (gix + iter * 64) % (18 * 18); + FfxInt32x2 coord = FfxInt32x2(gid * 16) + FfxInt32x2(iFetch % 18 - 1, iFetch / 18 - 1); + coord = clamp(coord, FfxInt32x2(0, 0), FfxInt32x2(imageSize) - FfxInt32x2(1, 1)); + FfxHalfOpt3 color = FfxHalfOpt3(FfxDofLoadFullInput(coord).rgb); + FfxDofSetIntFullColor(iFetch, color); + } +} + +void FfxDofSwizQuad(inout FfxUInt32x2 a, inout FfxUInt32x2 b, inout FfxUInt32x2 c, inout FfxUInt32x2 d) +{ + // Input: four color values in a quad. + // Re-orders the output to a swizzled format for better store throughput. + // This maps from one quad per lane, stored in four separate registers to + // four 16x2 regions (one per register). + // This is done in two steps. First, permute the values among the lanes + // using WaveReadLaneAt. Second, swap values between registers. + + // This only works for lane counts >= 32, do nothing otherwise for compatibility +#if FFX_HLSL + if (WaveGetLaneCount() < 32) return; + + FfxUInt32 lane = WaveGetLaneIndex(); + // index for A, switch bits around 43210 -> 10432. + FfxUInt32 idxA = ((lane & 3) << 3) + (lane >> 2); + // Adding 8/16/24 for B/C/D makes each variable offset from the previous by one slot. + a = WaveReadLaneAt(a, (lane & ~31) + (idxA + 0) % 32); + b = WaveReadLaneAt(b, (lane & ~31) + (idxA + 8) % 32); + c = WaveReadLaneAt(c, (lane & ~31) + (idxA + 16) % 32); + d = WaveReadLaneAt(d, (lane & ~31) + (idxA + 24) % 32); +#elif FFX_GLSL + if (gl_SubgroupSize < 32) return; + + FfxUInt32 lane = gl_SubgroupInvocationID; + FfxUInt32 idxA = ((lane & 3) << 3) + (lane >> 2); + a = subgroupShuffle(a, (lane & ~31) + (idxA + 0) % 32); + b = subgroupShuffle(b, (lane & ~31) + (idxA + 8) % 32); + c = subgroupShuffle(c, (lane & ~31) + (idxA + 16) % 32); + d = subgroupShuffle(d, (lane & ~31) + (idxA + 24) % 32); +#endif + + // Now, for each lane, a/b/c/d contain one value from each of the four 16x2 lines. + // And each group of 4 lanes have values from the same quads. + // We just need to shuffle between abcd, so that each set of 4 lanes contains one quad per variable. + // General idea: rotate by (lane % 4) variables. + if ((lane & 1) != 0) + { + // rotate A->B->C->D->A + FfxUInt32x2 tmp = d; + d = c; + c = b; + b = a; + a = tmp; + } + if ((lane & 2) != 0) + { + // swap A<->C and B<->D + FfxUInt32x2 tmp = a; + a = c; + c = tmp; + tmp = b; + b = d; + d = tmp; + } +} + +#if FFX_HALF +void FfxDofSwizQuad(inout FfxFloat16x4 a, inout FfxFloat16x4 b, inout FfxFloat16x4 c, inout FfxFloat16x4 d) +{ + // Same as above. + FfxUInt32x2 packed_a = FFX_FLOAT16X4_TO_UINT32X2(a); + FfxUInt32x2 packed_b = FFX_FLOAT16X4_TO_UINT32X2(b); + FfxUInt32x2 packed_c = FFX_FLOAT16X4_TO_UINT32X2(c); + FfxUInt32x2 packed_d = FFX_FLOAT16X4_TO_UINT32X2(d); + FfxDofSwizQuad(packed_a, packed_b, packed_c, packed_d); + a = FFX_UINT32X2_TO_FLOAT16X4(packed_a); + b = FFX_UINT32X2_TO_FLOAT16X4(packed_b); + c = FFX_UINT32X2_TO_FLOAT16X4(packed_c); + d = FFX_UINT32X2_TO_FLOAT16X4(packed_d); +} +#else // #if FFX_HALF +void FfxDofSwizQuad(inout FfxFloat32x4 a, inout FfxFloat32x4 b, inout FfxFloat32x4 c, inout FfxFloat32x4 d) +{ + // Same as above. + FfxUInt32x2 a0 = ffxAsUInt32(a.xy); + FfxUInt32x2 a1 = ffxAsUInt32(a.zw); + FfxUInt32x2 b0 = ffxAsUInt32(b.xy); + FfxUInt32x2 b1 = ffxAsUInt32(b.zw); + FfxUInt32x2 c0 = ffxAsUInt32(c.xy); + FfxUInt32x2 c1 = ffxAsUInt32(c.zw); + FfxUInt32x2 d0 = ffxAsUInt32(d.xy); + FfxUInt32x2 d1 = ffxAsUInt32(d.zw); + FfxDofSwizQuad(a0, b0, c0, d0); + FfxDofSwizQuad(a1, b1, c1, d1); + a = FfxFloat32x4(ffxAsFloat(a0), ffxAsFloat(a1)); + b = FfxFloat32x4(ffxAsFloat(b0), ffxAsFloat(b1)); + c = FfxFloat32x4(ffxAsFloat(c0), ffxAsFloat(c1)); + d = FfxFloat32x4(ffxAsFloat(d0), ffxAsFloat(d1)); +} +#endif // #if FFX_HALF #else + +void FfxDofCombineFarOnly(FfxUInt32x2 id, FfxUInt32x2 gtID, FfxUInt32x2 gid, FfxUInt32 gix, FfxUInt32x2 imageSize) +{ + // TODO: Is this the best configuration for fetching? + FFX_DOF_UNROLL_N(2) + for (FfxUInt32 iter = 0; iter < 2; iter++) + { + // HACK: with the modulo, we will re-fetch some pixels, but might be better than waiting twice (latency-wise) + // which is what the compiler would do if it had to possibly branch + FfxUInt32 iFetch = (gix + iter * 64) % FFX_DOF_COMBINE_AREA; + FfxInt32x2 coord = FfxInt32x2(gid * FFX_DOF_COMBINE_TILE_SIZE) + FfxInt32x2(iFetch % FFX_DOF_COMBINE_ROW_PITCH - 1, iFetch / FFX_DOF_COMBINE_ROW_PITCH - 1); + coord = clamp(coord, FfxInt32x2(0, 0), FfxInt32x2(imageSize - 1)); + FfxHalfOpt4 ffColor = FfxHalfOpt4(FfxDofLoadFar(coord)); + + // calculate and store luma for later median calculation + FfxHalfOpt ffLuma = FfxHalfOpt(0.2126) * ffColor.r + FfxHalfOpt(0.7152) * ffColor.g + FfxHalfOpt(0.0722) * ffColor.b; + FfxDofSetIntFarLuma(iFetch, ffLuma); + FfxDofSetIntermediateFarColor(iFetch, ffColor); + } + + FFX_GROUP_MEMORY_BARRIER; + + const FfxUInt32 baseIdx = gtID.x + gtID.y * FFX_DOF_COMBINE_ROW_PITCH; + // one extra round of filtering needs to be done around the edge, this index maps to that. + // TODO: This is ugly and possibly slow + const FfxUInt32 baseIdx2 = (FFX_DOF_COMBINE_TILE_SIZE + FFX_DOF_COMBINE_ROW_PITCH * gix + (gix / (FFX_DOF_COMBINE_TILE_SIZE + 1)) * ((gix - FFX_DOF_COMBINE_TILE_SIZE) * (-FFX_DOF_COMBINE_ROW_PITCH + 1) - (FFX_DOF_COMBINE_TILE_SIZE + 1))) % FFX_DOF_COMBINE_AREA; + + FfxHalfOpt4 ffColor = FfxHalfOpt4(0, 0, 0, 0), ffColor2 = FfxHalfOpt4(0, 0, 0, 0); + // far-field post-filter + ffColor = FfxDofFilterFF(baseIdx); + ffColor2 = gix < (2 * FFX_DOF_COMBINE_TILE_SIZE + 1) ? FfxDofFilterFF(baseIdx2) : FfxHalfOpt4(0, 0, 0, 0); + + FFX_GROUP_MEMORY_BARRIER; + + // write out colors for interpolation + FfxDofSetIntermediateFarColor(baseIdx, ffColor); + if (gix < (2 * FFX_DOF_COMBINE_TILE_SIZE + 1)) + { + FfxDofSetIntermediateFarColor(baseIdx2, ffColor2); + } + + FFX_GROUP_MEMORY_BARRIER; + + // upscaling + FfxHalfOpt4 ffTR = FfxHalfOpt4(0, 0, 0, 0), ffBL = FfxHalfOpt4(0, 0, 0, 0), ffBR = FfxHalfOpt4(0, 0, 0, 0); + ffTR = FfxHalfOpt(0.5) * ffColor + FfxHalfOpt(0.5) * FfxDofGetIntermediateFarColor(baseIdx + 1); + ffBL = FfxHalfOpt(0.5) * ffColor + FfxHalfOpt(0.5) * FfxDofGetIntermediateFarColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH); + ffBR = FfxHalfOpt(0.5) * ffTR + FfxHalfOpt(0.25) * FfxDofGetIntermediateFarColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH) + FfxHalfOpt(0.25) * FfxDofGetIntermediateFarColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH + 1); + + // top-left pixel + FfxUInt32x2 coord = 2 * id; + FfxUInt32x2 relCoord = 2 * gtID; + FfxUInt32x2 coordA = coord; + FfxHalfOpt4 colA = FfxDofFinalCombineColors(coord, relCoord, ffColor, FfxHalfOpt4(0, 0, 0, 0), FfxHalfOpt(0)); + // top-right + coord.x++; + relCoord.x++; + FfxUInt32x2 coordB = coord; + FfxHalfOpt4 colB = FfxDofFinalCombineColors(coord, relCoord, ffTR, FfxHalfOpt4(0, 0, 0, 0), FfxHalfOpt(0)); + // bottom-right + coord.y++; + relCoord.y++; + FfxUInt32x2 coordC = coord; + FfxHalfOpt4 colC = FfxDofFinalCombineColors(coord, relCoord, ffBR, FfxHalfOpt4(0, 0, 0, 0), FfxHalfOpt(0)); + // bottom-left + coord.x--; + relCoord.x--; + FfxUInt32x2 coordD = coord; + FfxHalfOpt4 colD = FfxDofFinalCombineColors(coord, relCoord, ffBL, FfxHalfOpt4(0, 0, 0, 0), FfxHalfOpt(0)); + + // TODO: Navi3 should make swizzling unnecessary because it supports write-combining clauses + FfxDofSwizQuad(colA, colB, colC, colD); + FfxDofSwizQuad(coordA, coordB, coordC, coordD); + + FfxDofStoreOutput(coordA, colA); + FfxDofStoreOutput(coordB, colB); + FfxDofStoreOutput(coordC, colC); + FfxDofStoreOutput(coordD, colD); +} + +void FfxDofCombineAll(FfxUInt32x2 id, FfxUInt32x2 gtID, FfxUInt32x2 gid, FfxUInt32 gix, FfxUInt32x2 imageSize) +{ + // TODO: Is this the best configuration for fetching? + FFX_DOF_UNROLL_N(2) + for (FfxUInt32 iter = 0; iter < 2; iter++) + { + // HACK: with the modulo, we will re-fetch some pixels, but might be better than waiting twice (latency-wise) + // which is what the compiler would do if it had to possibly branch + FfxUInt32 iFetch = (gix + iter * 64) % FFX_DOF_COMBINE_AREA; + FfxInt32x2 coord = FfxInt32x2(gid * FFX_DOF_COMBINE_TILE_SIZE) + FfxInt32x2(iFetch % FFX_DOF_COMBINE_ROW_PITCH - 1, iFetch / FFX_DOF_COMBINE_ROW_PITCH - 1); + coord = clamp(coord, FfxInt32x2(0, 0), FfxInt32x2(imageSize - 1)); + FfxHalfOpt4 ffColor = FfxHalfOpt4(FfxDofLoadFar(coord)); + FfxHalfOpt4 nfColor = FfxHalfOpt4(FfxDofLoadNear(coord)); + + // calculate and store luma for later median calculation + FfxHalfOpt ffLuma = FfxHalfOpt(0.2126) * ffColor.r + FfxHalfOpt(0.7152) * ffColor.g + FfxHalfOpt(0.0722) * ffColor.b; + FfxHalfOpt nfLuma = FfxHalfOpt(0.2126) * nfColor.r + FfxHalfOpt(0.7152) * nfColor.g + FfxHalfOpt(0.0722) * nfColor.b; + FfxDofSetIntFarLuma(iFetch, ffLuma); + FfxDofSetIntNearLuma(iFetch, nfLuma); + FfxDofSetIntermediateFarColor(iFetch, ffColor); + FfxDofSetIntermediateNearColor(iFetch, nfColor); + } + + FFX_GROUP_MEMORY_BARRIER; + + const FfxUInt32 baseIdx = gtID.x + gtID.y * FFX_DOF_COMBINE_ROW_PITCH; + // one extra round of filtering needs to be done around the edge, this index maps to that. + // TODO: same as above, ugly and slow. + const FfxUInt32 baseIdx2 = (FFX_DOF_COMBINE_TILE_SIZE + FFX_DOF_COMBINE_ROW_PITCH * gix + (gix / (FFX_DOF_COMBINE_TILE_SIZE + 1)) * ((gix - FFX_DOF_COMBINE_TILE_SIZE) * (-FFX_DOF_COMBINE_ROW_PITCH + 1) - (FFX_DOF_COMBINE_TILE_SIZE + 1))) % FFX_DOF_COMBINE_AREA; + + FfxHalfOpt4 ffColor = FfxHalfOpt4(0, 0, 0, 0), ffColor2 = FfxHalfOpt4(0, 0, 0, 0), nfColor = FfxHalfOpt4(0, 0, 0, 0), nfColor2 = FfxHalfOpt4(0, 0, 0, 0); + // far-field post-filter + ffColor = FfxDofFilterFF(baseIdx); + ffColor2 = gix < (2 * FFX_DOF_COMBINE_TILE_SIZE + 1) ? FfxDofFilterFF(baseIdx2) : FfxHalfOpt4(0, 0, 0, 0); + + // near-field post-filter + nfColor = FfxDofFilterNF(baseIdx); + nfColor2 = gix < (2 * FFX_DOF_COMBINE_TILE_SIZE + 1) ? FfxDofFilterNF(baseIdx2) : FfxHalfOpt4(0, 0, 0, 0); + + FFX_GROUP_MEMORY_BARRIER; + + // write out colors for interpolation + FfxDofSetIntermediateNearColor(baseIdx, nfColor); + FfxDofSetIntermediateFarColor(baseIdx, ffColor); + if (gix < (2 * FFX_DOF_COMBINE_TILE_SIZE + 1)) + { + FfxDofSetIntermediateNearColor(baseIdx2, nfColor2); + FfxDofSetIntermediateFarColor(baseIdx2, ffColor2); + } + + FFX_GROUP_MEMORY_BARRIER; + + // if any FG sample has zero weight, the interpolation is invalid. + // take the min and invalidate if zero (see CombineColors) + FfxHalfOpt fgMinW = min(nfColor.a, FfxHalfOpt(ffxMin3(FfxDofGetIntermediateNearAlpha(baseIdx, 1, 0), FfxDofGetIntermediateNearAlpha(baseIdx, 0, 1), FfxDofGetIntermediateNearAlpha(baseIdx, 1, 1)))); + + // upscaling + FfxHalfOpt4 nfTR = FfxHalfOpt4(0, 0, 0, 0), nfBL = FfxHalfOpt4(0, 0, 0, 0), nfBR = FfxHalfOpt4(0, 0, 0, 0); + nfTR = FfxHalfOpt(0.5) * nfColor + FfxHalfOpt(0.5) * FfxDofGetIntermediateNearColor(baseIdx + 1); + nfBL = FfxHalfOpt(0.5) * nfColor + FfxHalfOpt(0.5) * FfxDofGetIntermediateNearColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH); + nfBR = FfxHalfOpt(0.5) * nfTR + FfxHalfOpt(0.25) * FfxDofGetIntermediateNearColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH) + FfxHalfOpt(0.25) * FfxDofGetIntermediateNearColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH + 1); + + FfxHalfOpt4 ffTR = FfxHalfOpt4(0, 0, 0, 0), ffBL = FfxHalfOpt4(0, 0, 0, 0), ffBR = FfxHalfOpt4(0, 0, 0, 0); + ffTR = FfxHalfOpt(0.5) * ffColor + FfxHalfOpt(0.5) * FfxDofGetIntermediateFarColor(baseIdx + 1); + ffBL = FfxHalfOpt(0.5) * ffColor + FfxHalfOpt(0.5) * FfxDofGetIntermediateFarColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH); + ffBR = FfxHalfOpt(0.5) * ffTR + FfxHalfOpt(0.25) * FfxDofGetIntermediateFarColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH) + FfxHalfOpt(0.25) * FfxDofGetIntermediateFarColor(baseIdx + FFX_DOF_COMBINE_ROW_PITCH + 1); + + // top-left pixel + FfxUInt32x2 coord = 2 * id; + FfxUInt32x2 relCoord = 2 * gtID; + FfxUInt32x2 coordA = coord; + FfxHalfOpt4 colA = FfxDofFinalCombineColors(coord, relCoord, ffColor, nfColor, fgMinW); + // top-right + coord.x += 1; + relCoord.x += 1; + FfxUInt32x2 coordB = coord; + FfxHalfOpt4 colB = FfxDofFinalCombineColors(coord, relCoord, ffTR, nfTR, fgMinW); + // bottom-right + coord.y++; + relCoord.y++; + FfxUInt32x2 coordC = coord; + FfxHalfOpt4 colC = FfxDofFinalCombineColors(coord, relCoord, ffBR, nfBR, fgMinW); + // bottom-left + coord.x--; + relCoord.x--; + FfxUInt32x2 coordD = coord; + FfxHalfOpt4 colD = FfxDofFinalCombineColors(coord, relCoord, ffBL, nfBL, fgMinW); + + FfxDofSwizQuad(colA, colB, colC, colD); + FfxDofSwizQuad(coordA, coordB, coordC, coordD); + + FfxDofStoreOutput(coordA, colA); + FfxDofStoreOutput(coordB, colB); + FfxDofStoreOutput(coordC, colC); + FfxDofStoreOutput(coordD, colD); +} + +/// Entry point. Meant to run in 8x8 threads and writes 16x16 output pixels. +/// +/// @param threadID SV_DispatchThreadID.xy +/// @param groupThreadID SV_GroupThreadID.xy +/// @param group SV_GroupID.xy +/// @param index SV_GroupIndex +/// @param halfImageSize Pixel size of the input (half resolution) +/// @param fullImageSize Pixel size of the output (full resolution) +/// @ingroup FfxGPUDof +void FfxDofCombineHalfRes(FfxUInt32x2 threadID, FfxUInt32x2 groupThreadID, FfxUInt32x2 group, FfxUInt32 index, FfxUInt32x2 halfImageSize, FfxUInt32x2 fullImageSize) +{ + // classify tile + FfxFloat32x2 tileCoc = FfxDofGetTileRadius(group); + FfxBoolean nearNeeded = tileCoc.x > -1.025; // halved due to resolution change, then: 2px = threshold in main pass + small inaccuracy bias + FfxBoolean allSharp = max(abs(tileCoc.x), abs(tileCoc.y)) < 0.25; + + if (allSharp) + { + FfxDofCombineSharpOnly(group, groupThreadID); + } + else if (!nearNeeded) + { + FfxDofFetchFullColor(group, index, fullImageSize); + FfxDofCombineFarOnly(threadID, groupThreadID, group, index, halfImageSize); + } + else + { + FfxDofFetchFullColor(group, index, fullImageSize); + FfxDofCombineAll(threadID, groupThreadID, group, index, halfImageSize); + } +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_dilate_depth.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_dilate_depth.h new file mode 100644 index 00000000..5cd88769 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_dilate_depth.h @@ -0,0 +1,101 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" +#include "ffx_dof_common.h" + +// helper function for dilating depth values circularly +void FfxDofDilateStep(inout FfxFloat32 cMin, inout FfxFloat32 cMax, FfxInt32 x, FfxInt32 y, FfxInt32 r, FfxUInt32x2 size, FfxUInt32x2 dtID) +{ + if (x * x + y * y <= r * r) + { + // inside the circle + FfxInt32x2 tileID = FfxInt32x2(dtID) + FfxInt32x2(x, y); + if (tileID.x >= 0 && tileID.y >= 0 && tileID.x < size.x && tileID.y < size.y) + { + FfxFloat32x2 localCocRange = FfxDofLoadTileRadius(tileID); + FfxUInt32x2 tileRad = FfxDofPxRadToTiles(abs(localCocRange)); + + // seperately for min/max: check radius in range to spread and update + if (x * x + y * y < tileRad.x * tileRad.x) + { + // using max for cMin and min for cMax, since cMin actually refers to the CoC for the minimal view depth + // NOT the minimum signed CoC value + cMin = max(cMin, localCocRange.x); + } + if (x * x + y * y < tileRad.y * tileRad.y) + { + cMax = min(cMax, localCocRange.y); + } + } + } +} + +/// Entry point for the dilate pass. +/// +/// @param tile Coordinate of the tile to run on (SV_DispatchThreadID) +/// @param imageSize Resolution of the depth image (full resolution) +/// @ingroup FfxGPUDof +void FfxDofDilate(FfxUInt32x2 tile, FfxUInt32x2 imageSize) +{ + // dilate scatter-as-gather using global max radius + + // reject out-of-bounds on border + FfxUInt32x2 size = FfxUInt32x2(ceil(FfxFloat32x2(imageSize) / FfxFloat32(FFX_DOF_DEPTH_TILE_SIZE))); + + // get CoC and depth + FfxInt32 rMax = FfxInt32(FfxDofGetMaxTileRadius()); + FfxFloat32x2 cocMinMax = FfxDofLoadTileRadius(tile); + FfxFloat32x2 absCocMinMax = abs(cocMinMax); + + FfxFloat32 cMin = cocMinMax.x; + FfxFloat32 cMax = cocMinMax.y; + + // Very extremes of the kernel done explicity. Expanding the square (loop below) to this radius would + // waste time with a lot of failed radius checks. + if (rMax > 0) + { + FfxDofDilateStep(cMin, cMax, -rMax, 0, rMax, size, tile); + FfxDofDilateStep(cMin, cMax, rMax, 0, rMax, size, tile); + FfxDofDilateStep(cMin, cMax, 0, -rMax, rMax, size, tile); + FfxDofDilateStep(cMin, cMax, 0, rMax, rMax, size, tile); + } + // Gather the rest as a square shape. Likely faster than trying to make a circle. + for (FfxInt32 x = -rMax + 1; x < rMax; x++) + { + for (FfxInt32 y = -rMax + 1; y < rMax; y++) + { + // Zero offset is the starting point, don't need to handle again. + if (x == 0 && y == 0) continue; + FfxDofDilateStep(cMin, cMax, x, y, rMax, size, tile); + } + } + + // If center tile is in-focus enough: ignore far-field dilation (it is occluded). + if (absCocMinMax.x < 0.5 && absCocMinMax.y < 0.5) + { + cMax = cocMinMax.y; + } + + // store min and max + FfxDofStoreDilatedRadius(tile, FfxFloat32x2(cMin, cMax)); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_downsample_color.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_downsample_color.h new file mode 100644 index 00000000..fbaa4151 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_downsample_color.h @@ -0,0 +1,176 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#ifndef FFX_DOF_OPTION_MAX_MIP +#define FFX_DOF_OPTION_MAX_MIP FFX_DOF_INTERNAL_BILAT_MIP_COUNT +#endif + +#if FFX_HALF +#define FFX_SPD_PACKED_ONLY + +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateRG[16][16]; +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateBA[16][16]; + +FfxFloat16x4 SpdLoadSourceImageH(FfxInt32x2 tex, FfxUInt32 slice) +{ + FfxFloat16 d = FfxFloat16(FfxDofLoadFullDepth(tex)); + FfxFloat16 c = FfxFloat16(FfxDofGetCoc(d)); + return FfxFloat16x4(FfxDofLoadSource(tex).rgb, c); +} + +FfxFloat16x4 SpdLoadH(FfxInt32x2 tex, FfxUInt32 slice) +{ + return FfxFloat16x4(0, 0, 0, 0); +} + +void SpdStoreH(FfxInt32x2 pix, FfxFloat16x4 value, FfxUInt32 mip, FfxUInt32 slice) +{ + FfxDofStoreBilatMip(mip, pix, value); +} + +FfxFloat16x4 SpdLoadIntermediateH(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat16x4( + spdIntermediateRG[x][y].x, + spdIntermediateRG[x][y].y, + spdIntermediateBA[x][y].x, + spdIntermediateBA[x][y].y); +} +void SpdStoreIntermediateH(FfxUInt32 x, FfxUInt32 y, FfxFloat16x4 value) +{ + spdIntermediateRG[x][y] = value.xy; + spdIntermediateBA[x][y] = value.zw; +} + +/// Bilateral downsampling function, half-precision version +/// @ingroup FfxGPUDof +FfxFloat16x4 FfxDofDownsampleQuadH(FfxFloat16x4 v0, FfxFloat16x4 v1, FfxFloat16x4 v2, FfxFloat16x4 v3) +{ + FfxFloat16 c0 = v0.a; + FfxFloat16 c1 = v1.a; + FfxFloat16 c2 = v2.a; + FfxFloat16 c3 = v3.a; + FfxFloat16 w1 = ffxSaturate(FfxFloat16(1.0) - abs(c0 - c1)); + FfxFloat16 w2 = ffxSaturate(FfxFloat16(1.0) - abs(c0 - c2)); + FfxFloat16 w3 = ffxSaturate(FfxFloat16(1.0) - abs(c0 - c3)); + FfxFloat16x3 color = v0.rgb + w1 * v1.rgb + w2 * v2.rgb + w3 * v3.rgb; + FfxFloat16 weights = FfxFloat16(1.0) + w1 + w2 + w3; + return FfxFloat16x4(color / weights, c0); +} + +FfxFloat16x4 SpdReduce4H(FfxFloat16x4 v0, FfxFloat16x4 v1, FfxFloat16x4 v2, FfxFloat16x4 v3) +{ + return FfxDofDownsampleQuadH(v0, v1, v2, v3); +} +#else // #if FFX_HALF +#define FFX_SPD_NO_WAVE_OPERATIONS 1 +FFX_GROUPSHARED FfxFloat32 spdIntermediateR[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateG[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateB[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateA[16][16]; + +FfxFloat32x4 SpdLoadSourceImage(FfxInt32x2 tex, FfxUInt32 slice) +{ + FfxFloat32 d = FfxDofLoadFullDepth(tex); + FfxFloat32 c = FfxDofGetCoc(d); + return FfxFloat32x4(FfxDofLoadSource(tex).rgb, c); +} + +FfxFloat32x4 SpdLoad(FfxInt32x2 tex, FfxUInt32 slice) +{ + return FfxFloat32x4(0, 0, 0, 0); +} + +void SpdStore(FfxInt32x2 pix, FfxFloat32x4 value, FfxUInt32 mip, FfxUInt32 slice) +{ + FfxDofStoreBilatMip(mip, pix, value); +} + +FfxFloat32x4 SpdLoadIntermediate(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat32x4( + spdIntermediateR[x][y], + spdIntermediateG[x][y], + spdIntermediateB[x][y], + spdIntermediateA[x][y]); +} +void SpdStoreIntermediate(FfxUInt32 x, FfxUInt32 y, FfxFloat32x4 value) +{ + spdIntermediateR[x][y] = value.r; + spdIntermediateG[x][y] = value.g; + spdIntermediateB[x][y] = value.b; + spdIntermediateA[x][y] = value.a; +} + +/// Bilateral downsampling function, full-precision version +/// @ingroup FfxGPUDof +FfxFloat32x4 FfxDofDownsampleQuad(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3) +{ + FfxFloat32 c0 = v0.a; + FfxFloat32 c1 = v1.a; + FfxFloat32 c2 = v2.a; + FfxFloat32 c3 = v3.a; + FfxFloat32 w1 = ffxSaturate(1.0 - abs(c0 - c1)); + FfxFloat32 w2 = ffxSaturate(1.0 - abs(c0 - c2)); + FfxFloat32 w3 = ffxSaturate(1.0 - abs(c0 - c3)); + FfxFloat32x3 color = v0.rgb + w1 * v1.rgb + w2 * v2.rgb + w3 * v3.rgb; + FfxFloat32 weights = 1.0 + w1 + w2 + w3; + return FfxFloat32x4(color / weights, c0); +} + +FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3) +{ + return FfxDofDownsampleQuad(v0, v1, v2, v3); +} +#endif // #if FFX_HALF #else + +// we only generate 4 mips, so these functions are not needed and never called. +void SpdIncreaseAtomicCounter(FfxUInt32 slice) +{ + /*nothing*/ +} +FfxUInt32 SpdGetAtomicCounter() +{ + return 0; +} +void SpdResetAtomicCounter(FfxUInt32 slice) +{ + /*nothing*/ +} + +#include "spd/ffx_spd.h" + +/// Entry point for the downsample color pass. Uses SPD internally. +/// +/// @param LocalThreadId Thread index in thread group (SV_GroupIndex) +/// @param WorkGroupId Coordinate of the tile (SV_GroupID.xy) +/// @ingroup FfxGPUDof +void DownsampleColor(FfxUInt32 LocalThreadId, FfxUInt32x2 WorkGroupId) +{ +#if FFX_HALF + SpdDownsampleH(WorkGroupId, LocalThreadId, FfxUInt32(FFX_DOF_OPTION_MAX_MIP), FfxUInt32(0), FfxUInt32(0)); +#else + SpdDownsample(WorkGroupId, LocalThreadId, FfxUInt32(FFX_DOF_OPTION_MAX_MIP), FfxUInt32(0), FfxUInt32(0)); +#endif +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_downsample_depth.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_downsample_depth.h new file mode 100644 index 00000000..af59262a --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_downsample_depth.h @@ -0,0 +1,77 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" +#include "ffx_dof_common.h" + +FfxUInt32x2 FfxDofCocRadInTiles(FfxFloat32x2 zMinMax) +{ + FfxFloat32x2 rPx = abs(FfxDofGetCoc2(zMinMax)); + return FfxDofPxRadToTiles(rPx); +} + +FfxUInt32 FfxDofMaxCocInTiles(FfxFloat32x2 zMinMax) +{ + FfxUInt32x2 rTiles = FfxDofCocRadInTiles(zMinMax); + return max(rTiles.x, rTiles.y); +} + +/// Entry point for depth downsample function. SPD is not used for this, +/// since we only need one specific downsampled resolution. +/// +/// @param tile coordinate of the tile to run on (SV_DispatchThreadID) +/// @param imageSize Size of the depth image (full resolution) +/// @ingroup FfxGPUDof +void DownsampleDepth(FfxUInt32x2 tile, FfxUInt32x2 imageSize) +{ + FfxFloat32 minD = 1.0; + FfxFloat32 maxD = 0.0; + + const FfxUInt32x2 coordBase = tile * FFX_DOF_DEPTH_TILE_SIZE; + const FfxFloat32x2 rcpImageSize = ffxReciprocal(FfxFloat32x2(imageSize)); + + for (FfxUInt32 yy = 0; yy < FFX_DOF_DEPTH_TILE_SIZE; yy += 2) + { + for (FfxUInt32 xx = 0; xx < FFX_DOF_DEPTH_TILE_SIZE; xx += 2) + { + FfxUInt32x2 coordInt = coordBase + FfxUInt32x2(xx, yy); + FfxFloat32x2 coord = ffxSaturate(FfxFloat32x2(coordInt) * rcpImageSize); + FfxFloat32x4 d = FfxDofGatherDepth(coord); + + FfxFloat32 lo = min(min(min(d.x, d.y), d.z), d.w); + FfxFloat32 hi = max(max(max(d.x, d.y), d.z), d.w); + minD = min(minD, lo); + maxD = max(maxD, hi); + } + } + +#if FFX_DOF_OPTION_REVERSE_DEPTH + // if Z-buffer is reversed, the nearest Z is the max. + FfxFloat32x2 nearFarDepth = FfxFloat32x2(maxD, minD); +#else + FfxFloat32x2 nearFarDepth = FfxFloat32x2(minD, maxD); +#endif + FfxFloat32x2 coc = FfxDofGetCoc2(nearFarDepth); + FfxUInt32 rTiles = FfxDofMaxCocInTiles(nearFarDepth); + FfxDofAccumMaxTileRadius(rTiles); + FfxDofStoreTileRadius(tile, coc); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_resources.h new file mode 100644 index 00000000..c4d75216 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/dof/ffx_dof_resources.h @@ -0,0 +1,50 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_DOF_RESOURCES_H +#define FFX_DOF_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) +#define FFX_DOF_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_DOF_RESOURCE_IDENTIFIER_INPUT_DEPTH 1 +#define FFX_DOF_RESOURCE_IDENTIFIER_INPUT_COLOR 2 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_BILAT_COLOR 3 // same as MIP0 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_BILAT_COLOR_MIP0 3 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_BILAT_COLOR_MIP1 4 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_BILAT_COLOR_MIP2 5 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_BILAT_COLOR_MIP3 6 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_RADIUS 7 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_DILATED_RADIUS 8 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_NEAR 9 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_FAR 10 +#define FFX_DOF_RESOURCE_IDENTIFIER_OUTPUT_COLOR 11 +#define FFX_DOF_RESOURCE_IDENTIFIER_INTERNAL_GLOBALS 12 + +#define FFX_DOF_RESOURCE_IDENTIFIER_COUNT 13 + +#define FFX_DOF_CONSTANTBUFFER_IDENTIFIER_DOF 0 + +#define FFX_DOF_INTERNAL_BILAT_MIP_COUNT 4 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif //!defined( FFX_DOF_RESOURCES_H ) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/ffx_core_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/ffx_core_glsl.h new file mode 100644 index 00000000..c8dccacd --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/ffx_core_glsl.h @@ -0,0 +1,1916 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup GLSLCore GLSL Core +/// GLSL core defines and functions +/// +/// @ingroup FfxGLSL + +/// A define for abstracting select functionality for pre/post HLSL 21 +/// +/// @ingroup GLSLCore +#define FFX_SELECT(cond, arg1, arg2) cond ? arg1 : arg2 + +/// A define for abstracting shared memory between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_GROUPSHARED shared + +/// A define for abstracting compute memory barriers between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_GROUP_MEMORY_BARRIER groupMemoryBarrier(); barrier() + +/// A define for abstracting compute atomic additions between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_ATOMIC_ADD(x, y) atomicAdd(x, y) + +/// A define for abstracting compute atomic additions between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_ATOMIC_ADD_RETURN(x, y, r) r = atomicAdd(x, y) + +/// A define for abstracting compute atomic OR between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_ATOMIC_OR(x, y) atomicOr(x, y) + +/// A define for abstracting compute atomic min between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_ATOMIC_MIN(x, y) atomicMin(x, y) + +/// A define for abstracting compute atomic max between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_ATOMIC_MAX(x, y) atomicMax(x, y) + +/// A define added to accept static markup on functions to aid CPU/GPU portability of code. +/// +/// @ingroup GLSLCore +#define FFX_STATIC + +/// A define for abstracting loop unrolling between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_UNROLL + +/// A define for abstracting a 'greater than' comparison operator between two types. +/// +/// @ingroup GLSLCore +#define FFX_GREATER_THAN(x, y) greaterThan(x, y) + +/// A define for abstracting a 'greater than or equal' comparison operator between two types. +/// +/// @ingroup GLSLCore +#define FFX_GREATER_THAN_EQUAL(x, y) greaterThanEqual(x, y) + +/// A define for abstracting a 'less than' comparison operator between two types. +/// +/// @ingroup GLSLCore +#define FFX_LESS_THAN(x, y) lessThan(x, y) + +/// A define for abstracting a 'less than or equal' comparison operator between two types. +/// +/// @ingroup GLSLCore +#define FFX_LESS_THAN_EQUAL(x, y) lessThanEqual(x, y) + +/// A define for abstracting an 'equal' comparison operator between two types. +/// +/// @ingroup GLSLCore +#define FFX_EQUAL(x, y) equal(x, y) + +/// A define for abstracting a 'not equal' comparison operator between two types. +/// +/// @ingroup GLSLCore +#define FFX_NOT_EQUAL(x, y) notEqual(x, y) + +/// A define for abstracting matrix multiply operations between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_MATRIX_MULTIPLY(a, b) (a * b) + +/// A define for abstracting vector transformations between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_TRANSFORM_VECTOR(a, b) (a * b) + +/// A define for abstracting modulo operations between shading languages. +/// +/// @ingroup GLSLCore +#define FFX_MODULO(a, b) (mod(a, b)) + +/// Broadcast a scalar value to a 1-dimensional floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_FLOAT32(x) FfxFloat32(x) + +/// Broadcast a scalar value to a 2-dimensional floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_FLOAT32X2(x) FfxFloat32x2(FfxFloat32(x)) + +/// Broadcast a scalar value to a 3-dimensional floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_FLOAT32X3(x) FfxFloat32x3(FfxFloat32(x)) + +/// Broadcast a scalar value to a 4-dimensional floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_FLOAT32X4(x) FfxFloat32x4(FfxFloat32(x)) + +/// Broadcast a scalar value to a 1-dimensional unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_UINT32(x) FfxUInt32(x) + +/// Broadcast a scalar value to a 2-dimensional unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_UINT32X2(x) FfxUInt32x2(FfxUInt32(x)) + +/// Broadcast a scalar value to a 3-dimensional unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_UINT32X3(x) FfxUInt32x3(FfxUInt32(x)) + +/// Broadcast a scalar value to a 4-dimensional unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_UINT32X4(x) FfxUInt32x4(FfxUInt32(x)) + +/// Broadcast a scalar value to a 1-dimensional signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_INT32(x) FfxInt32(x) + +/// Broadcast a scalar value to a 2-dimensional signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_INT32X2(x) FfxInt32x2(FfxInt32(x)) + +/// Broadcast a scalar value to a 3-dimensional signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_INT32X3(x) FfxInt32x3(FfxInt32(x)) + +/// Broadcast a scalar value to a 4-dimensional signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_INT32X4(x) FfxInt32x4(FfxInt32(x)) + +/// Broadcast a scalar value to a 1-dimensional half-precision floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_FLOAT16(x) FFX_MIN16_F(x) + +/// Broadcast a scalar value to a 2-dimensional half-precision floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_FLOAT16X2(x) FFX_MIN16_F2(FFX_MIN16_F(x)) + +/// Broadcast a scalar value to a 3-dimensional half-precision floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_FLOAT16X3(x) FFX_MIN16_F3(FFX_MIN16_F(x)) + +/// Broadcast a scalar value to a 4-dimensional half-precision floating point vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_FLOAT16X4(x) FFX_MIN16_F4(FFX_MIN16_F(x)) + +/// Broadcast a scalar value to a 1-dimensional half-precision unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_UINT16(x) FFX_MIN16_U(x) + +/// Broadcast a scalar value to a 2-dimensional half-precision unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_UINT16X2(x) FFX_MIN16_U2(FFX_MIN16_U(x)) + +/// Broadcast a scalar value to a 3-dimensional half-precision unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_UINT16X3(x) FFX_MIN16_U3(FFX_MIN16_U(x)) + +/// Broadcast a scalar value to a 4-dimensional half-precision unsigned integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_UINT16X4(x) FFX_MIN16_U4(FFX_MIN16_U(x)) + +/// Broadcast a scalar value to a 1-dimensional half-precision signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_INT16(x) FFX_MIN16_I(x) + +/// Broadcast a scalar value to a 2-dimensional half-precision signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_INT16X2(x) FFX_MIN16_I2(FFX_MIN16_I(x)) + +/// Broadcast a scalar value to a 3-dimensional half-precision signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_INT16X3(x) FFX_MIN16_I3(FFX_MIN16_I(x)) + +/// Broadcast a scalar value to a 4-dimensional half-precision signed integer vector. +/// +/// @ingroup GLSLCore +#define FFX_BROADCAST_MIN_INT16X4(x) FFX_MIN16_I4(FFX_MIN16_I(x)) + + #extension GL_EXT_shader_explicit_arithmetic_types : require +#if !defined(FFX_SKIP_EXT) +#if FFX_HALF + #extension GL_EXT_shader_16bit_storage : require +#endif // FFX_HALF + +#if defined(FFX_LONG) + #extension GL_ARB_gpu_shader_int64 : require + #extension GL_NV_shader_atomic_int64 : require +#endif // #if defined(FFX_LONG) + +#if defined(FFX_WAVE) + #extension GL_KHR_shader_subgroup_arithmetic : require + #extension GL_KHR_shader_subgroup_ballot : require + #extension GL_KHR_shader_subgroup_quad : require + #extension GL_KHR_shader_subgroup_shuffle : require +#endif // #if defined(FFX_WAVE) +#endif // #if !defined(FFX_SKIP_EXT) + +// Forward declarations +FfxFloat32 ffxSqrt(FfxFloat32 x); +FfxFloat32x2 ffxSqrt(FfxFloat32x2 x); +FfxFloat32x3 ffxSqrt(FfxFloat32x3 x); +FfxFloat32x4 ffxSqrt(FfxFloat32x4 x); + +/// Interprets the bit pattern of x as a floating-point number. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as a floating-point number. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxAsFloat(FfxUInt32 x) +{ + return uintBitsToFloat(x); +} + +/// Interprets the bit pattern of x as a floating-point number. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as a floating-point number. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxAsFloat(FfxUInt32x2 x) +{ + return uintBitsToFloat(x); +} + +/// Interprets the bit pattern of x as a floating-point number. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as a floating-point number. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxAsFloat(FfxUInt32x3 x) +{ + return uintBitsToFloat(x); +} + +/// Interprets the bit pattern of x as a floating-point number. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as a floating-point number. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxAsFloat(FfxUInt32x4 x) +{ + return uintBitsToFloat(x); +} + +/// Interprets the bit pattern of x as an unsigned integer. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as an unsigned integer. +/// +/// @ingroup GLSLCore +FfxUInt32 ffxAsUInt32(FfxFloat32 x) +{ + return floatBitsToUint(x); +} + +/// Interprets the bit pattern of x as an unsigned integer. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as an unsigned integer. +/// +/// @ingroup GLSLCore +FfxUInt32x2 ffxAsUInt32(FfxFloat32x2 x) +{ + return floatBitsToUint(x); +} + +/// Interprets the bit pattern of x as an unsigned integer. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as an unsigned integer. +/// +/// @ingroup GLSLCore +FfxUInt32x3 ffxAsUInt32(FfxFloat32x3 x) +{ + return floatBitsToUint(x); +} + +/// Interprets the bit pattern of x as an unsigned integer. +/// +/// @param [in] x The input value. +/// +/// @returns +/// The input interpreted as an unsigned integer. +/// +/// @ingroup GLSLCore +FfxUInt32x4 ffxAsUInt32(FfxFloat32x4 x) +{ + return floatBitsToUint(x); +} + +/// Pack 2x32-bit floating point values in a single 32bit value. +/// +/// This function first converts each component of value into their nearest 16-bit floating +/// point representation, and then stores the X and Y components in the lower and upper 16 bits of the +/// 32bit unsigned integer respectively. +/// +/// @param [in] value A 2-dimensional floating point value to convert and pack. +/// +/// @returns +/// A packed 32bit value containing 2 16bit floating point values. +/// +/// @ingroup GLSLCore +FfxUInt32 ffxPackHalf2x16(FfxFloat32x2 value) +{ + return packHalf2x16(value); +} + +/// Convert a 32bit IEEE 754 floating point value to its nearest 16bit equivalent. +/// +/// @param [in] value The value to convert. +/// +/// @returns +/// The nearest 16bit equivalent of value. +/// +/// @ingroup GLSLCore +FfxUInt32 ffxF32ToF16(FfxFloat32 value) +{ + return packHalf2x16(FfxFloat32x2(value, 0.0)); +} + +/// Broadcast a scalar value to a 2-dimensional floating point vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 2-dimensional floating point vector with value in each component. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxBroadcast2(FfxFloat32 value) +{ + return FfxFloat32x2(value, value); +} + +/// Broadcast a scalar value to a 3-dimensional floating point vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 3-dimensional floating point vector with value in each component. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxBroadcast3(FfxFloat32 value) +{ + return FfxFloat32x3(value, value, value); +} + +/// Broadcast a scalar value to a 4-dimensional floating point vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 4-dimensional floating point vector with value in each component. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxBroadcast4(FfxFloat32 value) +{ + return FfxFloat32x4(value, value, value, value); +} + +/// Broadcast a scalar value to a 2-dimensional signed integer vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 2-dimensional signed integer vector with value in each component. +/// +/// @ingroup GLSLCore +FfxInt32x2 ffxBroadcast2(FfxInt32 value) +{ + return FfxInt32x2(value, value); +} + +/// Broadcast a scalar value to a 3-dimensional signed integer vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 3-dimensional signed integer vector with value in each component. +/// +/// @ingroup GLSLCore +FfxInt32x3 ffxBroadcast3(FfxInt32 value) +{ + return FfxInt32x3(value, value, value); +} + +/// Broadcast a scalar value to a 4-dimensional signed integer vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 4-dimensional signed integer vector with value in each component. +/// +/// @ingroup GLSLCore +FfxInt32x4 ffxBroadcast4(FfxInt32 value) +{ + return FfxInt32x4(value, value, value, value); +} + +/// Broadcast a scalar value to a 2-dimensional unsigned integer vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 2-dimensional unsigned integer vector with value in each component. +/// +/// @ingroup GLSLCore +FfxUInt32x2 ffxBroadcast2(FfxUInt32 value) +{ + return FfxUInt32x2(value, value); +} + +/// Broadcast a scalar value to a 3-dimensional unsigned integer vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 3-dimensional unsigned integer vector with value in each component. +/// +/// @ingroup GLSLCore +FfxUInt32x3 ffxBroadcast3(FfxUInt32 value) +{ + return FfxUInt32x3(value, value, value); +} + +/// Broadcast a scalar value to a 4-dimensional unsigned integer vector. +/// +/// @param [in] value The value to to broadcast. +/// +/// @returns +/// A 4-dimensional unsigned integer vector with value in each component. +/// +/// @ingroup GLSLCore +FfxUInt32x4 ffxBroadcast4(FfxUInt32 value) +{ + return FfxUInt32x4(value, value, value, value); +} + +/// +/// +/// @ingroup GLSLCore +FfxUInt32 ffxBitfieldExtract(FfxUInt32 src, FfxUInt32 off, FfxUInt32 bits) +{ + return bitfieldExtract(src, FfxInt32(off), FfxInt32(bits)); +} + +/// +/// +/// @ingroup GLSLCore +FfxUInt32 ffxBitfieldInsert(FfxUInt32 src, FfxUInt32 ins, FfxUInt32 mask) +{ + return (ins & mask) | (src & (~mask)); +} + +// Proxy for V_BFI_B32 where the 'mask' is set as 'bits', 'mask=(1<mix instrinsic function. Implements the +/// following math: +/// +/// (1 - t) * x + t * y +/// +/// @param [in] x The first value to lerp between. +/// @param [in] y The second value to lerp between. +/// @param [in] t The value to determine how much of x and how much of y. +/// +/// @returns +/// A linearly interpolated value between x and y according to t. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxLerp(FfxFloat32 x, FfxFloat32 y, FfxFloat32 t) +{ + return mix(x, y, t); +} + +/// Compute the linear interopation between two values. +/// +/// Implemented by calling the GLSL mix instrinsic function. Implements the +/// following math: +/// +/// (1 - t) * x + t * y +/// +/// @param [in] x The first value to lerp between. +/// @param [in] y The second value to lerp between. +/// @param [in] t The value to determine how much of x and how much of y. +/// +/// @returns +/// A linearly interpolated value between x and y according to t. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxLerp(FfxFloat32x2 x, FfxFloat32x2 y, FfxFloat32 t) +{ + return mix(x, y, t); +} + +/// Compute the linear interopation between two values. +/// +/// Implemented by calling the GLSL mix instrinsic function. Implements the +/// following math: +/// +/// (1 - t) * x + t * y +/// +/// @param [in] x The first value to lerp between. +/// @param [in] y The second value to lerp between. +/// @param [in] t The value to determine how much of x and how much of y. +/// +/// @returns +/// A linearly interpolated value between x and y according to t. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxLerp(FfxFloat32x2 x, FfxFloat32x2 y, FfxFloat32x2 t) +{ + return mix(x, y, t); +} + +/// Compute the linear interopation between two values. +/// +/// Implemented by calling the GLSL mix instrinsic function. Implements the +/// following math: +/// +/// (1 - t) * x + t * y +/// +/// @param [in] x The first value to lerp between. +/// @param [in] y The second value to lerp between. +/// @param [in] t The value to determine how much of x and how much of y. +/// +/// @returns +/// A linearly interpolated value between x and y according to t. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxLerp(FfxFloat32x3 x, FfxFloat32x3 y, FfxFloat32 t) +{ + return mix(x, y, t); +} + +/// Compute the linear interopation between two values. +/// +/// Implemented by calling the GLSL mix instrinsic function. Implements the +/// following math: +/// +/// (1 - t) * x + t * y +/// +/// @param [in] x The first value to lerp between. +/// @param [in] y The second value to lerp between. +/// @param [in] t The value to determine how much of x and how much of y. +/// +/// @returns +/// A linearly interpolated value between x and y according to t. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxLerp(FfxFloat32x3 x, FfxFloat32x3 y, FfxFloat32x3 t) +{ + return mix(x, y, t); +} + +/// Compute the linear interopation between two values. +/// +/// Implemented by calling the GLSL mix instrinsic function. Implements the +/// following math: +/// +/// (1 - t) * x + t * y +/// +/// @param [in] x The first value to lerp between. +/// @param [in] y The second value to lerp between. +/// @param [in] t The value to determine how much of x and how much of y. +/// +/// @returns +/// A linearly interpolated value between x and y according to t. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxLerp(FfxFloat32x4 x, FfxFloat32x4 y, FfxFloat32 t) +{ + return mix(x, y, t); +} + +/// Compute the linear interopation between two values. +/// +/// Implemented by calling the GLSL mix instrinsic function. Implements the +/// following math: +/// +/// (1 - t) * x + t * y +/// +/// @param [in] x The first value to lerp between. +/// @param [in] y The second value to lerp between. +/// @param [in] t The value to determine how much of x and how much of y. +/// +/// @returns +/// A linearly interpolated value between x and y according to t. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxLerp(FfxFloat32x4 x, FfxFloat32x4 y, FfxFloat32x4 t) +{ + return mix(x, y, t); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN or RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxMax3(FfxFloat32 x, FfxFloat32 y, FfxFloat32 z) +{ + return max(x, max(y, z)); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN or RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxMax3(FfxFloat32x2 x, FfxFloat32x2 y, FfxFloat32x2 z) +{ + return max(x, max(y, z)); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN or RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxMax3(FfxFloat32x3 x, FfxFloat32x3 y, FfxFloat32x3 z) +{ + return max(x, max(y, z)); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN or RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxMax3(FfxFloat32x4 x, FfxFloat32x4 y, FfxFloat32x4 z) +{ + return max(x, max(y, z)); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN or RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32 ffxMax3(FfxUInt32 x, FfxUInt32 y, FfxUInt32 z) +{ + return max(x, max(y, z)); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN or RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32x2 ffxMax3(FfxUInt32x2 x, FfxUInt32x2 y, FfxUInt32x2 z) +{ + return max(x, max(y, z)); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32x3 ffxMax3(FfxUInt32x3 x, FfxUInt32x3 y, FfxUInt32x3 z) +{ + return max(x, max(y, z)); +} + +/// Compute the maximum of three values. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the max calculation. +/// @param [in] y The second value to include in the max calcuation. +/// @param [in] z The third value to include in the max calcuation. +/// +/// @returns +/// The maximum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32x4 ffxMax3(FfxUInt32x4 x, FfxUInt32x4 y, FfxUInt32x4 z) +{ + return max(x, max(y, z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxMed3(FfxFloat32 x, FfxFloat32 y, FfxFloat32 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxMed3(FfxFloat32x2 x, FfxFloat32x2 y, FfxFloat32x2 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxMed3(FfxFloat32x3 x, FfxFloat32x3 y, FfxFloat32x3 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxMed3(FfxFloat32x4 x, FfxFloat32x4 y, FfxFloat32x4 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_I32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxInt32 ffxMed3(FfxInt32 x, FfxInt32 y, FfxInt32 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_I32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxInt32x2 ffxMed3(FfxInt32x2 x, FfxInt32x2 y, FfxInt32x2 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_I32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxInt32x3 ffxMed3(FfxInt32x3 x, FfxInt32x3 y, FfxInt32x3 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + +/// Compute the median of three values. +/// +/// NOTE: This function should compile down to a single V_MED3_I32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the median calculation. +/// @param [in] y The second value to include in the median calcuation. +/// @param [in] z The third value to include in the median calcuation. +/// +/// @returns +/// The median value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxInt32x4 ffxMed3(FfxInt32x4 x, FfxInt32x4 y, FfxInt32x4 z) +{ + return max(min(x, y), min(max(x, y), z)); +} + + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN and RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxMin3(FfxFloat32 x, FfxFloat32 y, FfxFloat32 z) +{ + return min(x, min(y, z)); +} + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxMin3(FfxFloat32x2 x, FfxFloat32x2 y, FfxFloat32x2 z) +{ + return min(x, min(y, z)); +} + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxMin3(FfxFloat32x3 x, FfxFloat32x3 y, FfxFloat32x3 z) +{ + return min(x, min(y, z)); +} + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxMin3(FfxFloat32x4 x, FfxFloat32x4 y, FfxFloat32x4 z) +{ + return min(x, min(y, z)); +} + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32 ffxMin3(FfxUInt32 x, FfxUInt32 y, FfxUInt32 z) +{ + return min(x, min(y, z)); +} + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32x2 ffxMin3(FfxUInt32x2 x, FfxUInt32x2 y, FfxUInt32x2 z) +{ + return min(x, min(y, z)); +} + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32x3 ffxMin3(FfxUInt32x3 x, FfxUInt32x3 y, FfxUInt32x3 z) +{ + return min(x, min(y, z)); +} + +/// Compute the minimum of three values. +/// +/// NOTE: This function should compile down to a single V_MIN3_F32 operation on +/// GCN/RDNA hardware. +/// +/// @param [in] x The first value to include in the min calculation. +/// @param [in] y The second value to include in the min calcuation. +/// @param [in] z The third value to include in the min calcuation. +/// +/// @returns +/// The minimum value of x, y, and z. +/// +/// @ingroup GLSLCore +FfxUInt32x4 ffxMin3(FfxUInt32x4 x, FfxUInt32x4 y, FfxUInt32x4 z) +{ + return min(x, min(y, z)); +} + +/// Compute the reciprocal of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rcp can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal value of x. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxReciprocal(FfxFloat32 x) +{ + return FfxFloat32(1.0) / x; +} + +/// Compute the reciprocal of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rcp can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal value of x. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxReciprocal(FfxFloat32x2 x) +{ + return ffxBroadcast2(1.0) / x; +} + +/// Compute the reciprocal of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rcp can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal value of x. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxReciprocal(FfxFloat32x3 x) +{ + return ffxBroadcast3(1.0) / x; +} + +/// Compute the reciprocal of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rcp can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal value of x. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxReciprocal(FfxFloat32x4 x) +{ + return ffxBroadcast4(1.0) / x; +} + +/// Compute the reciprocal square root of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rsqrt can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal square root value of x. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxRsqrt(FfxFloat32 x) +{ + return FfxFloat32(1.0) / ffxSqrt(x); +} + +/// Compute the reciprocal square root of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rsqrt can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal square root value of x. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxRsqrt(FfxFloat32x2 x) +{ + return ffxBroadcast2(1.0) / ffxSqrt(x); +} + +/// Compute the reciprocal square root of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rsqrt can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal square root value of x. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxRsqrt(FfxFloat32x3 x) +{ + return ffxBroadcast3(1.0) / ffxSqrt(x); +} + +/// Compute the reciprocal square root of a value. +/// +/// NOTE: This function is only provided for GLSL. In HLSL the intrinsic function rsqrt can be used. +/// +/// @param [in] x The value to compute the reciprocal for. +/// +/// @returns +/// The reciprocal square root value of x. +/// +/// @ingroup GLSLCore +FfxFloat32x4 rsqrt(FfxFloat32x4 x) +{ + return ffxBroadcast4(1.0) / ffxSqrt(x); +} + +/// Clamp a value to a [0..1] range. +/// +/// @param [in] x The value to clamp to [0..1] range. +/// +/// @returns +/// The clamped version of x. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxSaturate(FfxFloat32 x) +{ + return clamp(x, FfxFloat32(0.0), FfxFloat32(1.0)); +} + +/// Clamp a value to a [0..1] range. +/// +/// @param [in] x The value to clamp to [0..1] range. +/// +/// @returns +/// The clamped version of x. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxSaturate(FfxFloat32x2 x) +{ + return clamp(x, ffxBroadcast2(0.0), ffxBroadcast2(1.0)); +} + +/// Clamp a value to a [0..1] range. +/// +/// @param [in] x The value to clamp to [0..1] range. +/// +/// @returns +/// The clamped version of x. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxSaturate(FfxFloat32x3 x) +{ + return clamp(x, ffxBroadcast3(0.0), ffxBroadcast3(1.0)); +} + +/// Clamp a value to a [0..1] range. +/// +/// @param [in] x The value to clamp to [0..1] range. +/// +/// @returns +/// The clamped version of x. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxSaturate(FfxFloat32x4 x) +{ + return clamp(x, ffxBroadcast4(0.0), ffxBroadcast4(1.0)); +} + +/// Compute the factional part of a decimal value. +/// +/// This function calculates x - floor(x). Where floor is the intrinsic HLSL function. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on GCN/RDNA hardware. It is +/// worth further noting that this function is intentionally distinct from the HLSL frac intrinsic +/// function. +/// +/// @param [in] x The value to compute the fractional part from. +/// +/// @returns +/// The fractional part of x. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxFract(FfxFloat32 x) +{ + return fract(x); +} + +/// Compute the factional part of a decimal value. +/// +/// This function calculates x - floor(x). Where floor is the intrinsic HLSL function. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on GCN/RDNA hardware. It is +/// worth further noting that this function is intentionally distinct from the HLSL frac intrinsic +/// function. +/// +/// @param [in] x The value to compute the fractional part from. +/// +/// @returns +/// The fractional part of x. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxFract(FfxFloat32x2 x) +{ + return fract(x); +} + +/// Compute the factional part of a decimal value. +/// +/// This function calculates x - floor(x). Where floor is the intrinsic HLSL function. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on GCN/RDNA hardware. It is +/// worth further noting that this function is intentionally distinct from the HLSL frac intrinsic +/// function. +/// +/// @param [in] x The value to compute the fractional part from. +/// +/// @returns +/// The fractional part of x. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxFract(FfxFloat32x3 x) +{ + return fract(x); +} + +/// Compute the factional part of a decimal value. +/// +/// This function calculates x - floor(x). Where floor is the intrinsic HLSL function. +/// +/// NOTE: This function should compile down to a single V_MAX3_F32 operation on GCN/RDNA hardware. It is +/// worth further noting that this function is intentionally distinct from the HLSL frac intrinsic +/// function. +/// +/// @param [in] x The value to compute the fractional part from. +/// +/// @returns +/// The fractional part of x. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxFract(FfxFloat32x4 x) +{ + return fract(x); +} + +/// Rounds to the nearest integer. In case the fractional part is 0.5, it will round to the nearest even integer. +/// +/// @param [in] x The value to be rounded. +/// +/// @returns +/// The nearest integer from x. The nearest even integer from x if equidistant from 2 integer. +/// +/// @ingroup GLSLCore +FfxFloat32 ffxRound(FfxFloat32 x) +{ + return roundEven(x); +} + +/// Rounds to the nearest integer. In case the fractional part is 0.5, it will round to the nearest even integer. +/// +/// @param [in] x The value to be rounded. +/// +/// @returns +/// The nearest integer from x. The nearest even integer from x if equidistant from 2 integer. +/// +/// @ingroup GLSLCore +FfxFloat32x2 ffxRound(FfxFloat32x2 x) +{ + return roundEven(x); +} + +/// Rounds to the nearest integer. In case the fractional part is 0.5, it will round to the nearest even integer. +/// +/// @param [in] x The value to be rounded. +/// +/// @returns +/// The nearest integer from x. The nearest even integer from x if equidistant from 2 integer. +/// +/// @ingroup GLSLCore +FfxFloat32x3 ffxRound(FfxFloat32x3 x) +{ + return roundEven(x); +} + +/// Rounds to the nearest integer. In case the fractional part is 0.5, it will round to the nearest even integer. +/// +/// @param [in] x The value to be rounded. +/// +/// @returns +/// The nearest integer from x. The nearest even integer from x if equidistant from 2 integer. +/// +/// @ingroup GLSLCore +FfxFloat32x4 ffxRound(FfxFloat32x4 x) +{ + return roundEven(x); +} + +FfxUInt32 ffxAShrSU1(FfxUInt32 a, FfxUInt32 b) +{ + return FfxUInt32(FfxInt32(a) >> FfxInt32(b)); +} + +FfxUInt32 ffxPackF32(FfxFloat32x2 v){ + return packHalf2x16(v); +} + +FfxFloat32x2 ffxUnpackF32(FfxUInt32 u){ + return unpackHalf2x16(u); +} + +FfxUInt32x2 ffxPackF32x2(FfxFloat32x4 v){ + return FfxUInt32x2(ffxPackF32(v.xy), ffxPackF32(v.zw)); +} + +FfxFloat32x4 ffxUnpackF32x2(FfxUInt32x2 a){ + return FfxFloat32x4(ffxUnpackF32(a.x), ffxUnpackF32(a.y)); +} + +/// @brief Inverts the value while avoiding division by zero. If the value is zero, zero is returned. +/// @param v Value to invert. +/// @return If v = 0 returns 0. If v != 0 returns 1/v. +FfxFloat32 ffxInvertSafe(FfxFloat32 v){ + FfxFloat32 s = sign(v); + FfxFloat32 s2 = s*s; + return s2/(v + s2 - 1.0); +} + +/// @brief Inverts the value while avoiding division by zero. If the value is zero, zero is returned. +/// @param v Value to invert. +/// @return If v = 0 returns 0. If v != 0 returns 1/v. +FfxFloat32x2 ffxInvertSafe(FfxFloat32x2 v){ + FfxFloat32x2 s = sign(v); + FfxFloat32x2 s2 = s*s; + return s2/(v + s2 - FfxFloat32x2(1.0, 1.0)); +} + +/// @brief Inverts the value while avoiding division by zero. If the value is zero, zero is returned. +/// @param v Value to invert. +/// @return If v = 0 returns 0. If v != 0 returns 1/v. +FfxFloat32x3 ffxInvertSafe(FfxFloat32x3 v){ + FfxFloat32x3 s = sign(v); + FfxFloat32x3 s2 = s*s; + return s2/(v + s2 - FfxFloat32x3(1.0, 1.0, 1.0)); +} + +/// @brief Inverts the value while avoiding division by zero. If the value is zero, zero is returned. +/// @param v Value to invert. +/// @return If v = 0 returns 0. If v != 0 returns 1/v. +FfxFloat32x4 ffxInvertSafe(FfxFloat32x4 v){ + FfxFloat32x4 s = sign(v); + FfxFloat32x4 s2 = s*s; + return s2/(v + s2 - FfxFloat32x4(1.0, 1.0, 1.0, 1.0)); +} +#if FFX_HALF +#define FFX_UINT32_TO_FLOAT16X2(x) unpackFloat2x16(FfxUInt32(x)) + +FfxUInt32 ffxPackF16(FfxFloat16x2 v){ + return packHalf2x16(v); +} + +FfxFloat16x2 ffxUnpackF16(FfxUInt32 u){ + return FfxFloat16x2(unpackHalf2x16(u)); +} + +FfxFloat16x4 ffxUint32x2ToFloat16x4(FfxUInt32x2 x) +{ + return FfxFloat16x4(unpackFloat2x16(x.x), unpackFloat2x16(x.y)); +} +#define FFX_UINT32X2_TO_FLOAT16X4(x) ffxUint32x2ToFloat16x4(FfxUInt32x2(x)) +#define FFX_UINT32_TO_UINT16X2(x) unpackUint2x16(FfxUInt32(x)) +#define FFX_UINT32X2_TO_UINT16X4(x) unpackUint4x16(pack64(FfxUInt32x2(x))) +//------------------------------------------------------------------------------------------------------------------------------ +#define FFX_FLOAT16X2_TO_UINT32(x) packFloat2x16(FfxFloat16x2(x)) +FfxUInt32x2 ffxFloat16x4ToUint32x2(FfxFloat16x4 x) +{ + return FfxUInt32x2(packFloat2x16(x.xy), packFloat2x16(x.zw)); +} +#define FFX_FLOAT16X4_TO_UINT32X2(x) ffxFloat16x4ToUint32x2(FfxFloat16x4(x)) +#define FFX_UINT16X2_TO_UINT32(x) packUint2x16(FfxUInt16x2(x)) +#define FFX_UINT16X4_TO_UINT32X2(x) unpack32(packUint4x16(FfxUInt16x4(x))) +//============================================================================================================================== +#define FFX_TO_UINT16(x) halfBitsToUint16(FfxFloat16(x)) +#define FFX_TO_UINT16X2(x) halfBitsToUint16(FfxFloat16x2(x)) +#define FFX_TO_UINT16X3(x) halfBitsToUint16(FfxFloat16x3(x)) +#define FFX_TO_UINT16X4(x) halfBitsToUint16(FfxFloat16x4(x)) +//------------------------------------------------------------------------------------------------------------------------------ +#define FFX_TO_FLOAT16(x) uint16BitsToHalf(FfxUInt16(x)) +#define FFX_TO_FLOAT16X2(x) uint16BitsToHalf(FfxUInt16x2(x)) +#define FFX_TO_FLOAT16X3(x) uint16BitsToHalf(FfxUInt16x3(x)) +#define FFX_TO_FLOAT16X4(x) uint16BitsToHalf(FfxUInt16x4(x)) +//============================================================================================================================== +FfxFloat16 ffxBroadcastFloat16(FfxFloat16 a) +{ + return FfxFloat16(a); +} +FfxFloat16x2 ffxBroadcastFloat16x2(FfxFloat16 a) +{ + return FfxFloat16x2(a, a); +} +FfxFloat16x3 ffxBroadcastFloat16x3(FfxFloat16 a) +{ + return FfxFloat16x3(a, a, a); +} +FfxFloat16x4 ffxBroadcastFloat16x4(FfxFloat16 a) +{ + return FfxFloat16x4(a, a, a, a); +} +#define FFX_BROADCAST_FLOAT16(a) FfxFloat16(a) +#define FFX_BROADCAST_FLOAT16X2(a) FfxFloat16x2(FfxFloat16(a)) +#define FFX_BROADCAST_FLOAT16X3(a) FfxFloat16x3(FfxFloat16(a)) +#define FFX_BROADCAST_FLOAT16X4(a) FfxFloat16x4(FfxFloat16(a)) +//------------------------------------------------------------------------------------------------------------------------------ +FfxInt16 ffxBroadcastInt16(FfxInt16 a) +{ + return FfxInt16(a); +} +FfxInt16x2 ffxBroadcastInt16x2(FfxInt16 a) +{ + return FfxInt16x2(a, a); +} +FfxInt16x3 ffxBroadcastInt16x3(FfxInt16 a) +{ + return FfxInt16x3(a, a, a); +} +FfxInt16x4 ffxBroadcastInt16x4(FfxInt16 a) +{ + return FfxInt16x4(a, a, a, a); +} +#define FFX_BROADCAST_INT16(a) FfxInt16(a) +#define FFX_BROADCAST_INT16X2(a) FfxInt16x2(FfxInt16(a)) +#define FFX_BROADCAST_INT16X3(a) FfxInt16x3(FfxInt16(a)) +#define FFX_BROADCAST_INT16X4(a) FfxInt16x4(FfxInt16(a)) +//------------------------------------------------------------------------------------------------------------------------------ +FfxUInt16 ffxBroadcastUInt16(FfxUInt16 a) +{ + return FfxUInt16(a); +} +FfxUInt16x2 ffxBroadcastUInt16x2(FfxUInt16 a) +{ + return FfxUInt16x2(a, a); +} +FfxUInt16x3 ffxBroadcastUInt16x3(FfxUInt16 a) +{ + return FfxUInt16x3(a, a, a); +} +FfxUInt16x4 ffxBroadcastUInt16x4(FfxUInt16 a) +{ + return FfxUInt16x4(a, a, a, a); +} +#define FFX_BROADCAST_UINT16(a) FfxUInt16(a) +#define FFX_BROADCAST_UINT16X2(a) FfxUInt16x2(FfxUInt16(a)) +#define FFX_BROADCAST_UINT16X3(a) FfxUInt16x3(FfxUInt16(a)) +#define FFX_BROADCAST_UINT16X4(a) FfxUInt16x4(FfxUInt16(a)) +//============================================================================================================================== +FfxUInt16 ffxAbsHalf(FfxUInt16 a) +{ + return FfxUInt16(abs(FfxInt16(a))); +} +FfxUInt16x2 ffxAbsHalf(FfxUInt16x2 a) +{ + return FfxUInt16x2(abs(FfxInt16x2(a))); +} +FfxUInt16x3 ffxAbsHalf(FfxUInt16x3 a) +{ + return FfxUInt16x3(abs(FfxInt16x3(a))); +} +FfxUInt16x4 ffxAbsHalf(FfxUInt16x4 a) +{ + return FfxUInt16x4(abs(FfxInt16x4(a))); +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxFloat16 ffxClampHalf(FfxFloat16 x, FfxFloat16 n, FfxFloat16 m) +{ + return clamp(x, n, m); +} +FfxFloat16x2 ffxClampHalf(FfxFloat16x2 x, FfxFloat16x2 n, FfxFloat16x2 m) +{ + return clamp(x, n, m); +} +FfxFloat16x3 ffxClampHalf(FfxFloat16x3 x, FfxFloat16x3 n, FfxFloat16x3 m) +{ + return clamp(x, n, m); +} +FfxFloat16x4 ffxClampHalf(FfxFloat16x4 x, FfxFloat16x4 n, FfxFloat16x4 m) +{ + return clamp(x, n, m); +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxFloat16 ffxFract(FfxFloat16 x) +{ + return fract(x); +} +FfxFloat16x2 ffxFract(FfxFloat16x2 x) +{ + return fract(x); +} +FfxFloat16x3 ffxFract(FfxFloat16x3 x) +{ + return fract(x); +} +FfxFloat16x4 ffxFract(FfxFloat16x4 x) +{ + return fract(x); +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxFloat16 ffxLerp(FfxFloat16 x, FfxFloat16 y, FfxFloat16 a) +{ + return mix(x, y, a); +} +FfxFloat16x2 ffxLerp(FfxFloat16x2 x, FfxFloat16x2 y, FfxFloat16 a) +{ + return mix(x, y, a); +} +FfxFloat16x2 ffxLerp(FfxFloat16x2 x, FfxFloat16x2 y, FfxFloat16x2 a) +{ + return mix(x, y, a); +} +FfxFloat16x3 ffxLerp(FfxFloat16x3 x, FfxFloat16x3 y, FfxFloat16x3 a) +{ + return mix(x, y, a); +} +FfxFloat16x3 ffxLerp(FfxFloat16x3 x, FfxFloat16x3 y, FfxFloat16 a) +{ + return mix(x, y, a); +} +FfxFloat16x4 ffxLerp(FfxFloat16x4 x, FfxFloat16x4 y, FfxFloat16 a) +{ + return mix(x, y, a); +} +FfxFloat16x4 ffxLerp(FfxFloat16x4 x, FfxFloat16x4 y, FfxFloat16x4 a) +{ + return mix(x, y, a); +} +//------------------------------------------------------------------------------------------------------------------------------ +// No packed version of ffxMax3. +FfxFloat16 ffxMax3Half(FfxFloat16 x, FfxFloat16 y, FfxFloat16 z) +{ + return max(x, max(y, z)); +} +FfxFloat16x2 ffxMax3Half(FfxFloat16x2 x, FfxFloat16x2 y, FfxFloat16x2 z) +{ + return max(x, max(y, z)); +} +FfxFloat16x3 ffxMax3Half(FfxFloat16x3 x, FfxFloat16x3 y, FfxFloat16x3 z) +{ + return max(x, max(y, z)); +} +FfxFloat16x4 ffxMax3Half(FfxFloat16x4 x, FfxFloat16x4 y, FfxFloat16x4 z) +{ + return max(x, max(y, z)); +} +//------------------------------------------------------------------------------------------------------------------------------ +// No packed version of ffxMin3. +FfxFloat16 ffxMin3Half(FfxFloat16 x, FfxFloat16 y, FfxFloat16 z) +{ + return min(x, min(y, z)); +} +FfxFloat16x2 ffxMin3Half(FfxFloat16x2 x, FfxFloat16x2 y, FfxFloat16x2 z) +{ + return min(x, min(y, z)); +} +FfxFloat16x3 ffxMin3Half(FfxFloat16x3 x, FfxFloat16x3 y, FfxFloat16x3 z) +{ + return min(x, min(y, z)); +} +FfxFloat16x4 ffxMin3Half(FfxFloat16x4 x, FfxFloat16x4 y, FfxFloat16x4 z) +{ + return min(x, min(y, z)); +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxFloat16 ffxMed3Half(FfxFloat16 x, FfxFloat16 y, FfxFloat16 z) +{ + return max(min(x, y), min(max(x, y), z)); +} +FfxFloat16x2 ffxMed3Half(FfxFloat16x2 x, FfxFloat16x2 y, FfxFloat16x2 z) +{ + return max(min(x, y), min(max(x, y), z)); +} +FfxFloat16x3 ffxMed3Half(FfxFloat16x3 x, FfxFloat16x3 y, FfxFloat16x3 z) +{ + return max(min(x, y), min(max(x, y), z)); +} +FfxFloat16x4 ffxMed3Half(FfxFloat16x4 x, FfxFloat16x4 y, FfxFloat16x4 z) +{ + return max(min(x, y), min(max(x, y), z)); +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxFloat16 ffxReciprocalHalf(FfxFloat16 x) +{ + return FFX_BROADCAST_FLOAT16(1.0) / x; +} +FfxFloat16x2 ffxReciprocalHalf(FfxFloat16x2 x) +{ + return FFX_BROADCAST_FLOAT16X2(1.0) / x; +} +FfxFloat16x3 ffxReciprocalHalf(FfxFloat16x3 x) +{ + return FFX_BROADCAST_FLOAT16X3(1.0) / x; +} +FfxFloat16x4 ffxReciprocalHalf(FfxFloat16x4 x) +{ + return FFX_BROADCAST_FLOAT16X4(1.0) / x; +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxFloat16 ffxReciprocalSquareRootHalf(FfxFloat16 x) +{ + return FFX_BROADCAST_FLOAT16(1.0) / sqrt(x); +} +FfxFloat16x2 ffxReciprocalSquareRootHalf(FfxFloat16x2 x) +{ + return FFX_BROADCAST_FLOAT16X2(1.0) / sqrt(x); +} +FfxFloat16x3 ffxReciprocalSquareRootHalf(FfxFloat16x3 x) +{ + return FFX_BROADCAST_FLOAT16X3(1.0) / sqrt(x); +} +FfxFloat16x4 ffxReciprocalSquareRootHalf(FfxFloat16x4 x) +{ + return FFX_BROADCAST_FLOAT16X4(1.0) / sqrt(x); +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxFloat16 ffxSaturate(FfxFloat16 x) +{ + return clamp(x, FFX_BROADCAST_FLOAT16(0.0), FFX_BROADCAST_FLOAT16(1.0)); +} +FfxFloat16x2 ffxSaturate(FfxFloat16x2 x) +{ + return clamp(x, FFX_BROADCAST_FLOAT16X2(0.0), FFX_BROADCAST_FLOAT16X2(1.0)); +} +FfxFloat16x3 ffxSaturate(FfxFloat16x3 x) +{ + return clamp(x, FFX_BROADCAST_FLOAT16X3(0.0), FFX_BROADCAST_FLOAT16X3(1.0)); +} +FfxFloat16x4 ffxSaturate(FfxFloat16x4 x) +{ + return clamp(x, FFX_BROADCAST_FLOAT16X4(0.0), FFX_BROADCAST_FLOAT16X4(1.0)); +} +//------------------------------------------------------------------------------------------------------------------------------ +FfxUInt16 ffxBitShiftRightHalf(FfxUInt16 a, FfxUInt16 b) +{ + return FfxUInt16(FfxInt16(a) >> FfxInt16(b)); +} +FfxUInt16x2 ffxBitShiftRightHalf(FfxUInt16x2 a, FfxUInt16x2 b) +{ + return FfxUInt16x2(FfxInt16x2(a) >> FfxInt16x2(b)); +} +FfxUInt16x3 ffxBitShiftRightHalf(FfxUInt16x3 a, FfxUInt16x3 b) +{ + return FfxUInt16x3(FfxInt16x3(a) >> FfxInt16x3(b)); +} +FfxUInt16x4 ffxBitShiftRightHalf(FfxUInt16x4 a, FfxUInt16x4 b) +{ + return FfxUInt16x4(FfxInt16x4(a) >> FfxInt16x4(b)); +} +#endif // FFX_HALF + +#if defined(FFX_WAVE) +// Where 'x' must be a compile time literal. +FfxFloat32 ffxWaveXorF1(FfxFloat32 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxFloat32x2 ffxWaveXorF2(FfxFloat32x2 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxFloat32x3 ffxWaveXorF3(FfxFloat32x3 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxFloat32x4 ffxWaveXorF4(FfxFloat32x4 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxUInt32 ffxWaveXorU1(FfxUInt32 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxUInt32x2 ffxWaveXorU2(FfxUInt32x2 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxUInt32x3 ffxWaveXorU3(FfxUInt32x3 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxUInt32x4 ffxWaveXorU4(FfxUInt32x4 v, FfxUInt32 x) +{ + return subgroupShuffleXor(v, x); +} +FfxBoolean ffxWaveIsFirstLane() +{ + return subgroupElect(); +} +FfxUInt32 ffxWaveLaneIndex() +{ + return gl_SubgroupInvocationID; +} +FfxBoolean ffxWaveReadAtLaneIndexB1(FfxBoolean v, FfxUInt32 x ) +{ + return subgroupShuffle(v, x); +} +FfxUInt32 ffxWavePrefixCountBits(FfxBoolean v) +{ + return subgroupBallotExclusiveBitCount(subgroupBallot(v)); +} +FfxUInt32 ffxWaveActiveCountBits(FfxBoolean v) +{ + return subgroupBallotBitCount(subgroupBallot(v)); +} +FfxUInt32 ffxWaveReadLaneFirstU1(FfxUInt32 v) +{ + return subgroupBroadcastFirst(v); +} +FfxUInt32x2 ffxWaveReadLaneFirstU2(FfxUInt32x2 v) +{ + return subgroupBroadcastFirst(v); +} +FfxBoolean ffxWaveReadLaneFirstB1(FfxBoolean v) +{ + return subgroupBroadcastFirst(v); +} +FfxUInt32 ffxWaveOr(FfxUInt32 a) +{ + return subgroupOr(a); +} +FfxUInt32 ffxWaveMin(FfxUInt32 a) +{ + return subgroupMin(a); +} +FfxFloat32 ffxWaveMin(FfxFloat32 a) +{ + return subgroupMin(a); +} +FfxUInt32 ffxWaveMax(FfxUInt32 a) +{ + return subgroupMax(a); +} +FfxFloat32 ffxWaveMax(FfxFloat32 a) +{ + return subgroupMax(a); +} +FfxUInt32 ffxWaveSum(FfxUInt32 a) +{ + return subgroupAdd(a); +} +FfxFloat32 ffxWaveSum(FfxFloat32 a) +{ + return subgroupAdd(a); +} +FfxUInt32 ffxWaveLaneCount() +{ + return gl_SubgroupSize; +} +#if defined(FFX_WAVE_ALL_TRUE) +FfxBoolean ffxWaveAllTrue(FfxBoolean v) +{ + return subgroupAll(v); +} +#endif +FfxFloat32 ffxQuadReadX(FfxFloat32 v) +{ + return subgroupQuadSwapHorizontal(v); +} +FfxFloat32x2 ffxQuadReadX(FfxFloat32x2 v) +{ + return subgroupQuadSwapHorizontal(v); +} +FfxFloat32 ffxQuadReadY(FfxFloat32 v) +{ + return subgroupQuadSwapVertical(v); +} +FfxFloat32x2 ffxQuadReadY(FfxFloat32x2 v) +{ + return subgroupQuadSwapVertical(v); +} + +//------------------------------------------------------------------------------------------------------------------------------ +#if FFX_HALF +FfxFloat16x2 ffxWaveXorFloat16x2(FfxFloat16x2 v, FfxUInt32 x) +{ + return FFX_UINT32_TO_FLOAT16X2(subgroupShuffleXor(FFX_FLOAT16X2_TO_UINT32(v), x)); +} +FfxFloat16x4 ffxWaveXorFloat16x4(FfxFloat16x4 v, FfxUInt32 x) +{ + return FFX_UINT32X2_TO_FLOAT16X4(subgroupShuffleXor(FFX_FLOAT16X4_TO_UINT32X2(v), x)); +} +FfxUInt16x2 ffxWaveXorUint16x2(FfxUInt16x2 v, FfxUInt32 x) +{ + return FFX_UINT32_TO_UINT16X2(subgroupShuffleXor(FFX_UINT16X2_TO_UINT32(v), x)); +} +FfxUInt16x4 ffxWaveXorUint16x4(FfxUInt16x4 v, FfxUInt32 x) +{ + return FFX_UINT32X2_TO_UINT16X4(subgroupShuffleXor(FFX_UINT16X4_TO_UINT32X2(v), x)); +} +#endif // FFX_HALF +#endif // #if defined(FFX_WAVE) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/frameinterpolation/CMakeCompileFrameinterpolationShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/frameinterpolation/CMakeCompileFrameinterpolationShaders.txt new file mode 100644 index 00000000..9652cb0d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/frameinterpolation/CMakeCompileFrameinterpolationShaders.txt @@ -0,0 +1,55 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(FRAMEINTERPOLATION_BASE_ARGS + -DFFX_FRAMEINTERPOLATION_OPTION_UPSAMPLE_SAMPLERS_USE_DATA_HALF=0 + -DFFX_FRAMEINTERPOLATION_OPTION_ACCUMULATE_SAMPLERS_USE_DATA_HALF=0 + -DFFX_FRAMEINTERPOLATION_OPTION_REPROJECT_SAMPLERS_USE_DATA_HALF=1 + -DFFX_FRAMEINTERPOLATION_OPTION_POSTPROCESSLOCKSTATUS_SAMPLERS_USE_DATA_HALF=0 + # Upsample uses lanczos approximation + -DFFX_FRAMEINTERPOLATION_OPTION_UPSAMPLE_USE_LANCZOS_TYPE=2 + -reflection -deps=gcc -DFFX_GPU=1) + +set(FRAMEINTERPOLATION_PERMUTATION_ARGS + -DFFX_FRAMEINTERPOLATION_OPTION_LOW_RES_MOTION_VECTORS={0,1} + -DFFX_FRAMEINTERPOLATION_OPTION_JITTER_MOTION_VECTORS={0,1} + -DFFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH={0,1}) + +set(FRAMEINTERPOLATION_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/frameinterpolation") + +if (NOT FRAMEINTERPOLATION_SHADER_EXT) + set(FRAMEINTERPOLATION_SHADER_EXT *) +endif() + +file(GLOB FRAMEINTERPOLATION_SHADERS + "shaders/frameinterpolation/*.${FRAMEINTERPOLATION_SHADER_EXT}") + +# compile all the shaders +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${FRAMEINTERPOLATION_BASE_ARGS}" "${FRAMEINTERPOLATION_API_BASE_ARGS}" "${FRAMEINTERPOLATION_PERMUTATION_ARGS}" "${FRAMEINTERPOLATION_INCLUDE_ARGS}" + "${FRAMEINTERPOLATION_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" FRAMEINTERPOLATION_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${FRAMEINTERPOLATION_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/frameinterpolation/ffx_frameinterpolation_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/frameinterpolation/ffx_frameinterpolation_callbacks_glsl.h new file mode 100644 index 00000000..20c5c296 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/frameinterpolation/ffx_frameinterpolation_callbacks_glsl.h @@ -0,0 +1,758 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_frameinterpolation_resources.h" +#include "ffx_core.h" + +#define COUNTER_SPD 0 +#define COUNTER_FRAME_INDEX_SINCE_LAST_RESET 1 + + /////////////////////////////////////////////// + // declare CBs and CB accessors +/////////////////////////////////////////////// +#if defined(FFX_FRAMEINTERPOLATION_BIND_CB_FRAMEINTERPOLATION) + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_CB_FRAMEINTERPOLATION, std140) uniform cbFI_t + { + FfxInt32x2 renderSize; + FfxInt32x2 displaySize; + + FfxFloat32x2 displaySizeRcp; + FfxFloat32 cameraNear; + FfxFloat32 cameraFar; + + FfxInt32x2 upscalerTargetSize; + FfxInt32 Mode; + FfxInt32 reset; + + FfxFloat32x4 fDeviceToViewDepth; + + FfxFloat32 deltaTime; + FfxInt32 HUDLessAttachedFactor; + FfxInt32x2 distortionFieldSize; + + FfxFloat32x2 opticalFlowScale; + FfxInt32 opticalFlowBlockSize; + FfxUInt32 dispatchFlags; + + FfxInt32x2 maxRenderSize; + FfxInt32 opticalFlowHalfResMode; + FfxInt32 NumInstances; + + FfxInt32x2 interpolationRectBase; + FfxInt32x2 interpolationRectSize; + + FfxFloat32x3 debugBarColor; + FfxUInt32 backBufferTransferFunction; + + FfxFloat32x2 minMaxLuminance; + FfxFloat32 fTanHalfFOV; + FfxInt32 _pad1; + + FfxFloat32x2 fJitter; + FfxFloat32x2 fMotionVectorScale; + } cbFI; + + FfxFloat32x2 Jitter() + { + return cbFI.fJitter; + } + + FfxInt32x2 InterpolationRectBase() + { + return cbFI.interpolationRectBase; + } + + FfxInt32x2 InterpolationRectSize() + { + return cbFI.interpolationRectSize; + } + + FfxFloat32x2 MotionVectorScale() + { + return cbFI.fMotionVectorScale; + } + + FfxInt32x2 RenderSize() + { + return cbFI.renderSize; + } + + FfxInt32x2 DisplaySize() + { + return cbFI.displaySize; + } + + FfxBoolean Reset() + { + return cbFI.reset == 1; + } + + FfxFloat32x4 DeviceToViewSpaceTransformFactors() + { + return cbFI.fDeviceToViewDepth; + } + + FfxInt32x2 GetOpticalFlowSize() + { + FfxInt32x2 iOpticalFlowSize = FfxInt32x2((1.0 / cbFI.opticalFlowScale) / FfxFloat32x2(cbFI.opticalFlowBlockSize.xx)); + + return iOpticalFlowSize; + } + + FfxInt32x2 GetOpticalFlowSize2() + { + return GetOpticalFlowSize() * 1; + } + + FfxFloat32x2 GetOpticalFlowScale() + { + return cbFI.opticalFlowScale; + } + + FfxInt32 GetOpticalFlowBlockSize() + { + return cbFI.opticalFlowBlockSize; + } + + FfxInt32 GetHUDLessAttachedFactor() + { + return cbFI.HUDLessAttachedFactor; + } + + FfxInt32x2 GetDistortionFieldSize() + { + return cbFI.distortionFieldSize; + } + + FfxUInt32 GetDispatchFlags() + { + return cbFI.dispatchFlags; + } + + FfxInt32x2 GetMaxRenderSize() + { + return cbFI.maxRenderSize; + } + + FfxInt32 GetOpticalFlowHalfResMode() + { + return cbFI.opticalFlowHalfResMode; + } + + FfxFloat32x3 GetDebugBarColor() + { + return cbFI.debugBarColor; + } + + FfxFloat32 TanHalfFoV() + { + return cbFI.fTanHalfFOV; + } + + FfxUInt32 BackBufferTransferFunction() + { + return cbFI.backBufferTransferFunction; + } + + FfxFloat32 MinLuminance() + { + return cbFI.minMaxLuminance[0]; + } + + FfxFloat32 MaxLuminance() + { + return cbFI.minMaxLuminance[1]; + } + +#endif // defined(FFX_FRAMEINTERPOLATION_BIND_CB_FRAMEINTERPOLATION) + + +#if defined(FFX_FRAMEINTERPOLATION_BIND_CB_INPAINTING_PYRAMID) + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_CB_INPAINTING_PYRAMID, std140) uniform cbInpaintingPyramid_t + { + FfxUInt32 mips; + FfxUInt32 numWorkGroups; + FfxUInt32x2 workGroupOffset; + } cbInpaintingPyramid; + + FfxUInt32 NumMips() + { + return cbInpaintingPyramid.mips; + } + FfxUInt32 NumWorkGroups() + { + return cbInpaintingPyramid.numWorkGroups; + } + FfxUInt32x2 WorkGroupOffset() + { + return cbInpaintingPyramid.workGroupOffset; + } + +#endif // defined(FFX_FRAMEINTERPOLATION_BIND_CB_INPAINTING_PYRAMID) + + + /////////////////////////////////////////////// + // declare samplers +/////////////////////////////////////////////// + + +layout (set = 0, binding = 1000) uniform sampler s_LinearClamp; + + /////////////////////////////////////////////// + // declare SRVs and SRV accessors +/////////////////////////////////////////////// + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_PREVIOUS_INTERPOLATION_SOURCE + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_PREVIOUS_INTERPOLATION_SOURCE) uniform texture2D r_previous_interpolation_source; + + FfxFloat32x3 LoadPreviousBackbuffer(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_previous_interpolation_source, iPxPos, 0).rgb; + } + FfxFloat32x3 SamplePreviousBackbuffer(FFX_PARAMETER_IN FfxFloat32x2 fUv) + { + return textureLod(sampler2D(r_previous_interpolation_source, s_LinearClamp), fUv, 0.0).xyz; + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_CURRENT_INTERPOLATION_SOURCE + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_CURRENT_INTERPOLATION_SOURCE) uniform texture2D r_current_interpolation_source; + + FfxFloat32x3 LoadCurrentBackbuffer(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_current_interpolation_source, iPxPos, 0).rgb; + } + FfxFloat32x3 SampleCurrentBackbuffer(FFX_PARAMETER_IN FfxFloat32x2 fUv) + { + return textureLod(sampler2D(r_current_interpolation_source, s_LinearClamp), fUv, 0.0).xyz; + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_DILATED_MOTION_VECTORS + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_DILATED_MOTION_VECTORS) uniform texture2D r_dilated_motion_vectors; + + FfxFloat32x2 LoadDilatedMotionVector(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_dilated_motion_vectors, iPxPos, 0).xy; + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_DILATED_DEPTH + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_DILATED_DEPTH) uniform texture2D r_dilated_depth; + + FfxFloat32 LoadDilatedDepth(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_dilated_depth, iPxPos, 0).x; + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_RECONSTRUCTED_DEPTH_PREVIOUS_FRAME + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_RECONSTRUCTED_DEPTH_PREVIOUS_FRAME) uniform utexture2D r_reconstructed_depth_previous_frame; + + FfxFloat32 LoadReconstructedDepthPreviousFrame(FFX_PARAMETER_IN FfxInt32x2 iPxInput) + { + return ffxAsFloat(texelFetch(r_reconstructed_depth_previous_frame, iPxInput, 0).x); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_RECONSTRUCTED_DEPTH_INTERPOLATED_FRAME + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_RECONSTRUCTED_DEPTH_INTERPOLATED_FRAME) uniform utexture2D r_reconstructed_depth_interpolated_frame; + + FfxFloat32 LoadEstimatedInterpolationFrameDepth(FFX_PARAMETER_IN FfxInt32x2 iPxInput) + { + return ffxAsFloat(texelFetch(r_reconstructed_depth_interpolated_frame, iPxInput, 0).x); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_DISOCCLUSION_MASK + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_DISOCCLUSION_MASK) uniform texture2D r_disocclusion_mask; + + FfxFloat32x4 LoadDisocclusionMask(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_disocclusion_mask, iPxPos, 0); + } + FfxFloat32x4 SampleDisocclusionMask(FFX_PARAMETER_IN FfxFloat32x2 fUv) + { + return textureLod(sampler2D(r_disocclusion_mask, s_LinearClamp), fUv, 0); + } +#endif + +#if defined(FFX_FRAMEINTERPOLATION_BIND_SRV_GAME_MOTION_VECTOR_FIELD_X) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_SRV_GAME_MOTION_VECTOR_FIELD_Y) + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_GAME_MOTION_VECTOR_FIELD_X) uniform utexture2D r_game_motion_vector_field_x; + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_GAME_MOTION_VECTOR_FIELD_Y) uniform utexture2D r_game_motion_vector_field_y; + + FfxUInt32x2 LoadGameFieldMv(FFX_PARAMETER_IN FfxInt32x2 iPxSample) + { + FfxUInt32 packedX = texelFetch(r_game_motion_vector_field_x, iPxSample, 0).x; + FfxUInt32 packedY = texelFetch(r_game_motion_vector_field_y, iPxSample, 0).x; + + return FfxUInt32x2(packedX, packedY); + } +#endif + +#if defined(FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_X) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_Y) + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_X) uniform utexture2D r_optical_flow_motion_vector_field_x; + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_Y) uniform utexture2D r_optical_flow_motion_vector_field_y; + + FfxUInt32x2 LoadOpticalFlowFieldMv(FFX_PARAMETER_IN FfxInt32x2 iPxSample) + { + FfxUInt32 packedX = texelFetch(r_optical_flow_motion_vector_field_x, iPxSample, 0).x; + FfxUInt32 packedY = texelFetch(r_optical_flow_motion_vector_field_y, iPxSample, 0).x; + + return FfxUInt32x2(packedX, packedY); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW) uniform itexture2D r_optical_flow; + + #if defined(FFX_FRAMEINTERPOLATION_BIND_CB_FRAMEINTERPOLATION) + FfxFloat32x2 LoadOpticalFlow(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_optical_flow, iPxPos, 0).xy * GetOpticalFlowScale(); + } + #endif +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_UPSAMPLED + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_UPSAMPLED) uniform texture2D r_optical_flow_upsampled; + + FfxFloat32x2 LoadOpticalFlowUpsampled(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_optical_flow_upsampled, iPxPos, 0).xy; + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_CONFIDENCE + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_CONFIDENCE) uniform utexture2D r_optical_flow_confidence; + + FfxFloat32 LoadOpticalFlowConfidence(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_optical_flow_confidence, iPxPos, 0).y; + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_GLOBAL_MOTION + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_GLOBAL_MOTION) uniform utexture2D r_optical_flow_global_motion; + + FfxUInt32 LoadOpticalFlowGlobalMotion(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_optical_flow_global_motion, iPxPos, 0).x; + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_SCENE_CHANGE_DETECTION + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_SCENE_CHANGE_DETECTION) uniform utexture2D r_optical_flow_scd; + + FfxUInt32 LoadOpticalFlowSceneChangeDetection(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_optical_flow_scd, iPxPos, 0).x; + } + + FfxBoolean HasSceneChanged() + { + #define SCD_OUTPUT_HISTORY_BITS_SLOT 1 + //if (FrameIndex() <= 5) // threshold according to original OpenCL code + //{ + // return 1.0; + //} + //else + { + // Report that the scene is changed if the change was detected in any of the + // 4 previous frames (0xfu - covers 4 history bits). + return ((texelFetch(r_optical_flow_scd, FfxInt32x2(SCD_OUTPUT_HISTORY_BITS_SLOT, 0), 0).x) & 0xfu) != 0; + } + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_DEBUG + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OPTICAL_FLOW_DEBUG) uniform texture2D r_optical_flow_debug; + + FfxFloat32x4 LoadOpticalFlowDebug(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return texelFetch(r_optical_flow_debug, iPxPos, 0); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_OUTPUT + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_OUTPUT) uniform texture2D r_output; + + FfxFloat32x4 LoadFrameInterpolationOutput(FFX_PARAMETER_IN FfxInt32x2 iPxInput) + { + return texelFetch(r_output, iPxInput, 0); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_INPAINTING_PYRAMID + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_INPAINTING_PYRAMID) uniform texture2D r_inpainting_pyramid; + + FfxFloat32x4 LoadInpaintingPyramid(FFX_PARAMETER_IN FfxInt32 mipLevel, FFX_PARAMETER_IN FfxUInt32x2 iPxInput) + { + return texelFetch(r_inpainting_pyramid, FfxInt32x2(iPxInput), mipLevel); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_PRESENT_BACKBUFFER + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_PRESENT_BACKBUFFER) uniform texture2D r_present_backbuffer; + + FfxFloat32x4 LoadPresentBackbuffer(FFX_PARAMETER_IN FfxInt32x2 iPxInput) + { + return texelFetch(r_present_backbuffer, iPxInput, 0); + } + FfxFloat32x4 SamplePresentBackbuffer(FFX_PARAMETER_IN FfxFloat32x2 fUv) + { + return textureLod(sampler2D(r_present_backbuffer, s_LinearClamp), fUv, 0.0); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_SRV_COUNTERS + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_COUNTERS) readonly buffer FrameInterpolationCounters_t + { + FfxUInt32 data[]; + } r_counters; + + FfxUInt32 LoadCounter(FFX_PARAMETER_IN FfxInt32 iPxPos) + { + return r_counters.data[iPxPos]; + } + + FfxUInt32 FrameIndexSinceLastReset() + { + return LoadCounter(COUNTER_FRAME_INDEX_SINCE_LAST_RESET); + } +#endif + + +#if defined(FFX_FRAMEINTERPOLATION_BIND_SRV_INPUT_DEPTH) + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_INPUT_DEPTH) uniform texture2D r_input_depth; + + FfxFloat32 LoadInputDepth(FfxInt32x2 iPxPos) + { + return texelFetch(r_input_depth, iPxPos, 0).x; + } +#endif + +#if defined(FFX_FRAMEINTERPOLATION_BIND_SRV_INPUT_MOTION_VECTORS) + layout (set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors; + + FfxFloat32x2 LoadInputMotionVector(FfxInt32x2 iPxDilatedMotionVectorPos) + { + FfxFloat32x2 fSrcMotionVector = texelFetch(r_input_motion_vectors, iPxDilatedMotionVectorPos, 0).xy; + + FfxFloat32x2 fUvMotionVector = fSrcMotionVector * MotionVectorScale(); + + #if FFX_FRAMEINTERPOLATION_OPTION_JITTERED_MOTION_VECTORS + fUvMotionVector -= MotionVectorJitterCancellation(); + #endif + + return fUvMotionVector; + } +#endif + +#if defined(FFX_FRAMEINTERPOLATION_BIND_SRV_DISTORTION_FIELD) + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_SRV_DISTORTION_FIELD) uniform texture2D r_input_distortion_field; + FfxFloat32x2 SampleDistortionField(FFX_PARAMETER_IN FfxFloat32x2 fUv) + { + return textureLod(sampler2D(r_input_distortion_field, s_LinearClamp), fUv, 0.0).xy; + } +#endif + +/////////////////////////////////////////////// +// declare UAVs and UAV accessors +/////////////////////////////////////////////// +#ifdef FFX_FRAMEINTERPOLATION_BIND_UAV_OUTPUT + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_OUTPUT /* app controlled format */) uniform image2D rw_output; + + FfxFloat32x4 RWLoadFrameinterpolationOutput(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_output, iPxPos); + } + + void StoreFrameinterpolationOutput(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x4 val) + { + imageStore(rw_output, iPxPos, val); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_UAV_DILATED_MOTION_VECTORS + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_DILATED_MOTION_VECTORS, rg16f) uniform image2D rw_dilated_motion_vectors; + + FfxFloat32x2 RWLoadDilatedMotionVectors(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_dilated_motion_vectors, iPxPos).xy; + } + + void StoreDilatedMotionVectors(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 val) + { + imageStore(rw_dilated_motion_vectors, iPxPos, FfxFloat32x4(val, 0.0, 0.0)); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_UAV_DILATED_DEPTH + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_DILATED_DEPTH, r32f) uniform image2D rw_dilated_depth; + + FfxFloat32 RWLoadDilatedDepth(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_dilated_depth, iPxPos).x; + } + + void StoreDilatedDepth(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32 val) + { + imageStore(rw_dilated_depth, iPxPos, FfxFloat32x4(val, 0.0, 0.0, 0.0)); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_UAV_RECONSTRUCTED_DEPTH_PREVIOUS_FRAME + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_RECONSTRUCTED_DEPTH_PREVIOUS_FRAME, r32ui) uniform uimage2D rw_reconstructed_depth_previous_frame; + + FfxFloat32 RWLoadReconstructedDepthPreviousFrame(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return ffxAsFloat(imageLoad(rw_reconstructed_depth_previous_frame, iPxPos).x); + } + + void UpdateReconstructedDepthPreviousFrame(FfxInt32x2 iPxSample, FfxFloat32 fDepth) + { + FfxUInt32 uDepth = ffxAsUInt32(fDepth); + +#if FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH + imageAtomicMax(rw_reconstructed_depth_previous_frame, iPxSample, uDepth); +#else + imageAtomicMin(rw_reconstructed_depth_previous_frame, iPxSample, uDepth); // min for standard, max for inverted depth +#endif + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_UAV_RECONSTRUCTED_DEPTH_INTERPOLATED_FRAME + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_RECONSTRUCTED_DEPTH_INTERPOLATED_FRAME, r32ui) uniform uimage2D rw_reconstructed_depth_interpolated_frame; + + FfxFloat32 RWLoadReconstructedDepthInterpolatedFrame(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return ffxAsFloat(imageLoad(rw_reconstructed_depth_interpolated_frame, iPxPos).x); + } + + void StoreReconstructedDepthInterpolatedFrame(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32 value) + { + FfxUInt32 uDepth = ffxAsUInt32(value); + imageStore(rw_reconstructed_depth_interpolated_frame, iPxPos, FfxUInt32x4(uDepth, 0, 0, 0)); + } + + void UpdateReconstructedDepthInterpolatedFrame(FfxInt32x2 iPxSample, FfxFloat32 fDepth) + { + FfxUInt32 uDepth = ffxAsUInt32(fDepth); + +#if FFX_FRAMEINTERPOLATION_OPTION_INVERTED_DEPTH + imageAtomicMax(rw_reconstructed_depth_interpolated_frame, iPxSample, uDepth); +#else + imageAtomicMin(rw_reconstructed_depth_interpolated_frame, iPxSample, uDepth); // min for standard, max for inverted depth +#endif + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_UAV_DISOCCLUSION_MASK + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_DISOCCLUSION_MASK, rg8) uniform image2D rw_disocclusion_mask; + + FfxFloat32x2 RWLoadDisocclusionMask(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_disocclusion_mask, iPxPos).xy; + } + + void StoreDisocclusionMask(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 val) + { + imageStore(rw_disocclusion_mask, iPxPos, FfxFloat32x4(val, 0.0, 0.0)); + } +#endif + +#if defined(FFX_FRAMEINTERPOLATION_BIND_UAV_GAME_MOTION_VECTOR_FIELD_X) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_GAME_MOTION_VECTOR_FIELD_Y) + + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_GAME_MOTION_VECTOR_FIELD_X, r32ui) uniform uimage2D rw_game_motion_vector_field_x; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_GAME_MOTION_VECTOR_FIELD_Y, r32ui) uniform uimage2D rw_game_motion_vector_field_y; + + FfxUInt32 RWLoadGameMotionVectorFieldX(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_game_motion_vector_field_x, iPxPos).x; + } + + void StoreGameMotionVectorFieldX(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 val) + { + imageStore(rw_game_motion_vector_field_x, iPxPos, FfxUInt32x4(val, 0, 0, 0)); + } + + FfxUInt32 RWLoadGameMotionVectorFieldY(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_game_motion_vector_field_y, iPxPos).x; + } + + void StoreGameMotionVectorFieldY(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 val) + { + imageStore(rw_game_motion_vector_field_y, iPxPos, FfxUInt32x4(val, 0, 0, 0)); + } + + void UpdateGameMotionVectorField(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32x2 packedVector) + { + imageAtomicMax(rw_game_motion_vector_field_x, iPxPos, packedVector.x); + imageAtomicMax(rw_game_motion_vector_field_y, iPxPos, packedVector.y); + } + + FfxUInt32 UpdateGameMotionVectorFieldEx(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32x2 packedVector) + { + FfxUInt32 uPreviousValueX = imageAtomicMax(rw_game_motion_vector_field_x, iPxPos, packedVector.x); + FfxUInt32 uPreviousValueY = imageAtomicMax(rw_game_motion_vector_field_y, iPxPos, packedVector.y); + + const FfxUInt32 uExistingVectorFieldEntry = ffxMax(uPreviousValueX, uPreviousValueY); + + return uExistingVectorFieldEntry; + } +#endif + +#if defined(FFX_FRAMEINTERPOLATION_BIND_UAV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_X) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_Y) + + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_X, r32ui) uniform uimage2D rw_optical_flow_motion_vector_field_x; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_OPTICAL_FLOW_MOTION_VECTOR_FIELD_Y, r32ui) uniform uimage2D rw_optical_flow_motion_vector_field_y; + + FfxUInt32 RWLoadOpticalflowMotionVectorFieldX(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_optical_flow_motion_vector_field_x, iPxPos).x; + } + void StoreOpticalflowMotionVectorFieldX(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 val) + { + imageStore(rw_optical_flow_motion_vector_field_x, iPxPos, FfxUInt32x4(val, 0, 0, 0)); + } + FfxUInt32 RWLoadOpticalflowMotionVectorFieldY(FFX_PARAMETER_IN FfxInt32x2 iPxPos) + { + return imageLoad(rw_optical_flow_motion_vector_field_y, iPxPos).x; + } + void StoreOpticalflowMotionVectorFieldY(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 val) + { + imageStore(rw_optical_flow_motion_vector_field_y, iPxPos, FfxUInt32x4(val, 0, 0, 0)); + } + void UpdateOpticalflowMotionVectorField(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32x2 packedVector) + { + imageAtomicMax(rw_optical_flow_motion_vector_field_x, iPxPos, packedVector.x); + imageAtomicMax(rw_optical_flow_motion_vector_field_y, iPxPos, packedVector.y); + } +#endif + +#ifdef FFX_FRAMEINTERPOLATION_BIND_UAV_COUNTERS + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_COUNTERS) coherent buffer FrameInterpolationRWCounters_t + { + FfxUInt32 data[]; + } rw_counters; + + FfxUInt32 RWLoadCounter(FFX_PARAMETER_IN FfxInt32 iPxPos) + { + return rw_counters.data[iPxPos]; + } + + void StoreCounter(FFX_PARAMETER_IN FfxInt32 iPxPos, FFX_PARAMETER_IN FfxUInt32 counter) + { + rw_counters.data[iPxPos] = counter; + } + void AtomicIncreaseCounter(FFX_PARAMETER_IN FfxInt32 iPxPos, FFX_PARAMETER_OUT FfxUInt32 oldVal) + { + oldVal = atomicAdd(rw_counters.data[iPxPos], 1); + } +#endif + + +#if defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_0) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_1) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_2) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_3) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_4) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_5) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_6) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_7) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_8) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_9) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_10) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_11) && \ + defined(FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_12) + + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_0, rgba16f) uniform image2D rw_inpainting_pyramid0; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_1, rgba16f) uniform image2D rw_inpainting_pyramid1; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_2, rgba16f) uniform image2D rw_inpainting_pyramid2; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_3, rgba16f) uniform image2D rw_inpainting_pyramid3; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_4, rgba16f) uniform image2D rw_inpainting_pyramid4; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_5, rgba16f) coherent uniform image2D rw_inpainting_pyramid5; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_6, rgba16f) uniform image2D rw_inpainting_pyramid6; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_7, rgba16f) uniform image2D rw_inpainting_pyramid7; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_8, rgba16f) uniform image2D rw_inpainting_pyramid8; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_9, rgba16f) uniform image2D rw_inpainting_pyramid9; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_10, rgba16f) uniform image2D rw_inpainting_pyramid10; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_11, rgba16f) uniform image2D rw_inpainting_pyramid11; + layout(set = 0, binding = FFX_FRAMEINTERPOLATION_BIND_UAV_INPAINTING_PYRAMID_MIPMAP_12, rgba16f) uniform image2D rw_inpainting_pyramid12; + + + FfxFloat32x4 RWLoadInpaintingPyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 index) + { + #define LOAD(idx) \ + if (index == idx) \ + { \ + return imageLoad(rw_inpainting_pyramid##idx, iPxPos); \ + } + LOAD(0); + LOAD(1); + LOAD(2); + LOAD(3); + LOAD(4); + LOAD(5); + LOAD(6); + LOAD(7); + LOAD(8); + LOAD(9); + LOAD(10); + LOAD(11); + LOAD(12); + return FfxFloat32x4(0.0, 0.0, 0.0, 0.0); + + #undef LOAD + } + + void StoreInpaintingPyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x4 outValue, FFX_PARAMETER_IN FfxUInt32 index) + { + #define STORE(idx) \ + if (index == idx) \ + { \ + imageStore(rw_inpainting_pyramid##idx, iPxPos, outValue); \ + } + + STORE(0); + STORE(1); + STORE(2); + STORE(3); + STORE(4); + STORE(5); + STORE(6); + STORE(7); + STORE(8); + STORE(9); + STORE(10); + STORE(11); + STORE(12); + + #undef STORE + } +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr1/CMakeCompileFSR1Shaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr1/CMakeCompileFSR1Shaders.txt new file mode 100644 index 00000000..c0b592cd --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr1/CMakeCompileFSR1Shaders.txt @@ -0,0 +1,49 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(FSR1_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(FSR1_PERMUTATION_ARGS + # Reproject can use either reference lanczos or LUT + -DFFX_FSR1_OPTION_APPLY_RCAS={0,1} + -DFFX_FSR1_OPTION_RCAS_PASSTHROUGH_ALPHA={0,1} + -DFFX_FSR1_OPTION_SRGB_CONVERSIONS={0,1}) + +set(FSR1_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/fsr1") + +if (NOT FSR1_SHADER_EXT) + set(FSR1_SHADER_EXT *) +endif() + +file(GLOB FSR1_SHADERS + "shaders/fsr1/ffx_fsr1_easu_pass.${FSR1_SHADER_EXT}" + "shaders/fsr1/ffx_fsr1_rcas_pass.${FSR1_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${FSR1_BASE_ARGS}" "${FSR1_API_BASE_ARGS}" "${FSR1_PERMUTATION_ARGS}" "${FSR1_INCLUDE_ARGS}" + "${FSR1_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" FSR1_PERMUTATION_OUTPUTS) + +add_shader_output("${FSR1_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr1/ffx_fsr1_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr1/ffx_fsr1_callbacks_glsl.h new file mode 100644 index 00000000..c1909e63 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr1/ffx_fsr1_callbacks_glsl.h @@ -0,0 +1,219 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_fsr1_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(FSR1_BIND_CB_FSR1) + layout (set = 0, binding = FSR1_BIND_CB_FSR1, std140) uniform cbFSR1_t + { + FfxUInt32x4 const0; + FfxUInt32x4 const1; + FfxUInt32x4 const2; + FfxUInt32x4 const3; + FfxUInt32x4 sample0; + } cbFSR1; +#endif + +FfxUInt32x4 Const0() +{ + return cbFSR1.const0; +} + +FfxUInt32x4 Const1() +{ + return cbFSR1.const1; +} + +FfxUInt32x4 Const2() +{ + return cbFSR1.const2; +} + +FfxUInt32x4 Const3() +{ + return cbFSR1.const3; +} + +FfxUInt32x4 EASUSample() +{ + return cbFSR1.sample0; +} + +FfxUInt32x4 RCasSample() +{ + return cbFSR1.sample0; +} + +FfxUInt32x4 RCasConfig() +{ + return cbFSR1.const0; +} + +layout (set = 0, binding = 1000) uniform sampler s_LinearClamp; + + +// SRVs +#if defined FSR1_BIND_SRV_INPUT_COLOR + layout (set = 0, binding = FSR1_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color; +#endif +#if defined FSR1_BIND_SRV_INTERNAL_UPSCALED_COLOR + layout (set = 0, binding = FSR1_BIND_SRV_INTERNAL_UPSCALED_COLOR) uniform texture2D r_internal_upscaled_color; +#endif +#if defined FSR1_BIND_SRV_UPSCALED_OUTPUT + layout (set = 0, binding = FSR1_BIND_SRV_UPSCALED_OUTPUT) uniform texture2D r_upscaled_output; +#endif + +// UAV declarations +#if defined FSR1_BIND_UAV_INPUT_COLOR + layout (set = 0, binding = FSR1_BIND_UAV_INPUT_COLOR, rgba32f) uniform image2D rw_input_color; +#endif +#if defined FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR + layout (set = 0, binding = FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR, rgba32f) uniform image2D rw_internal_upscaled_color; +#endif +#if defined FSR1_BIND_UAV_UPSCALED_OUTPUT + layout (set = 0, binding = FSR1_BIND_UAV_UPSCALED_OUTPUT, rgba32f) uniform image2D rw_upscaled_output; +#endif + +#if FFX_HALF + +#if defined(FSR1_BIND_SRV_INPUT_COLOR) + FfxFloat16x4 GatherEasuRed(FfxFloat32x2 fPxPos) + { + return FfxFloat16x4(textureGather(sampler2D(r_input_color, s_LinearClamp), fPxPos, 0)); + } +#endif // defined(FSR1_BIND_SRV_INPUT_COLOR) + +#if defined(FSR1_BIND_SRV_INPUT_COLOR) + FfxFloat16x4 GatherEasuGreen(FfxFloat32x2 fPxPos) + { + return FfxFloat16x4(textureGather(sampler2D(r_input_color, s_LinearClamp), fPxPos, 1)); + } +#endif // defined(FSR1_BIND_SRV_INPUT_COLOR) + +#if defined(FSR1_BIND_SRV_INPUT_COLOR) + FfxFloat16x4 GatherEasuBlue(FfxFloat32x2 fPxPos) + { + return FfxFloat16x4(textureGather(sampler2D(r_input_color, s_LinearClamp), fPxPos, 2)); + } +#endif // defined(FSR1_BIND_SRV_INPUT_COLOR) + +#if FFX_FSR1_OPTION_APPLY_RCAS + #if defined(FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR) + void StoreEASUOutput(FfxUInt32x2 iPxPos, FfxFloat16x3 fColor) + { + imageStore(rw_internal_upscaled_color, FfxInt32x2(iPxPos), FfxFloat32x4(fColor, 1.f)); + } + #endif // #if defined(FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR) +#else + #if defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) + void StoreEASUOutput(FfxUInt32x2 iPxPos, FfxFloat16x3 fColor) + { + imageStore(rw_upscaled_output, FfxInt32x2(iPxPos), FfxFloat32x4(fColor, 1.f)); + } + #endif // #if defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) +#endif // #if FFX_FSR1_OPTION_APPLY_RCAS + +#if defined(FSR1_BIND_SRV_INTERNAL_UPSCALED_COLOR) + FfxFloat16x4 LoadRCas_Input(FfxInt16x2 iPxPos) + { + return FfxFloat16x4(texelFetch(r_internal_upscaled_color, FfxInt32x2(iPxPos), 0)); + } +#endif // defined(FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR) + +#if defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) + void StoreRCasOutputHx2(FfxInt16x2 iPxPos, FfxFloat16x2 fColorR, FfxFloat16x2 fColorG, FfxFloat16x2 fColorB, FfxFloat16x2 fColorA) + { + imageStore(rw_upscaled_output, FfxInt32x2(iPxPos), FfxFloat32x4(fColorR.x, fColorG.x, fColorB.x, fColorA.x)); + iPxPos.x += FfxInt16(8); + imageStore(rw_upscaled_output, FfxInt32x2(iPxPos), FfxFloat32x4(fColorR.y, fColorG.y, fColorB.y, fColorA.y)); + } + +#endif // defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) + +#else // FFX_HALF + +#if defined(FSR1_BIND_SRV_INPUT_COLOR) + FfxFloat32x4 GatherEasuRed(FfxFloat32x2 fPxPos) + { + return textureGather(sampler2D(r_input_color, s_LinearClamp), fPxPos, 0); + } +#endif // defined(FSR1_BIND_SRV_INPUT_COLOR) + +#if defined(FSR1_BIND_SRV_INPUT_COLOR) + FfxFloat32x4 GatherEasuGreen(FfxFloat32x2 fPxPos) + { + return textureGather(sampler2D(r_input_color, s_LinearClamp), fPxPos, 1); + } +#endif // defined(FSR1_BIND_SRV_INPUT_COLOR) + +#if defined(FSR1_BIND_SRV_INPUT_COLOR) + FfxFloat32x4 GatherEasuBlue(FfxFloat32x2 fPxPos) + { + return textureGather(sampler2D(r_input_color, s_LinearClamp), fPxPos, 2); + } +#endif // defined(FSR1_BIND_SRV_INPUT_COLOR) + +#if FFX_FSR1_OPTION_APPLY_RCAS + #if defined(FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR) + void StoreEASUOutput(FfxUInt32x2 iPxPos, FfxFloat32x3 fColor) + { + imageStore(rw_internal_upscaled_color, FfxInt32x2(iPxPos), FfxFloat32x4(fColor, 1.f)); + } + #endif // #if defined(FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR) +#else + #if defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) + void StoreEASUOutput(FfxUInt32x2 iPxPos, FfxFloat32x3 fColor) + { + imageStore(rw_upscaled_output, FfxInt32x2(iPxPos), FfxFloat32x4(fColor, 1.f)); + } + #endif // #if defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) +#endif // #if FFX_FSR1_OPTION_APPLY_RCAS + +#if defined(FSR1_BIND_SRV_INTERNAL_UPSCALED_COLOR) + FfxFloat32x4 LoadRCas_Input(FfxInt32x2 iPxPos) + { + return texelFetch(r_internal_upscaled_color, iPxPos, 0); + } +#endif // defined(FSR1_BIND_UAV_INTERNAL_UPSCALED_COLOR) + +#if defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) + void StoreRCasOutput(FfxInt32x2 iPxPos, FfxFloat32x4 fColor) + { + imageStore(rw_upscaled_output, iPxPos, fColor); + } + + void StoreRCasOutput(FfxInt32x2 iPxPos, FfxFloat32x3 fColor) + { + StoreRCasOutput(iPxPos, FfxFloat32x4(fColor, 1.f)); + } +#endif // defined(FSR1_BIND_UAV_UPSCALED_OUTPUT) + +#endif // FFX_HALF + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr2/CMakeCompileFSR2Shaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr2/CMakeCompileFSR2Shaders.txt new file mode 100644 index 00000000..d86462a7 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr2/CMakeCompileFSR2Shaders.txt @@ -0,0 +1,67 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(FSR2_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1 + + # Only reprojection is to do half for now + -DFFX_FSR2_OPTION_UPSAMPLE_SAMPLERS_USE_DATA_HALF=0 + -DFFX_FSR2_OPTION_ACCUMULATE_SAMPLERS_USE_DATA_HALF=0 + -DFFX_FSR2_OPTION_REPROJECT_SAMPLERS_USE_DATA_HALF=1 + -DFFX_FSR2_OPTION_POSTPROCESSLOCKSTATUS_SAMPLERS_USE_DATA_HALF=0 + + # Upsample uses lanczos approximation + -DFFX_FSR2_OPTION_UPSAMPLE_USE_LANCZOS_TYPE=2) + +set(FSR2_PERMUTATION_ARGS + # Reproject can use either reference lanczos or LUT + -DFFX_FSR2_OPTION_REPROJECT_USE_LANCZOS_TYPE={0,1} + -DFFX_FSR2_OPTION_HDR_COLOR_INPUT={0,1} + -DFFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS={0,1} + -DFFX_FSR2_OPTION_JITTERED_MOTION_VECTORS={0,1} + -DFFX_FSR2_OPTION_INVERTED_DEPTH={0,1} + -DFFX_FSR2_OPTION_APPLY_SHARPENING={0,1}) + +set(FSR2_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/fsr2") + +if (NOT FSR2_SHADER_EXT) + set(FSR2_SHADER_EXT *) +endif() + +file(GLOB FSR2_SHADERS + "shaders/fsr2/ffx_fsr2_accumulate_pass.${FSR2_SHADER_EXT}" + "shaders/fsr2/ffx_fsr2_autogen_reactive_pass.${FSR2_SHADER_EXT}" + "shaders/fsr2/ffx_fsr2_compute_luminance_pyramid_pass.${FSR2_SHADER_EXT}" + "shaders/fsr2/ffx_fsr2_depth_clip_pass.${FSR2_SHADER_EXT}" + "shaders/fsr2/ffx_fsr2_lock_pass.${FSR2_SHADER_EXT}" + "shaders/fsr2/ffx_fsr2_rcas_pass.${FSR2_SHADER_EXT}" + "shaders/fsr2/ffx_fsr2_reconstruct_previous_depth_pass.${FSR2_SHADER_EXT}" + "shaders/fsr2/ffx_fsr2_tcr_autogen_pass.${FSR2_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${FSR2_BASE_ARGS}" "${FSR2_API_BASE_ARGS}" "${FSR2_PERMUTATION_ARGS}" "${FSR2_INCLUDE_ARGS}" + "${FSR2_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" FSR2_PERMUTATION_OUTPUTS) + +add_shader_output("${FSR2_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr2/ffx_fsr2_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr2/ffx_fsr2_callbacks_glsl.h new file mode 100644 index 00000000..8d6964b6 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr2/ffx_fsr2_callbacks_glsl.h @@ -0,0 +1,855 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_fsr2_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(FSR2_BIND_CB_FSR2) + layout (set = 0, binding = FSR2_BIND_CB_FSR2, std140) uniform cbFSR2_t + { + FfxInt32x2 iRenderSize; + FfxInt32x2 iMaxRenderSize; + FfxInt32x2 iDisplaySize; + FfxInt32x2 iInputColorResourceDimensions; + FfxInt32x2 iLumaMipDimensions; + FfxInt32 iLumaMipLevelToUse; + FfxInt32 iFrameIndex; + + FfxFloat32x4 fDeviceToViewDepth; + FfxFloat32x2 fJitter; + FfxFloat32x2 fMotionVectorScale; + FfxFloat32x2 fDownscaleFactor; + FfxFloat32x2 fMotionVectorJitterCancellation; + FfxFloat32 fPreExposure; + FfxFloat32 fPreviousFramePreExposure; + FfxFloat32 fTanHalfFOV; + FfxFloat32 fJitterSequenceLength; + FfxFloat32 fDeltaTime; + FfxFloat32 fDynamicResChangeFactor; + FfxFloat32 fViewSpaceToMetersFactor; + } cbFSR2; + + +FfxInt32x2 RenderSize() +{ + return cbFSR2.iRenderSize; +} + +FfxInt32x2 MaxRenderSize() +{ + return cbFSR2.iMaxRenderSize; +} + +FfxInt32x2 DisplaySize() +{ + return cbFSR2.iDisplaySize; +} + +FfxInt32x2 InputColorResourceDimensions() +{ + return cbFSR2.iInputColorResourceDimensions; +} + +FfxInt32x2 LumaMipDimensions() +{ + return cbFSR2.iLumaMipDimensions; +} + +FfxInt32 LumaMipLevelToUse() +{ + return cbFSR2.iLumaMipLevelToUse; +} + +FfxInt32 FrameIndex() +{ + return cbFSR2.iFrameIndex; +} + +FfxFloat32x4 DeviceToViewSpaceTransformFactors() +{ + return cbFSR2.fDeviceToViewDepth; +} + +FfxFloat32x2 Jitter() +{ + return cbFSR2.fJitter; +} + +FfxFloat32x2 MotionVectorScale() +{ + return cbFSR2.fMotionVectorScale; +} + +FfxFloat32x2 DownscaleFactor() +{ + return cbFSR2.fDownscaleFactor; +} + +FfxFloat32x2 MotionVectorJitterCancellation() +{ + return cbFSR2.fMotionVectorJitterCancellation; +} + +FfxFloat32 PreExposure() +{ + return cbFSR2.fPreExposure; +} + +FfxFloat32 PreviousFramePreExposure() +{ + return cbFSR2.fPreviousFramePreExposure; +} + +FfxFloat32 TanHalfFoV() +{ + return cbFSR2.fTanHalfFOV; +} + +FfxFloat32 JitterSequenceLength() +{ + return cbFSR2.fJitterSequenceLength; +} + +FfxFloat32 DeltaTime() +{ + return cbFSR2.fDeltaTime; +} + +FfxFloat32 DynamicResChangeFactor() +{ + return cbFSR2.fDynamicResChangeFactor; +} + +FfxFloat32 ViewSpaceToMetersFactor() +{ + return cbFSR2.fViewSpaceToMetersFactor; +} + +#endif // #if defined(FSR2_BIND_CB_FSR2) + + +#ifdef FSR2_BIND_CB_AUTOREACTIVE +layout(set = 0, binding = FSR2_BIND_CB_AUTOREACTIVE, std140) uniform cbGenerateReactive_t +{ + FfxFloat32 fTcThreshold; + FfxFloat32 fTcScale; + FfxFloat32 fReactiveScale; + FfxFloat32 fReactiveMax; +} cbGenerateReactive; + +FfxFloat32 TcThreshold() +{ + return cbGenerateReactive.fTcThreshold; +} + +FfxFloat32 TcScale() +{ + return cbGenerateReactive.fTcScale; +} + +FfxFloat32 ReactiveScale() +{ + return cbGenerateReactive.fReactiveScale; +} + +FfxFloat32 ReactiveMax() +{ + return cbGenerateReactive.fReactiveMax; +} +#endif // #ifdef FSR2_BIND_CB_AUTOREACTIVE + +#if defined(FSR2_BIND_CB_RCAS) +layout(set = 0, binding = FSR2_BIND_CB_RCAS, std140) uniform cbRCAS_t +{ + FfxUInt32x4 rcasConfig; +} cbRCAS; + +FfxUInt32x4 RCASConfig() +{ + return cbRCAS.rcasConfig; +} +#endif // #if defined(FSR2_BIND_CB_RCAS) + + +#if defined(FSR2_BIND_CB_REACTIVE) +layout(set = 0, binding = FSR2_BIND_CB_REACTIVE, std140) uniform cbGenerateReactive_t +{ + FfxFloat32 scale; + FfxFloat32 threshold; + FfxFloat32 binaryValue; + FfxUInt32 flags; +} cbGenerateReactive; + +FfxFloat32 GenReactiveScale() +{ + return cbGenerateReactive.scale; +} + +FfxFloat32 GenReactiveThreshold() +{ + return cbGenerateReactive.threshold; +} + +FfxFloat32 GenReactiveBinaryValue() +{ + return cbGenerateReactive.binaryValue; +} + +FfxUInt32 GenReactiveFlags() +{ + return cbGenerateReactive.flags; +} +#endif // #if defined(FSR2_BIND_CB_REACTIVE) + + +#if defined(FSR2_BIND_CB_SPD) +layout(set = 0, binding = FSR2_BIND_CB_SPD, std140) uniform cbSPD_t +{ + FfxUInt32 mips; + FfxUInt32 numWorkGroups; + FfxUInt32x2 workGroupOffset; + FfxUInt32x2 renderSize; +} cbSPD; + +FfxUInt32 MipCount() +{ + return cbSPD.mips; +} + +FfxUInt32 NumWorkGroups() +{ + return cbSPD.numWorkGroups; +} + +FfxUInt32x2 WorkGroupOffset() +{ + return cbSPD.workGroupOffset; +} + +FfxUInt32x2 SPD_RenderSize() +{ + return cbSPD.renderSize; +} +#endif // #if defined(FSR2_BIND_CB_SPD) + +layout (set = 0, binding = 1000) uniform sampler s_PointClamp; +layout (set = 0, binding = 1001) uniform sampler s_LinearClamp; + +// SRVs +#if defined(FSR2_BIND_SRV_INPUT_OPAQUE_ONLY) + layout (set = 0, binding = FSR2_BIND_SRV_INPUT_OPAQUE_ONLY) uniform texture2D r_input_opaque_only; +#endif +#if defined(FSR2_BIND_SRV_INPUT_COLOR) + layout (set = 0, binding = FSR2_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color_jittered; +#endif +#if defined(FSR2_BIND_SRV_INPUT_MOTION_VECTORS) + layout (set = 0, binding = FSR2_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors; +#endif +#if defined(FSR2_BIND_SRV_INPUT_DEPTH) + layout (set = 0, binding = FSR2_BIND_SRV_INPUT_DEPTH) uniform texture2D r_input_depth; +#endif +#if defined(FSR2_BIND_SRV_INPUT_EXPOSURE) + layout (set = 0, binding = FSR2_BIND_SRV_INPUT_EXPOSURE) uniform texture2D r_input_exposure; +#endif +#if defined(FSR2_BIND_SRV_AUTO_EXPOSURE) + layout(set = 0, binding = FSR2_BIND_SRV_AUTO_EXPOSURE) uniform texture2D r_auto_exposure; +#endif +#if defined(FSR2_BIND_SRV_REACTIVE_MASK) + layout (set = 0, binding = FSR2_BIND_SRV_REACTIVE_MASK) uniform texture2D r_reactive_mask; +#endif +#if defined(FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK) + layout (set = 0, binding = FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK) uniform texture2D r_transparency_and_composition_mask; +#endif +#if defined(FSR2_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH) + layout (set = 0, binding = FSR2_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH) uniform utexture2D r_reconstructed_previous_nearest_depth; +#endif +#if defined(FSR2_BIND_SRV_DILATED_MOTION_VECTORS) + layout (set = 0, binding = FSR2_BIND_SRV_DILATED_MOTION_VECTORS) uniform texture2D r_dilated_motion_vectors; +#endif +#if defined (FSR2_BIND_SRV_PREVIOUS_DILATED_MOTION_VECTORS) + layout(set = 0, binding = FSR2_BIND_SRV_PREVIOUS_DILATED_MOTION_VECTORS) uniform texture2D r_previous_dilated_motion_vectors; +#endif +#if defined(FSR2_BIND_SRV_DILATED_DEPTH) + layout (set = 0, binding = FSR2_BIND_SRV_DILATED_DEPTH) uniform texture2D r_dilatedDepth; +#endif +#if defined(FSR2_BIND_SRV_INTERNAL_UPSCALED) + layout (set = 0, binding = FSR2_BIND_SRV_INTERNAL_UPSCALED) uniform texture2D r_internal_upscaled_color; +#endif +#if defined(FSR2_BIND_SRV_LOCK_STATUS) + layout (set = 0, binding = FSR2_BIND_SRV_LOCK_STATUS) uniform texture2D r_lock_status; +#endif +#if defined(FSR2_BIND_SRV_LOCK_INPUT_LUMA) + layout (set = 0, binding = FSR2_BIND_SRV_LOCK_INPUT_LUMA) uniform texture2D r_lock_input_luma; +#endif +#if defined(FSR2_BIND_SRV_NEW_LOCKS) + layout(set = 0, binding = FSR2_BIND_SRV_NEW_LOCKS) uniform texture2D r_new_locks; +#endif +#if defined(FSR2_BIND_SRV_PREPARED_INPUT_COLOR) + layout (set = 0, binding = FSR2_BIND_SRV_PREPARED_INPUT_COLOR) uniform texture2D r_prepared_input_color; +#endif +#if defined(FSR2_BIND_SRV_LUMA_HISTORY) + layout (set = 0, binding = FSR2_BIND_SRV_LUMA_HISTORY) uniform texture2D r_luma_history; +#endif +#if defined(FSR2_BIND_SRV_RCAS_INPUT) + layout (set = 0, binding = FSR2_BIND_SRV_RCAS_INPUT) uniform texture2D r_rcas_input; +#endif +#if defined(FSR2_BIND_SRV_LANCZOS_LUT) + layout (set = 0, binding = FSR2_BIND_SRV_LANCZOS_LUT) uniform texture2D r_lanczos_lut; +#endif +#if defined(FSR2_BIND_SRV_SCENE_LUMINANCE_MIPS) + layout (set = 0, binding = FSR2_BIND_SRV_SCENE_LUMINANCE_MIPS) uniform texture2D r_imgMips; +#endif +#if defined(FSR2_BIND_SRV_UPSCALE_MAXIMUM_BIAS_LUT) + layout (set = 0, binding = FSR2_BIND_SRV_UPSCALE_MAXIMUM_BIAS_LUT) uniform texture2D r_upsample_maximum_bias_lut; +#endif +#if defined(FSR2_BIND_SRV_DILATED_REACTIVE_MASKS) + layout (set = 0, binding = FSR2_BIND_SRV_DILATED_REACTIVE_MASKS) uniform texture2D r_dilated_reactive_masks; +#endif +#if defined(FSR2_BIND_SRV_PREV_PRE_ALPHA_COLOR) + layout(set = 0, binding = FSR2_BIND_SRV_PREV_PRE_ALPHA_COLOR) uniform texture2D r_input_prev_color_pre_alpha; +#endif +#if defined(FSR2_BIND_SRV_PREV_POST_ALPHA_COLOR) + layout(set = 0, binding = FSR2_BIND_SRV_PREV_POST_ALPHA_COLOR) uniform texture2D r_input_prev_color_post_alpha; +#endif + +// UAV +#if defined FSR2_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH + layout (set = 0, binding = FSR2_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH, r32ui) uniform uimage2D rw_reconstructed_previous_nearest_depth; +#endif +#if defined FSR2_BIND_UAV_DILATED_MOTION_VECTORS + layout (set = 0, binding = FSR2_BIND_UAV_DILATED_MOTION_VECTORS, rg16f) writeonly uniform image2D rw_dilated_motion_vectors; +#endif +#if defined FSR2_BIND_UAV_DILATED_DEPTH + layout (set = 0, binding = FSR2_BIND_UAV_DILATED_DEPTH, r16f) writeonly uniform image2D rw_dilatedDepth; +#endif +#if defined FSR2_BIND_UAV_INTERNAL_UPSCALED + layout (set = 0, binding = FSR2_BIND_UAV_INTERNAL_UPSCALED, rgba16f) writeonly uniform image2D rw_internal_upscaled_color; +#endif +#if defined FSR2_BIND_UAV_LOCK_STATUS + layout (set = 0, binding = FSR2_BIND_UAV_LOCK_STATUS, rg16f) uniform image2D rw_lock_status; +#endif +#if defined(FSR2_BIND_UAV_LOCK_INPUT_LUMA) + layout(set = 0, binding = FSR2_BIND_UAV_LOCK_INPUT_LUMA, r16f) writeonly uniform image2D rw_lock_input_luma; +#endif +#if defined FSR2_BIND_UAV_NEW_LOCKS + layout(set = 0, binding = FSR2_BIND_UAV_NEW_LOCKS, r8) uniform image2D rw_new_locks; +#endif +#if defined FSR2_BIND_UAV_PREPARED_INPUT_COLOR + layout (set = 0, binding = FSR2_BIND_UAV_PREPARED_INPUT_COLOR, rgba16) writeonly uniform image2D rw_prepared_input_color; +#endif +#if defined FSR2_BIND_UAV_LUMA_HISTORY + layout (set = 0, binding = FSR2_BIND_UAV_LUMA_HISTORY, rgba8) uniform image2D rw_luma_history; +#endif +#if defined FSR2_BIND_UAV_UPSCALED_OUTPUT + layout (set = 0, binding = FSR2_BIND_UAV_UPSCALED_OUTPUT /* app controlled format */) writeonly uniform image2D rw_upscaled_output; +#endif +#if defined FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE + layout (set = 0, binding = FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE, r16f) coherent uniform image2D rw_img_mip_shading_change; +#endif +#if defined FSR2_BIND_UAV_EXPOSURE_MIP_5 + layout (set = 0, binding = FSR2_BIND_UAV_EXPOSURE_MIP_5, r16f) coherent uniform image2D rw_img_mip_5; +#endif +#if defined FSR2_BIND_UAV_DILATED_REACTIVE_MASKS + layout (set = 0, binding = FSR2_BIND_UAV_DILATED_REACTIVE_MASKS, rg8) writeonly uniform image2D rw_dilated_reactive_masks; +#endif +#if defined FSR2_BIND_UAV_EXPOSURE + layout (set = 0, binding = FSR2_BIND_UAV_EXPOSURE, rg32f) uniform image2D rw_exposure; +#endif +#if defined FSR2_BIND_UAV_AUTO_EXPOSURE + layout(set = 0, binding = FSR2_BIND_UAV_AUTO_EXPOSURE, rg32f) uniform image2D rw_auto_exposure; +#endif +#if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC + layout (set = 0, binding = FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC, r32ui) coherent uniform uimage2D rw_spd_global_atomic; +#endif + +#if defined FSR2_BIND_UAV_AUTOREACTIVE + layout(set = 0, binding = FSR2_BIND_UAV_AUTOREACTIVE, r32f) uniform image2D rw_output_autoreactive; +#endif +#if defined FSR2_BIND_UAV_AUTOCOMPOSITION + layout(set = 0, binding = FSR2_BIND_UAV_AUTOCOMPOSITION, r32f) uniform image2D rw_output_autocomposition; +#endif +#if defined FSR2_BIND_UAV_PREV_PRE_ALPHA_COLOR + layout(set = 0, binding = FSR2_BIND_UAV_PREV_PRE_ALPHA_COLOR, r11f_g11f_b10f) uniform image2D rw_output_prev_color_pre_alpha; +#endif +#if defined FSR2_BIND_UAV_PREV_POST_ALPHA_COLOR + layout(set = 0, binding = FSR2_BIND_UAV_PREV_POST_ALPHA_COLOR, r11f_g11f_b10f) uniform image2D rw_output_prev_color_post_alpha; +#endif + +#if defined(FSR2_BIND_SRV_SCENE_LUMINANCE_MIPS) +FfxFloat32 LoadMipLuma(FfxInt32x2 iPxPos, FfxInt32 mipLevel) +{ + return texelFetch(r_imgMips, iPxPos, FfxInt32(mipLevel)).r; +} +#endif + +#if defined(FSR2_BIND_SRV_SCENE_LUMINANCE_MIPS) +FfxFloat32 SampleMipLuma(FfxFloat32x2 fUV, FfxInt32 mipLevel) +{ + return textureLod(sampler2D(r_imgMips, s_LinearClamp), fUV, FfxFloat32(mipLevel)).r; +} +#endif + +#if defined(FSR2_BIND_SRV_INPUT_DEPTH) +FfxFloat32 LoadInputDepth(FfxInt32x2 iPxPos) +{ + return texelFetch(r_input_depth, iPxPos, 0).r; +} +#endif + +#if defined(FSR2_BIND_SRV_REACTIVE_MASK) +FfxFloat32 LoadReactiveMask(FfxInt32x2 iPxPos) +{ + return texelFetch(r_reactive_mask, FfxInt32x2(iPxPos), 0).r; +} +#endif + +#if defined(FSR2_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK) +FfxFloat32 LoadTransparencyAndCompositionMask(FfxUInt32x2 iPxPos) +{ + return texelFetch(r_transparency_and_composition_mask, FfxInt32x2(iPxPos), 0).r; +} +#endif + +#if defined(FSR2_BIND_SRV_INPUT_COLOR) +FfxFloat32x3 LoadInputColor(FfxInt32x2 iPxPos) +{ + return texelFetch(r_input_color_jittered, iPxPos, 0).rgb; +} +#endif + +#if defined(FSR2_BIND_SRV_INPUT_COLOR) +FfxFloat32x3 SampleInputColor(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_input_color_jittered, s_LinearClamp), fUV, 0.0f).rgb; +} +#endif + +#if defined(FSR2_BIND_SRV_PREPARED_INPUT_COLOR) +FfxFloat32x3 LoadPreparedInputColor(FfxInt32x2 iPxPos) +{ + return texelFetch(r_prepared_input_color, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR2_BIND_SRV_INPUT_MOTION_VECTORS) +FfxFloat32x2 LoadInputMotionVector(FfxInt32x2 iPxDilatedMotionVectorPos) +{ + FfxFloat32x2 fSrcMotionVector = texelFetch(r_input_motion_vectors, iPxDilatedMotionVectorPos, 0).xy; + + FfxFloat32x2 fUvMotionVector = fSrcMotionVector * MotionVectorScale(); + +#if FFX_FSR2_OPTION_JITTERED_MOTION_VECTORS + fUvMotionVector -= MotionVectorJitterCancellation(); +#endif + + return fUvMotionVector; +} +#endif + +#if defined(FSR2_BIND_SRV_INTERNAL_UPSCALED) +FfxFloat32x4 LoadHistory(FfxInt32x2 iPxHistory) +{ + return texelFetch(r_internal_upscaled_color, iPxHistory, 0); +} +#endif + +#if defined(FSR2_BIND_UAV_LUMA_HISTORY) +void StoreLumaHistory(FfxInt32x2 iPxPos, FfxFloat32x4 fLumaHistory) +{ + imageStore(rw_luma_history, FfxInt32x2(iPxPos), fLumaHistory); +} +#endif + +#if defined(FSR2_BIND_SRV_LUMA_HISTORY) +FfxFloat32x4 SampleLumaHistory(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_luma_history, s_LinearClamp), fUV, 0.0f); +} +#endif + +FfxFloat32x4 LoadRCAS_Input(FfxInt32x2 iPxPos) +{ +#if defined(FSR2_BIND_SRV_RCAS_INPUT) + return texelFetch(r_rcas_input, iPxPos, 0); +#else + return FfxFloat32x4(0.0); +#endif +} + +#if defined(FSR2_BIND_UAV_INTERNAL_UPSCALED) +void StoreReprojectedHistory(FfxInt32x2 iPxHistory, FfxFloat32x4 fHistory) +{ + imageStore(rw_internal_upscaled_color, iPxHistory, fHistory); +} +#endif + +#if defined(FSR2_BIND_UAV_INTERNAL_UPSCALED) +void StoreInternalColorAndWeight(FfxInt32x2 iPxPos, FfxFloat32x4 fColorAndWeight) +{ + imageStore(rw_internal_upscaled_color, FfxInt32x2(iPxPos), fColorAndWeight); +} +#endif + +#if defined(FSR2_BIND_UAV_UPSCALED_OUTPUT) +void StoreUpscaledOutput(FfxInt32x2 iPxPos, FfxFloat32x3 fColor) +{ + imageStore(rw_upscaled_output, FfxInt32x2(iPxPos), FfxFloat32x4(fColor, 1.f)); +} +#endif + +#if defined(FSR2_BIND_SRV_LOCK_STATUS) +FfxFloat32x2 LoadLockStatus(FfxInt32x2 iPxPos) +{ + FfxFloat32x2 fLockStatus = texelFetch(r_lock_status, iPxPos, 0).rg; + + return fLockStatus; +} +#endif + +#if defined(FSR2_BIND_UAV_LOCK_STATUS) +void StoreLockStatus(FfxInt32x2 iPxPos, FfxFloat32x2 fLockstatus) +{ + imageStore(rw_lock_status, iPxPos, vec4(fLockstatus, 0.0f, 0.0f)); +} +#endif + +#if defined(FSR2_BIND_SRV_LOCK_INPUT_LUMA) +FfxFloat32 LoadLockInputLuma(FfxInt32x2 iPxPos) +{ + return texelFetch(r_lock_input_luma, iPxPos, 0).r; +} +#endif + +#if defined(FSR2_BIND_UAV_LOCK_INPUT_LUMA) +void StoreLockInputLuma(FfxInt32x2 iPxPos, FfxFloat32 fLuma) +{ + imageStore(rw_lock_input_luma, iPxPos, vec4(fLuma, 0, 0, 0)); +} +#endif + +#if defined(FSR2_BIND_SRV_NEW_LOCKS) +FfxFloat32 LoadNewLocks(FfxInt32x2 iPxPos) +{ + return texelFetch(r_new_locks, iPxPos, 0).r; +} +#endif + +#if defined(FSR2_BIND_UAV_NEW_LOCKS) +FfxFloat32 LoadRwNewLocks(FfxInt32x2 iPxPos) +{ + return imageLoad(rw_new_locks, iPxPos).r; +} +#endif + +#if defined(FSR2_BIND_UAV_NEW_LOCKS) +void StoreNewLocks(FfxInt32x2 iPxPos, FfxFloat32 newLock) +{ + imageStore(rw_new_locks, iPxPos, vec4(newLock, 0, 0, 0)); +} +#endif + +#if defined(FSR2_BIND_UAV_PREPARED_INPUT_COLOR) +void StorePreparedInputColor(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x4 fTonemapped) +{ + imageStore(rw_prepared_input_color, iPxPos, fTonemapped); +} +#endif + +#if defined(FSR2_BIND_SRV_PREPARED_INPUT_COLOR) +FfxFloat32 SampleDepthClip(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_prepared_input_color, s_LinearClamp), fUV, 0.0f).w; +} +#endif + +#if defined(FSR2_BIND_SRV_LOCK_STATUS) +FfxFloat32x2 SampleLockStatus(FfxFloat32x2 fUV) +{ + FfxFloat32x2 fLockStatus = textureLod(sampler2D(r_lock_status, s_LinearClamp), fUV, 0.0f).rg; + return fLockStatus; +} +#endif + +#if defined(FSR2_BIND_SRV_DEPTH) +FfxFloat32 LoadSceneDepth(FfxInt32x2 iPxInput) +{ + return texelFetch(r_input_depth, iPxInput, 0).r; +} +#endif + +#if defined(FSR2_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH) +FfxFloat32 LoadReconstructedPrevDepth(FfxInt32x2 iPxPos) +{ + return uintBitsToFloat(texelFetch(r_reconstructed_previous_nearest_depth, iPxPos, 0).r); +} +#endif + +#if defined(FSR2_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH) +void StoreReconstructedDepth(FfxInt32x2 iPxSample, FfxFloat32 fDepth) +{ + FfxUInt32 uDepth = floatBitsToUint(fDepth); + + #if FFX_FSR2_OPTION_INVERTED_DEPTH + imageAtomicMax(rw_reconstructed_previous_nearest_depth, iPxSample, uDepth); + #else + imageAtomicMin(rw_reconstructed_previous_nearest_depth, iPxSample, uDepth); // min for standard, max for inverted depth + #endif +} +#endif + +#if defined(FSR2_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH) +void SetReconstructedDepth(FfxInt32x2 iPxSample, FfxUInt32 uValue) +{ + imageStore(rw_reconstructed_previous_nearest_depth, iPxSample, uvec4(uValue, 0, 0, 0)); +} +#endif + +#if defined(FSR2_BIND_UAV_DILATED_DEPTH) +void StoreDilatedDepth(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32 fDepth) +{ + //FfxUInt32 uDepth = ffxF32ToF16(fDepth); + imageStore(rw_dilatedDepth, iPxPos, vec4(fDepth, 0.0f, 0.0f, 0.0f)); +} +#endif + +#if defined(FSR2_BIND_UAV_DILATED_MOTION_VECTORS) +void StoreDilatedMotionVector(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 fMotionVector) +{ + imageStore(rw_dilated_motion_vectors, iPxPos, vec4(fMotionVector, 0.0f, 0.0f)); +} +#endif + +#if defined(FSR2_BIND_SRV_DILATED_MOTION_VECTORS) +FfxFloat32x2 LoadDilatedMotionVector(FfxInt32x2 iPxInput) +{ + return texelFetch(r_dilated_motion_vectors, iPxInput, 0).rg; +} +#endif + +#if defined(FSR2_BIND_SRV_DILATED_MOTION_VECTORS) +FfxFloat32x2 SampleDilatedMotionVector(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_motion_vectors, s_LinearClamp), fUV, 0.0f).rg; +} +#endif + +#if defined(FSR2_BIND_SRV_PREVIOUS_DILATED_MOTION_VECTORS) +FfxFloat32x2 LoadPreviousDilatedMotionVector(FfxInt32x2 iPxInput) +{ + return texelFetch(r_previous_dilated_motion_vectors, iPxInput, 0).rg; +} + +FfxFloat32x2 SamplePreviousDilatedMotionVector(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_previous_dilated_motion_vectors, s_LinearClamp), fUV, 0.0f).xy; +} +#endif + +#if defined(FSR2_BIND_SRV_DILATED_DEPTH) +FfxFloat32 LoadDilatedDepth(FfxInt32x2 iPxInput) +{ + return texelFetch(r_dilatedDepth, iPxInput, 0).r; +} +#endif + +#if defined(FSR2_BIND_SRV_INPUT_EXPOSURE) +FfxFloat32 Exposure() +{ + FfxFloat32 exposure = texelFetch(r_input_exposure, FfxInt32x2(0, 0), 0).x; + + if (exposure == 0.0f) { + exposure = 1.0f; + } + + return exposure; +} +#endif + +#if defined(FSR2_BIND_SRV_AUTO_EXPOSURE) +FfxFloat32 AutoExposure() +{ + FfxFloat32 exposure = texelFetch(r_auto_exposure, FfxInt32x2(0, 0), 0).x; + + if (exposure == 0.0f) { + exposure = 1.0f; + } + + return exposure; +} +#endif + +FfxFloat32 SampleLanczos2Weight(FfxFloat32 x) +{ +#if defined(FSR2_BIND_SRV_LANCZOS_LUT) + return textureLod(sampler2D(r_lanczos_lut, s_LinearClamp), FfxFloat32x2(x / 2.0f, 0.5f), 0.0f).x; +#else + return 0.f; +#endif +} + +#if defined(FSR2_BIND_SRV_UPSCALE_MAXIMUM_BIAS_LUT) +FfxFloat32 SampleUpsampleMaximumBias(FfxFloat32x2 uv) +{ + // Stored as a SNORM, so make sure to multiply by 2 to retrieve the actual expected range. + return FfxFloat32(2.0f) * FfxFloat32(textureLod(sampler2D(r_upsample_maximum_bias_lut, s_LinearClamp), abs(uv) * 2.0f, 0.0f).r); +} +#endif + +#if defined(FSR2_BIND_SRV_DILATED_REACTIVE_MASKS) +FfxFloat32x2 SampleDilatedReactiveMasks(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_reactive_masks, s_LinearClamp), fUV, 0.0f).rg; +} +#endif + +#if defined(FSR2_BIND_SRV_DILATED_REACTIVE_MASKS) +FfxFloat32x2 LoadDilatedReactiveMasks(FFX_PARAMETER_IN FfxInt32x2 iPxPos) +{ + return texelFetch(r_dilated_reactive_masks, iPxPos, 0).rg; +} +#endif + +#if defined(FSR2_BIND_UAV_DILATED_REACTIVE_MASKS) +void StoreDilatedReactiveMasks(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 fDilatedReactiveMasks) +{ + imageStore(rw_dilated_reactive_masks, iPxPos, vec4(fDilatedReactiveMasks, 0.0f, 0.0f)); +} +#endif + +#if defined(FSR2_BIND_SRV_INPUT_OPAQUE_ONLY) +FfxFloat32x3 LoadOpaqueOnly(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_opaque_only, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR2_BIND_SRV_PREV_PRE_ALPHA_COLOR) +FfxFloat32x3 LoadPrevPreAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_prev_color_pre_alpha, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR2_BIND_SRV_PREV_POST_ALPHA_COLOR) +FfxFloat32x3 LoadPrevPostAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_prev_color_post_alpha, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR2_BIND_UAV_AUTOREACTIVE) +#if defined(FSR2_BIND_UAV_AUTOCOMPOSITION) +void StoreAutoReactive(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F2 fReactive) +{ + imageStore(rw_output_autoreactive, iPxPos, vec4(FfxFloat32(fReactive.x), 0.0f, 0.0f, 0.0f)); + + imageStore(rw_output_autocomposition, iPxPos, vec4(FfxFloat32(fReactive.y), 0.0f, 0.0f, 0.0f)); +} +#endif +#endif + +#if defined(FSR2_BIND_UAV_PREV_PRE_ALPHA_COLOR) +void StorePrevPreAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F3 color) +{ + imageStore(rw_output_prev_color_pre_alpha, iPxPos, vec4(color, 0.0f)); +} +#endif + +#if defined(FSR2_BIND_UAV_PREV_POST_ALPHA_COLOR) +void StorePrevPostAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F3 color) +{ + imageStore(rw_output_prev_color_post_alpha, iPxPos, vec4(color, 0.0f)); +} +#endif + +FfxFloat32x2 SPD_LoadExposureBuffer() +{ +#if defined FSR2_BIND_UAV_AUTO_EXPOSURE + return imageLoad(rw_auto_exposure, ivec2(0, 0)).xy; +#else + return FfxFloat32x2(0.f, 0.f); +#endif // #if defined FSR2_BIND_UAV_AUTO_EXPOSURE +} + +void SPD_SetExposureBuffer(FfxFloat32x2 value) +{ +#if defined FSR2_BIND_UAV_AUTO_EXPOSURE + imageStore(rw_auto_exposure, ivec2(0, 0), vec4(value, 0.0f, 0.0f)); +#endif // #if defined FSR2_BIND_UAV_AUTO_EXPOSURE +} + +FfxFloat32x4 SPD_LoadMipmap5(FfxInt32x2 iPxPos) +{ +#if defined FSR2_BIND_UAV_EXPOSURE_MIP_5 + return FfxFloat32x4(imageLoad(rw_img_mip_5, iPxPos).x, 0.0f, 0.0f, 0.0f); +#else + return FfxFloat32x4(0.f, 0.f, 0.f, 0.f); +#endif // #if defined FSR2_BIND_UAV_EXPOSURE_MIP_5 +} + +void SPD_SetMipmap(FfxInt32x2 iPxPos, FfxUInt32 slice, FfxFloat32 value) +{ + switch (slice) + { + case FFX_FSR2_SHADING_CHANGE_MIP_LEVEL: +#if defined FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE + imageStore(rw_img_mip_shading_change, iPxPos, FfxFloat32x4(value, 0.0f, 0.0f, 0.0f)); +#endif // #if defined FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE + break; + case 5: +#if defined FSR2_BIND_UAV_EXPOSURE_MIP_5 + imageStore(rw_img_mip_5, iPxPos, FfxFloat32x4(value, 0.0f, 0.0f, 0.0f)); +#endif // #if defined FSR2_BIND_UAV_EXPOSURE_MIP_5 + break; + default: + + // avoid flattened side effect +#if defined(FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE) + imageStore(rw_img_mip_shading_change, iPxPos, FfxFloat32x4(imageLoad(rw_img_mip_shading_change, iPxPos).x, 0.0f, 0.0f, 0.0f)); +#elif defined(FSR2_BIND_UAV_EXPOSURE_MIP_5) + imageStore(rw_img_mip_5, iPxPos, FfxFloat32x4(imageLoad(rw_img_mip_5, iPxPos).x, 0.0f, 0.0f, 0.0f)); +#endif // #if defined FSR2_BIND_UAV_EXPOSURE_MIP_LUMA_CHANGE + break; + } +} + +void SPD_IncreaseAtomicCounter(inout FfxUInt32 spdCounter) +{ +#if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC + spdCounter = imageAtomicAdd(rw_spd_global_atomic, ivec2(0, 0), 1); +#endif // #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC +} + +void SPD_ResetAtomicCounter() +{ +#if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC + imageStore(rw_spd_global_atomic, ivec2(0, 0), uvec4(0)); +#endif // #if defined FSR2_BIND_UAV_SPD_GLOBAL_ATOMIC +} + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr3upscaler/CMakeCompileFSR3UpscalerShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr3upscaler/CMakeCompileFSR3UpscalerShaders.txt new file mode 100644 index 00000000..fcba2727 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr3upscaler/CMakeCompileFSR3UpscalerShaders.txt @@ -0,0 +1,62 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(FSR3UPSCALER_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1 + + # Only reprojection is to do half for now + -DFFX_FSR3UPSCALER_OPTION_UPSAMPLE_SAMPLERS_USE_DATA_HALF=0 + -DFFX_FSR3UPSCALER_OPTION_ACCUMULATE_SAMPLERS_USE_DATA_HALF=0 + -DFFX_FSR3UPSCALER_OPTION_REPROJECT_SAMPLERS_USE_DATA_HALF=1 + -DFFX_FSR3UPSCALER_OPTION_POSTPROCESSLOCKSTATUS_SAMPLERS_USE_DATA_HALF=0 + + # Upsample uses lanczos approximation + -DFFX_FSR3UPSCALER_OPTION_UPSAMPLE_USE_LANCZOS_TYPE=2) + +set(FSR3UPSCALER_PERMUTATION_ARGS + # Reproject can use either reference lanczos or LUT + -DFFX_FSR3UPSCALER_OPTION_REPROJECT_USE_LANCZOS_TYPE={0,1} + -DFFX_FSR3UPSCALER_OPTION_HDR_COLOR_INPUT={0,1} + -DFFX_FSR3UPSCALER_OPTION_LOW_RESOLUTION_MOTION_VECTORS={0,1} + -DFFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS={0,1} + -DFFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH={0,1} + -DFFX_FSR3UPSCALER_OPTION_APPLY_SHARPENING={0,1}) + +set(FSR3UPSCALER_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/fsr3upscaler") + +if (NOT FSR3UPSCALER_SHADER_EXT) + set(FSR3UPSCALER_SHADER_EXT *) +endif() + +file(GLOB FSR3UPSCALER_SHADERS + "shaders/fsr3upscaler/*.${FSR3UPSCALER_SHADER_EXT}") + +# compile all the shaders +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${FSR3UPSCALER_BASE_ARGS}" "${FSR3UPSCALER_API_BASE_ARGS}" "${FSR3UPSCALER_PERMUTATION_ARGS}" "${FSR3UPSCALER_INCLUDE_ARGS}" + "${FSR3UPSCALER_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" FSR3UPSCALER_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${FSR3UPSCALER_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_callbacks_glsl.h new file mode 100644 index 00000000..d0cbf9d3 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/fsr3upscaler/ffx_fsr3upscaler_callbacks_glsl.h @@ -0,0 +1,903 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_fsr3upscaler_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" +#endif // #if defined(FFX_GPU) + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // FFX_PREFER_WAVE64 + +#if defined(FSR3UPSCALER_BIND_CB_FSR3UPSCALER) + layout (set = 0, binding = FSR3UPSCALER_BIND_CB_FSR3UPSCALER, std140) uniform cbFSR3UPSCALER_t + { + FfxInt32x2 iRenderSize; + FfxInt32x2 iPreviousFrameRenderSize; + + FfxInt32x2 iUpscaleSize; + FfxInt32x2 iPreviousFrameUpscaleSize; + + FfxInt32x2 iMaxRenderSize; + FfxInt32x2 iMaxUpscaleSize; + + FfxFloat32x4 fDeviceToViewDepth; + + FfxFloat32x2 fJitter; + FfxFloat32x2 fPreviousFrameJitter; + + FfxFloat32x2 fMotionVectorScale; + FfxFloat32x2 fDownscaleFactor; + + FfxFloat32x2 fMotionVectorJitterCancellation; + FfxFloat32 fTanHalfFOV; + FfxFloat32 fJitterSequenceLength; + + FfxFloat32 fDeltaTime; + FfxFloat32 fDeltaPreExposure; + FfxFloat32 fViewSpaceToMetersFactor; + FfxFloat32 fFrameIndex; + + FfxFloat32 fVelocityFactor; + FfxFloat32 fReactivenessScale; + FfxFloat32 fShadingChangeScale; + FfxFloat32 fAccumulationAddedPerFrame; + FfxFloat32 fMinDisocclusionAccumulation; + } cbFSR3Upscaler; + + +FfxInt32x2 RenderSize() +{ + return cbFSR3Upscaler.iRenderSize; +} + +FfxInt32x2 PreviousFrameRenderSize() +{ + return cbFSR3Upscaler.iPreviousFrameRenderSize; +} + +FfxInt32x2 MaxRenderSize() +{ + return cbFSR3Upscaler.iMaxRenderSize; +} + +FfxInt32x2 UpscaleSize() +{ + return cbFSR3Upscaler.iUpscaleSize; +} + +FfxInt32x2 PreviousFrameUpscaleSize() +{ + return cbFSR3Upscaler.iPreviousFrameUpscaleSize; +} + +FfxInt32x2 MaxUpscaleSize() +{ + return cbFSR3Upscaler.iMaxUpscaleSize; +} + +FfxFloat32x2 Jitter() +{ + return cbFSR3Upscaler.fJitter; +} + +FfxFloat32x2 PreviousFrameJitter() +{ + return cbFSR3Upscaler.fPreviousFrameJitter; +} + +FfxFloat32x4 DeviceToViewSpaceTransformFactors() +{ + return cbFSR3Upscaler.fDeviceToViewDepth; +} + +FfxFloat32x2 MotionVectorScale() +{ + return cbFSR3Upscaler.fMotionVectorScale; +} + +FfxFloat32x2 DownscaleFactor() +{ + return cbFSR3Upscaler.fDownscaleFactor; +} + +FfxFloat32x2 MotionVectorJitterCancellation() +{ + return cbFSR3Upscaler.fMotionVectorJitterCancellation; +} + +FfxFloat32 TanHalfFoV() +{ + return cbFSR3Upscaler.fTanHalfFOV; +} + +FfxFloat32 JitterSequenceLength() +{ + return cbFSR3Upscaler.fJitterSequenceLength; +} + +FfxFloat32 DeltaTime() +{ + return cbFSR3Upscaler.fDeltaTime; +} + +FfxFloat32 DeltaPreExposure() +{ + return cbFSR3Upscaler.fDeltaPreExposure; +} + +FfxFloat32 ViewSpaceToMetersFactor() +{ + return cbFSR3Upscaler.fViewSpaceToMetersFactor; +} + +FfxFloat32 FrameIndex() +{ + return cbFSR3Upscaler.fFrameIndex; +} + +FfxFloat32 VelocityFactor() +{ + return cbFSR3Upscaler.fVelocityFactor; +} + +FfxFloat32 AccumulationAddedPerFrame() +{ + return cbFSR3Upscaler.fAccumulationAddedPerFrame; +} + +FfxFloat32 MinDisocclusionAccumulation() +{ + return cbFSR3Upscaler.fMinDisocclusionAccumulation; +} + +#endif // #if defined(FSR3UPSCALER_BIND_CB_FSR3UPSCALER) + + +#if defined(FSR3UPSCALER_BIND_CB_AUTOREACTIVE) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_AUTOREACTIVE, std140) uniform cbGenerateReactive_t +{ + FfxFloat32 fTcThreshold; // 0.1 is a good starting value, lower will result in more TC pixels + FfxFloat32 fTcScale; + FfxFloat32 fReactiveScale; + FfxFloat32 fReactiveMax; +} cbGenerateReactive; + +FfxFloat32 TcThreshold() +{ + return cbGenerateReactive.fTcThreshold; +} + +FfxFloat32 TcScale() +{ + return cbGenerateReactive.fTcScale; +} + +FfxFloat32 ReactiveScale() +{ + return cbGenerateReactive.fReactiveScale; +} + +FfxFloat32 ReactiveMax() +{ + return cbGenerateReactive.fReactiveMax; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_AUTOREACTIVE) + +#if defined(FSR3UPSCALER_BIND_CB_RCAS) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_RCAS, std140) uniform cbRCAS_t +{ + FfxUInt32x4 rcasConfig; +} cbRCAS; + +FfxUInt32x4 RCASConfig() +{ + return cbRCAS.rcasConfig; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_RCAS) + + +#if defined(FSR3UPSCALER_BIND_CB_REACTIVE) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_REACTIVE, std140) uniform cbGenerateReactive_t +{ + FfxFloat32 gen_reactive_scale; + FfxFloat32 gen_reactive_threshold; + FfxFloat32 gen_reactive_binaryValue; + FfxUInt32 gen_reactive_flags; +} cbGenerateReactive; + +FfxFloat32 GenReactiveScale() +{ + return cbGenerateReactive.gen_reactive_scale; +} + +FfxFloat32 GenReactiveThreshold() +{ + return cbGenerateReactive.gen_reactive_threshold; +} + +FfxFloat32 GenReactiveBinaryValue() +{ + return cbGenerateReactive.gen_reactive_binaryValue; +} + +FfxUInt32 GenReactiveFlags() +{ + return cbGenerateReactive.gen_reactive_flags; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_REACTIVE) + + +#if defined(FSR3UPSCALER_BIND_CB_SPD) +layout(set = 0, binding = FSR3UPSCALER_BIND_CB_SPD, std140) uniform cbSPD_t +{ + FfxUInt32 mips; + FfxUInt32 numWorkGroups; + FfxUInt32x2 workGroupOffset; + FfxUInt32x2 renderSize; +} cbSPD; + +FfxUInt32 MipCount() +{ + return cbSPD.mips; +} + +FfxUInt32 NumWorkGroups() +{ + return cbSPD.numWorkGroups; +} + +FfxUInt32x2 WorkGroupOffset() +{ + return cbSPD.workGroupOffset; +} + +FfxUInt32x2 SPD_RenderSize() +{ + return cbSPD.renderSize; +} +#endif // #if defined(FSR3UPSCALER_BIND_CB_SPD) + +layout (set = 0, binding = 1000) uniform sampler s_PointClamp; +layout (set = 0, binding = 1001) uniform sampler s_LinearClamp; + +#if defined(FSR3UPSCALER_BIND_SRV_SPD_MIPS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_SPD_MIPS) uniform texture2D r_spd_mips; + +FfxInt32x2 GetSPDMipDimensions(FfxUInt32 uMipLevel) +{ + return textureSize(r_spd_mips, int(uMipLevel)).xy; +} + +FfxFloat32x2 SampleSPDMipLevel(FfxFloat32x2 fUV, FfxUInt32 mipLevel) +{ + return textureLod(sampler2D(r_spd_mips, s_LinearClamp), fUV, float(mipLevel)).rg; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_DEPTH) uniform texture2D r_input_depth; + +FfxFloat32 LoadInputDepth(FfxInt32x2 iPxPos) +{ + return texelFetch(r_input_depth, iPxPos, 0).r; +} + +FfxFloat32 SampleInputDepth(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_input_depth, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_REACTIVE_MASK) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_REACTIVE_MASK) uniform texture2D r_reactive_mask; + +FfxFloat32 LoadReactiveMask(FfxInt32x2 iPxPos) +{ + return texelFetch(r_reactive_mask, FfxInt32x2(iPxPos), 0).r * cbFSR3Upscaler.fReactivenessScale; +} + +FfxInt32x2 GetReactiveMaskResourceDimensions() +{ + return textureSize(r_reactive_mask, 0).xy; +} + +FfxFloat32 SampleReactiveMask(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_reactive_mask, s_LinearClamp), fUV, 0.0).x * cbFSR3Upscaler.fReactivenessScale; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_TRANSPARENCY_AND_COMPOSITION_MASK) uniform texture2D r_transparency_and_composition_mask; + +FfxFloat32 LoadTransparencyAndCompositionMask(FfxUInt32x2 iPxPos) +{ + return texelFetch(r_transparency_and_composition_mask, FfxInt32x2(iPxPos), 0).r; +} + +FfxInt32x2 GetTransparencyAndCompositionMaskResourceDimensions() +{ + return textureSize(r_transparency_and_composition_mask, 0).xy; +} + +FfxFloat32 SampleTransparencyAndCompositionMask(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_transparency_and_composition_mask, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_COLOR) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color_jittered; + +FfxFloat32x3 LoadInputColor(FfxInt32x2 iPxPos) +{ + return texelFetch(r_input_color_jittered, iPxPos, 0).rgb; +} + +FfxFloat32x3 SampleInputColor(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_input_color_jittered, s_LinearClamp), fUV, 0.0).rgb; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_MOTION_VECTORS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors; + +FfxFloat32x2 LoadInputMotionVector(FfxInt32x2 iPxDilatedMotionVectorPos) +{ + FfxFloat32x2 fSrcMotionVector = texelFetch(r_input_motion_vectors, iPxDilatedMotionVectorPos, 0).xy; + + FfxFloat32x2 fUvMotionVector = fSrcMotionVector * MotionVectorScale(); + +#if FFX_FSR3UPSCALER_OPTION_JITTERED_MOTION_VECTORS + fUvMotionVector -= MotionVectorJitterCancellation(); +#endif + + return fUvMotionVector; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INTERNAL_UPSCALED) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INTERNAL_UPSCALED) uniform texture2D r_internal_upscaled_color; + +FfxFloat32x4 LoadHistory(FfxInt32x2 iPxHistory) +{ + return texelFetch(r_internal_upscaled_color, iPxHistory, 0); +} + +FfxFloat32x4 SampleHistory(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_internal_upscaled_color, s_LinearClamp), fUV, 0.0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_LUMA_HISTORY) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_LUMA_HISTORY, rgba8) uniform image2D rw_luma_history; + +void StoreLumaHistory(FfxInt32x2 iPxPos, FfxFloat32x4 fLumaHistory) +{ + imageStore(rw_luma_history, iPxPos, fLumaHistory); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_LUMA_HISTORY) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_LUMA_HISTORY) uniform texture2D r_luma_history; + +FfxFloat32x4 LoadLumaHistory(FfxInt32x2 iPxPos) +{ + return texelFetch(r_luma_history, iPxPos, 0); +} + +FfxFloat32x4 SampleLumaHistory(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_luma_history, s_LinearClamp), fUV, 0.0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_RCAS_INPUT) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_RCAS_INPUT) uniform texture2D r_rcas_input; + +FfxFloat32x4 LoadRCAS_Input(FfxInt32x2 iPxPos) +{ + return texelFetch(r_rcas_input, iPxPos, 0); +} + +FfxFloat32x3 SampleRCAS_Input(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_rcas_input, s_LinearClamp), fUV, 0.0).rgb; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_INTERNAL_UPSCALED) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_INTERNAL_UPSCALED, rgba16f) writeonly uniform image2D rw_internal_upscaled_color; + +void StoreReprojectedHistory(FfxInt32x2 iPxHistory, FfxFloat32x4 fHistory) +{ + imageStore(rw_internal_upscaled_color, iPxHistory, fHistory); +} + +void StoreInternalColorAndWeight(FfxInt32x2 iPxPos, FfxFloat32x4 fColorAndWeight) +{ + imageStore(rw_internal_upscaled_color, iPxPos, fColorAndWeight); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_UPSCALED_OUTPUT /* app controlled format */) writeonly uniform image2D rw_upscaled_output; + +void StoreUpscaledOutput(FfxInt32x2 iPxPos, FfxFloat32x3 fColor) +{ + imageStore(rw_upscaled_output, iPxPos, FfxFloat32x4(fColor, 1.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_ACCUMULATION) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_ACCUMULATION) uniform texture2D r_accumulation; + +FfxFloat32 SampleAccumulation(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_accumulation, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_ACCUMULATION) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_ACCUMULATION, r8) uniform image2D rw_accumulation; + +void StoreAccumulation(FfxInt32x2 iPxPos, FfxFloat32 fAccumulation) +{ + imageStore(rw_accumulation, iPxPos, vec4(fAccumulation, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_SHADING_CHANGE) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_SHADING_CHANGE) uniform texture2D r_shading_change; + +FfxFloat32 LoadShadingChange(FfxInt32x2 iPxPos) +{ + return texelFetch(r_shading_change, iPxPos, 0).x * cbFSR3Upscaler.fShadingChangeScale; +} + +FfxFloat32 SampleShadingChange(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_shading_change, s_LinearClamp), fUV, 0.0).x * cbFSR3Upscaler.fShadingChangeScale; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_SHADING_CHANGE) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SHADING_CHANGE, r8) uniform image2D rw_shading_change; + +void StoreShadingChange(FfxInt32x2 iPxPos, FfxFloat32 fShadingChange) +{ + imageStore(rw_shading_change, iPxPos, vec4(fShadingChange, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH) uniform texture2D r_farthest_depth; + +FfxInt32x2 GetFarthestDepthResourceDimensions() +{ + return textureSize(r_farthest_depth, 0).xy; +} + +FfxFloat32 LoadFarthestDepth(FfxInt32x2 iPxPos) +{ + return texelFetch(r_farthest_depth, iPxPos, 0).x; +} + +FfxFloat32 SampleFarthestDepth(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_farthest_depth, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH, r16f) uniform image2D rw_farthest_depth; + +void StoreFarthestDepth(FfxInt32x2 iPxPos, FfxFloat32 fDepth) +{ + imageStore(rw_farthest_depth, iPxPos, vec4(fDepth, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH_MIP1) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_FARTHEST_DEPTH_MIP1) uniform texture2D r_farthest_depth_mip1; + +FfxInt32x2 GetFarthestDepthMip1ResourceDimensions() +{ + return textureSize(r_farthest_depth_mip1, 0).xy; +} + +FfxFloat32 LoadFarthestDepthMip1(FfxInt32x2 iPxPos) +{ + return texelFetch(r_farthest_depth_mip1, iPxPos, 0).x; +} + +FfxFloat32 SampleFarthestDepthMip1(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_farthest_depth_mip1, s_LinearClamp), fUV, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH_MIP1) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_FARTHEST_DEPTH_MIP1, r16f) uniform image2D rw_farthest_depth_mip1; + +void StoreFarthestDepthMip1(FfxInt32x2 iPxPos, FfxFloat32 fDepth) +{ + imageStore(rw_farthest_depth_mip1, iPxPos, vec4(fDepth, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_CURRENT_LUMA) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_CURRENT_LUMA) uniform texture2D r_current_luma; + +FfxFloat32 LoadCurrentLuma(FfxInt32x2 iPxPos) +{ + return texelFetch(r_current_luma, iPxPos, 0).r; +} + +FfxFloat32 SampleCurrentLuma(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(r_current_luma, s_LinearClamp), uv, 0.0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_CURRENT_LUMA) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_CURRENT_LUMA, r16f) uniform image2D rw_current_luma; + +void StoreCurrentLuma(FfxInt32x2 iPxPos, FfxFloat32 fLuma) +{ + imageStore(rw_current_luma, iPxPos, vec4(fLuma, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_LUMA_INSTABILITY) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_LUMA_INSTABILITY) uniform texture2D r_luma_instability; + +FfxFloat32 SampleLumaInstability(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(r_luma_instability, s_LinearClamp), uv, 0.0).x; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_LUMA_INSTABILITY) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_LUMA_INSTABILITY, r16f) uniform image2D rw_luma_instability; + +void StoreLumaInstability(FfxInt32x2 iPxPos, FfxFloat32 fLumaInstability) +{ + imageStore(rw_luma_instability, iPxPos, vec4(fLumaInstability, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_PREVIOUS_LUMA) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_PREVIOUS_LUMA) uniform texture2D r_previous_luma; + +FfxFloat32 LoadPreviousLuma(FfxInt32x2 iPxPos) +{ + return texelFetch(r_previous_luma, iPxPos, 0).r; +} + +FfxFloat32 SamplePreviousLuma(FfxFloat32x2 uv) +{ + return textureLod(sampler2D(r_previous_luma, s_LinearClamp), uv, 0.0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_NEW_LOCKS) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_NEW_LOCKS) uniform texture2D r_new_locks; + +FfxFloat32 LoadNewLocks(FfxInt32x2 iPxPos) +{ + return texelFetch(r_new_locks, iPxPos, 0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_NEW_LOCKS) +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_NEW_LOCKS, r8) uniform image2D rw_new_locks; + +FfxFloat32 LoadRwNewLocks(FfxInt32x2 iPxPos) +{ + return imageLoad(rw_new_locks, iPxPos).r; +} + +void StoreNewLocks(FfxInt32x2 iPxPos, FfxFloat32 newLock) +{ + imageStore(rw_new_locks, iPxPos, vec4(newLock, 0, 0, 0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_RECONSTRUCTED_PREV_NEAREST_DEPTH) uniform utexture2D r_reconstructed_previous_nearest_depth; + +FfxFloat32 LoadReconstructedPrevDepth(FfxInt32x2 iPxPos) +{ + return uintBitsToFloat(texelFetch(r_reconstructed_previous_nearest_depth, iPxPos, 0).r); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_RECONSTRUCTED_PREV_NEAREST_DEPTH, r32ui) uniform uimage2D rw_reconstructed_previous_nearest_depth; + +void StoreReconstructedDepth(FfxInt32x2 iPxSample, FfxFloat32 fDepth) +{ + FfxUInt32 uDepth = floatBitsToUint(fDepth); + + #if FFX_FSR3UPSCALER_OPTION_INVERTED_DEPTH + imageAtomicMax(rw_reconstructed_previous_nearest_depth, iPxSample, uDepth); + #else + imageAtomicMin(rw_reconstructed_previous_nearest_depth, iPxSample, uDepth); // min for standard, max for inverted depth + #endif +} + +void SetReconstructedDepth(FfxInt32x2 iPxSample, FfxUInt32 uValue) +{ + imageStore(rw_reconstructed_previous_nearest_depth, iPxSample, uvec4(uValue, 0, 0, 0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_DILATED_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_DILATED_DEPTH, r32f) writeonly uniform image2D rw_dilated_depth; + +void StoreDilatedDepth(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32 fDepth) +{ + imageStore(rw_dilated_depth, iPxPos, vec4(fDepth, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_DILATED_MOTION_VECTORS) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_DILATED_MOTION_VECTORS, rg16f) writeonly uniform image2D rw_dilated_motion_vectors; + +void StoreDilatedMotionVector(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 fMotionVector) +{ + imageStore(rw_dilated_motion_vectors, iPxPos, vec4(fMotionVector, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_DILATED_MOTION_VECTORS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_DILATED_MOTION_VECTORS) uniform texture2D r_dilated_motion_vectors; + +FfxFloat32x2 LoadDilatedMotionVector(FfxInt32x2 iPxInput) +{ + return texelFetch(r_dilated_motion_vectors, iPxInput, 0).xy; +} + +FfxFloat32x2 SampleDilatedMotionVector(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_motion_vectors, s_LinearClamp), fUV, 0.0).xy; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_DILATED_DEPTH) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_DILATED_DEPTH) uniform texture2D r_dilated_depth; + +FfxFloat32 LoadDilatedDepth(FfxInt32x2 iPxInput) +{ + return texelFetch(r_dilated_depth, iPxInput, 0).r; +} + +FfxFloat32 SampleDilatedDepth(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_depth, s_LinearClamp), fUV, 0.0).r; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_EXPOSURE) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_EXPOSURE) uniform texture2D r_input_exposure; + +FfxFloat32 Exposure() +{ + FfxFloat32 exposure = texelFetch(r_input_exposure, FfxInt32x2(0, 0), 0).x; + + if (exposure == 0.0) { + exposure = 1.0; + } + + return exposure; +} +#endif + +// BEGIN: FSR3UPSCALER_BIND_SRV_LANCZOS_LUT +#if defined(FSR3UPSCALER_BIND_SRV_LANCZOS_LUT) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_LANCZOS_LUT) uniform texture2D r_lanczos_lut; +#endif + +FfxFloat32 SampleLanczos2Weight(FfxFloat32 x) +{ +#if defined(FSR3UPSCALER_BIND_SRV_LANCZOS_LUT) + return textureLod(sampler2D(r_lanczos_lut, s_LinearClamp), FfxFloat32x2(x / 2.0, 0.5), 0.0).x; +#else + return 0.f; +#endif +} +// END: FSR3UPSCALER_BIND_SRV_LANCZOS_LUT + +#if defined(FSR3UPSCALER_BIND_SRV_DILATED_REACTIVE_MASKS) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_DILATED_REACTIVE_MASKS) uniform texture2D r_dilated_reactive_masks; + +FfxFloat32x4 SampleDilatedReactiveMasks(FfxFloat32x2 fUV) +{ + return textureLod(sampler2D(r_dilated_reactive_masks, s_LinearClamp), fUV, 0.0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_DILATED_REACTIVE_MASKS) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_DILATED_REACTIVE_MASKS, rgba8) writeonly uniform image2D rw_dilated_reactive_masks; + +void StoreDilatedReactiveMasks(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x4 fDilatedReactiveMasks) +{ + imageStore(rw_dilated_reactive_masks, iPxPos, fDilatedReactiveMasks); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_INPUT_OPAQUE_ONLY) +layout (set = 0, binding = FSR3UPSCALER_BIND_SRV_INPUT_OPAQUE_ONLY) uniform texture2D r_input_opaque_only; + +FfxFloat32x3 LoadOpaqueOnly(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_opaque_only, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_PREV_PRE_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_PREV_PRE_ALPHA_COLOR) uniform texture2D r_input_prev_color_pre_alpha; + +FfxFloat32x3 LoadPrevPreAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_prev_color_pre_alpha, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_PREV_POST_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_PREV_POST_ALPHA_COLOR) uniform texture2D r_input_prev_color_post_alpha; + +FfxFloat32x3 LoadPrevPostAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos) +{ + return texelFetch(r_input_prev_color_post_alpha, iPxPos, 0).xyz; +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_AUTOREACTIVE) && \ + defined(FSR3UPSCALER_BIND_UAV_AUTOCOMPOSITION) + +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_AUTOREACTIVE, r32f) uniform image2D rw_output_autoreactive; +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_AUTOCOMPOSITION, r32f) uniform image2D rw_output_autocomposition; + +void StoreAutoReactive(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F2 fReactive) +{ + imageStore(rw_output_autoreactive, iPxPos, FfxFloat32x4(FfxFloat32(fReactive.x), 0.0, 0.0, 0.0)); + + imageStore(rw_output_autocomposition, iPxPos, FfxFloat32x4(FfxFloat32(fReactive.y), 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_PREV_PRE_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_PREV_PRE_ALPHA_COLOR, r11f_g11f_b10f) uniform image2D rw_output_prev_color_pre_alpha; + +void StorePrevPreAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F3 color) +{ + imageStore(rw_output_prev_color_pre_alpha, iPxPos, FfxFloat32x4(color, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_PREV_POST_ALPHA_COLOR) +layout(set = 0, binding = FSR3UPSCALER_BIND_UAV_PREV_POST_ALPHA_COLOR, r11f_g11f_b10f) uniform image2D rw_output_prev_color_post_alpha; + +void StorePrevPostAlpha(FFX_PARAMETER_IN FFX_MIN16_I2 iPxPos, FFX_PARAMETER_IN FFX_MIN16_F3 color) +{ + imageStore(rw_output_prev_color_post_alpha, iPxPos, FfxFloat32x4(color, 0.0)); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_FRAME_INFO) +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_FRAME_INFO, rgba32f) uniform image2D rw_frame_info; + +FfxFloat32x4 LoadFrameInfo() +{ + return imageLoad(rw_frame_info, ivec2(0, 0)); +} + +void StoreFrameInfo(FfxFloat32x4 fInfo) +{ + imageStore(rw_frame_info, ivec2(0, 0), fInfo); +} +#endif + +#if defined(FSR3UPSCALER_BIND_SRV_FRAME_INFO) +layout(set = 0, binding = FSR3UPSCALER_BIND_SRV_FRAME_INFO) uniform texture2D r_frame_info; + +FfxFloat32x4 FrameInfo() +{ + return texelFetch(r_frame_info, ivec2(0, 0), 0); +} +#endif + +#if defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_0) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_1) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4) && \ + defined(FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5) + +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_0, rg16f) uniform image2D rw_spd_mip0; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_1, rg16f) uniform image2D rw_spd_mip1; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_2, rg16f) uniform image2D rw_spd_mip2; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_3, rg16f) uniform image2D rw_spd_mip3; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_4, rg16f) uniform image2D rw_spd_mip4; +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_MIPS_LEVEL_5, rg16f) coherent uniform image2D rw_spd_mip5; + +FfxFloat32x2 RWLoadPyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxUInt32 index) +{ +#define LOAD(idx) \ + if (index == idx) \ + { \ + return imageLoad(rw_spd_mip##idx, iPxPos).xy; \ + } + LOAD(0); + LOAD(1); + LOAD(2); + LOAD(3); + LOAD(4); + LOAD(5); + + return FfxFloat32x2(0.0, 0.0); + +#undef LOAD +} + +void StorePyramid(FFX_PARAMETER_IN FfxInt32x2 iPxPos, FFX_PARAMETER_IN FfxFloat32x2 outValue, FFX_PARAMETER_IN FfxUInt32 index) +{ +#define STORE(idx) \ + if (index == idx) \ + { \ + imageStore(rw_spd_mip##idx, iPxPos, vec4(outValue, 0.0, 0.0)); \ + } + + STORE(0); + STORE(1); + STORE(2); + STORE(3); + STORE(4); + STORE(5); + +#undef STORE +} +#endif + +#if defined FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC +layout (set = 0, binding = FSR3UPSCALER_BIND_UAV_SPD_GLOBAL_ATOMIC, r32ui) coherent uniform uimage2D rw_spd_global_atomic; + +void SPD_IncreaseAtomicCounter(inout FfxUInt32 spdCounter) +{ + spdCounter = imageAtomicAdd(rw_spd_global_atomic, ivec2(0, 0), 1); +} + +void SPD_ResetAtomicCounter() +{ + imageStore(rw_spd_global_atomic, ivec2(0, 0), uvec4(0)); +} +#endif + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/CMakeCompileLENSShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/CMakeCompileLENSShaders.txt new file mode 100644 index 00000000..fc710d04 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/CMakeCompileLENSShaders.txt @@ -0,0 +1,46 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(LENS_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(LENS_PERMUTATION_ARGS + -DFFX_LENS_OPTION_LINEAR_SAMPLE={0,1} + -DFFX_LENS_OPTION_WAVE_INTEROP_LDS={0,1}) + +set(LENS_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/lens") + +if (NOT LENS_SHADER_EXT) + set(LENS_SHADER_EXT *) +endif() + +file(GLOB LENS_SHADERS + "shaders/lens/ffx_lens_pass.${LENS_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${LENS_BASE_ARGS}" "${LENS_API_BASE_ARGS}" "${LENS_PERMUTATION_ARGS}" "${LENS_INCLUDE_ARGS}" + "${LENS_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" LENS_PERMUTATION_OUTPUTS) + +add_shader_output("${LENS_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens.h new file mode 100644 index 00000000..6302d64f --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens.h @@ -0,0 +1,284 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup FfxGPULens FidelityFX Lens +/// FidelityFX Lens GPU documentation +/// +/// @ingroup FfxGPUEffects + +// Noise function used as basis for film grain effect +FfxUInt32x3 pcg3d16(FfxUInt32x3 v) +{ + v = v * 12829u + 47989u; + v.x += v.y * v.z; + v.y += v.z * v.x; + v.z += v.x * v.y; + v.x += v.y * v.z; + v.y += v.z * v.x; + v.z += v.x * v.y; + v >>= 16u; + return v; +} + +// Simplex noise, transforms given position onto triangle grid +// This logic should be kept at 32-bit floating point precision. 16 bits causes artifacting. +FfxFloat32x2 simplex(const in FfxFloat32x2 P) +{ + // Skew and unskew factors are a bit hairy for 2D, so define them as constants + const FfxFloat32 F2 = (sqrt(3.0) - 1.0) / 2.0; // 0.36602540378 + const FfxFloat32 G2 = (3.0 - sqrt(3.0)) / 6.0; // 0.2113248654 + + // Skew the (x,y) space to determine which cell of 2 simplices we're in + FfxFloat32 u = (P.x + P.y) * F2; + FfxFloat32x2 Pi = round(P + u); + FfxFloat32 v = (Pi.x + Pi.y) * G2; + FfxFloat32x2 P0 = Pi - v; // Unskew the cell origin back to (x,y) space + FfxFloat32x2 Pf0 = P - P0; // The x,y distances from the cell origin + + return FfxFloat32x2(Pf0); +} + +#if FFX_HALF + +FfxFloat16x2 toFloat16(FfxUInt32x2 inputVal) +{ + return FfxFloat16x2(inputVal * (1.0 / 65536.0) - 0.5); +} + +FfxFloat16x3 toFloat16(FfxUInt32x3 inputVal) +{ + return FfxFloat16x3(inputVal * (1.0 / 65536.0) - 0.5); +} + +/// Function call to calculate the red and green wavelength/channel sample offset values. +/// +/// @param chromAbIntensity Intensity constant value for the chromatic aberration effect. +/// @return FfxFloat32x2 containing the red and green wavelength/channel magnitude values +/// @ingroup FfxGPULens +FfxFloat16x2 FfxLensGetRGMag(FfxFloat16 chromAbIntensity) +{ + const FfxFloat16 A = FfxFloat16(1.5220); + const FfxFloat16 B = FfxFloat16(0.00459) * chromAbIntensity; // um^2 + + const FfxFloat16 redWaveLengthUM = FfxFloat16(0.612 * 0.612); + const FfxFloat16 greenWaveLengthUM = FfxFloat16(0.549 * 0.549); + const FfxFloat16 blueWaveLengthUM = FfxFloat16(0.464 * 0.464); + + const FfxFloat16 redIdxRefraction = A + B / (redWaveLengthUM); + const FfxFloat16 greenIdxRefraction = A + B / (greenWaveLengthUM); + const FfxFloat16 blueIdxRefraction = A + B / (blueWaveLengthUM); + + const FfxFloat16 redMag = (redIdxRefraction - FfxFloat16(1.0)) / (blueIdxRefraction - FfxFloat16(1.0)); + const FfxFloat16 greenMag = (greenIdxRefraction - FfxFloat16(1.0)) / (blueIdxRefraction - FfxFloat16(1.0)); + + return FfxFloat16x2(redMag, greenMag); +} + +/// Function call to apply chromatic aberration effect when sampling the color input texture. +/// +/// @param coord The input window coordinate [0, widthPixels), [0, heightPixels). +/// @param centerCoord The center window coordinate of the screen. +/// @param redMag Magnitude value for the offset calculation of the red wavelength (texture channel). +/// @param greenMag Magnitude value for the offset calculation of the green wavelength (texture channel). +/// @return The final sampled RGB color. +/// @ingroup FfxGPULens +FfxFloat16x3 FfxLensSampleWithChromaticAberration(FfxInt32x2 coord, FfxInt32x2 centerCoord, FfxFloat16 redMag, FfxFloat16 greenMag) +{ + FfxFloat16x2 coordfp16 = FfxFloat16x2(coord); + FfxFloat16x2 centerCoordfp16 = FfxFloat16x2(centerCoord); + FfxFloat16x2 redShift = (coordfp16 - centerCoordfp16) * redMag + centerCoordfp16 + FfxFloat16x2(0.5, 0.5); + redShift *= FfxFloat16x2(ffxReciprocal(FfxFloat16(2.0) * centerCoordfp16)); + FfxFloat16x2 greenShift = (coordfp16 - centerCoordfp16) * greenMag + centerCoordfp16 + FfxFloat16x2(0.5, 0.5); + greenShift *= FfxFloat16x2(ffxReciprocal(FfxFloat16(2.0) * centerCoordfp16)); + + FfxFloat16 red = FfxLensSampleR(redShift); + FfxFloat16 green = FfxLensSampleG(greenShift); + FfxFloat16 blue = FfxLensSampleB(coordfp16 * ffxReciprocal(FfxFloat16(2.0) * centerCoordfp16)); + + return FfxFloat16x3(red, green, blue); +} + +/// Function call to apply film grain effect to inout color. This call could be skipped entirely as the choice to use the film grain is optional. +/// +/// @param coord The input window coordinate [0, widthPixels), [0, heightPixels). +/// @param color The current running color, or more clearly, the sampled input color texture color after being modified by chromatic aberration function. +/// @param grainScaleVal Scaling constant value for the grain's noise frequency. +/// @param grainAmountVal Intensity constant value of the grain effect. +/// @param grainSeedVal Seed value for the grain noise, for example, to change how the noise functions effect the grain frame to frame. +/// @ingroup FfxGPULens +void FfxLensApplyFilmGrain(FfxInt32x2 coord, inout FfxFloat16x3 color, FfxFloat16 grainScaleVal, FfxFloat16 grainAmountVal, uint grainSeedVal) +{ + FfxFloat32x2 randomNumberFine = toFloat16(pcg3d16(FfxUInt32x3(FfxFloat32x2(coord) / (FfxFloat32(grainScaleVal / 8.0)), grainSeedVal)).xy).xy; + FfxFloat16x2 simplexP = FfxFloat16x2(simplex(FfxFloat32x2(coord) / FfxFloat32(grainScaleVal) + randomNumberFine)); + const FfxFloat16 grainShape = FfxFloat16(3.0); + + FfxFloat16 grain = FfxFloat16(1.0) - FfxFloat16(2.0) * exp2(-length(simplexP) * grainShape); + + color += grain * min(color, FfxFloat16x3(1.0, 1.0, 1.0) - color) * grainAmountVal; +} + +/// Function call to apply vignette effect to inout color. This call could be skipped entirely as the choice to use the vignette is optional. +/// +/// @param coord The input window coordinate [0, widthPixels), [0, heightPixels). +/// @param centerCoord The center window coordinate of the screen. +/// @param color The current running color, or more clearly, the sampled input color texture color after being modified by chromatic aberration and film grain functions. +/// @param vignetteAmount Intensity constant value of the vignette effect. +/// @ingroup FfxGPULens +void FfxLensApplyVignette(FfxInt32x2 coord, FfxInt32x2 centerCoord, inout FfxFloat16x3 color, FfxFloat16 vignetteAmount) +{ + FfxFloat16x2 vignetteMask = FfxFloat16x2(0.0, 0.0); + FfxFloat16x2 coordFromCenter = FfxFloat16x2(abs(coord - centerCoord)) / FfxFloat16x2(centerCoord); + + const FfxFloat16 piOver4 = FfxFloat16(FFX_PI * 0.25); + vignetteMask = FfxFloat16x2(cos(coordFromCenter * vignetteAmount * piOver4)); + vignetteMask = vignetteMask * vignetteMask; + vignetteMask = vignetteMask * vignetteMask; + + FfxFloat16 vignetteMaskClamped = FfxFloat16(clamp(vignetteMask.x * vignetteMask.y, 0, 1)); + color *= FfxFloat16x3(vignetteMaskClamped, vignetteMaskClamped, vignetteMaskClamped); +} + +#else // FFX_HALF + +FfxFloat32x2 toFloat16(FfxUInt32x2 inputVal) +{ + return FfxFloat32x2(inputVal * (1.0 / 65536.0) - 0.5); +} + +FfxFloat32x3 toFloat16(FfxUInt32x3 inputVal) +{ + return FfxFloat32x3(inputVal * (1.0 / 65536.0) - 0.5); +} + +/// Function call to calculate the red and green wavelength/channel sample offset values. +/// +/// @param chromAbIntensity Intensity constant value for the chromatic aberration effect. +/// @return FfxFloat32x2 containing the red and green wavelength/channel magnitude values +/// @ingroup FfxGPULens +FfxFloat32x2 FfxLensGetRGMag(FfxFloat32 chromAbIntensity) +{ + const FfxFloat32 A = 1.5220; + const FfxFloat32 B = 0.00459 * chromAbIntensity; // um^2 + + const FfxFloat32 redWaveLengthUM = 0.612; + const FfxFloat32 greenWaveLengthUM = 0.549; + const FfxFloat32 blueWaveLengthUM = 0.464; + + const FfxFloat32 redIdxRefraction = A + B / (redWaveLengthUM * redWaveLengthUM); + const FfxFloat32 greenIdxRefraction = A + B / (greenWaveLengthUM * greenWaveLengthUM); + const FfxFloat32 blueIdxRefraction = A + B / (blueWaveLengthUM * blueWaveLengthUM); + + const FfxFloat32 redMag = (redIdxRefraction - 1) / (blueIdxRefraction - 1); + const FfxFloat32 greenMag = (greenIdxRefraction - 1) / (blueIdxRefraction - 1); + + return FfxFloat32x2(redMag, greenMag); +} + +/// Function call to apply chromatic aberration effect when sampling the color input texture. +/// +/// @param coord The input window coordinate [0, widthPixels), [0, heightPixels). +/// @param centerCoord The center window coordinate of the screen. +/// @param redMag Magnitude value for the offset calculation of the red wavelength (texture channel). +/// @param greenMag Magnitude value for the offset calculation of the green wavelength (texture channel). +/// @return The final sampled RGB color. +/// @ingroup FfxGPULens +FfxFloat32x3 FfxLensSampleWithChromaticAberration(FfxInt32x2 coord, FfxInt32x2 centerCoord, FfxFloat32 redMag, FfxFloat32 greenMag) +{ + FfxFloat32x2 redShift = (coord - centerCoord) * redMag + centerCoord + 0.5; + redShift *= ffxReciprocal(2 * centerCoord); + FfxFloat32x2 greenShift = (coord - centerCoord) * greenMag + centerCoord + 0.5; + greenShift *= ffxReciprocal(2 * centerCoord); + + FfxFloat32 red = FfxLensSampleR(redShift); + FfxFloat32 green = FfxLensSampleG(greenShift); + FfxFloat32 blue = FfxLensSampleB(coord * ffxReciprocal(2 * centerCoord)); + + return FfxFloat32x3(red, green, blue); +} + +/// Function call to apply film grain effect to inout color. This call could be skipped entirely as the choice to use the film grain is optional. +/// +/// @param coord The input window coordinate [0, widthPixels), [0, heightPixels). +/// @param color The current running color, or more clearly, the sampled input color texture color after being modified by chromatic aberration function. +/// @param grainScaleVal Scaling constant value for the grain's noise frequency. +/// @param grainAmountVal Intensity constant value of the grain effect. +/// @param grainSeedVal Seed value for the grain noise, for example, to change how the noise functions effect the grain frame to frame. +/// @ingroup FfxGPULens +void FfxLensApplyFilmGrain(FfxInt32x2 coord, inout FfxFloat32x3 color, FfxFloat32 grainScaleVal, FfxFloat32 grainAmountVal, uint grainSeedVal) +{ + FfxFloat32x2 randomNumberFine = toFloat16(pcg3d16(FfxUInt32x3(coord / (grainScaleVal / 8), grainSeedVal)).xy).xy; + FfxFloat32x2 simplexP = simplex(coord / grainScaleVal + randomNumberFine); + const FfxFloat32 grainShape = 3; + + FfxFloat32 grain = 1 - 2 * exp2(-length(simplexP) * grainShape); + + color += grain * min(color, 1 - color) * grainAmountVal; +} + +/// Function call to apply vignette effect to inout color. This call could be skipped entirely as the choice to use the vignette is optional. +/// +/// @param coord The input window coordinate [0, widthPixels), [0, heightPixels). +/// @param centerCoord The center window coordinate of the screen. +/// @param color The current running color, or more clearly, the sampled input color texture color after being modified by chromatic aberration and film grain functions. +/// @param vignetteAmount Intensity constant value of the vignette effect. +/// @ingroup FfxGPULens +void FfxLensApplyVignette(FfxInt32x2 coord, FfxInt32x2 centerCoord, inout FfxFloat32x3 color, FfxFloat32 vignetteAmount) +{ + FfxFloat32x2 vignetteMask = FfxFloat32x2(0.0, 0.0); + FfxFloat32x2 coordFromCenter = abs(coord - centerCoord) / FfxFloat32x2(centerCoord); + + const FfxFloat32 piOver4 = FFX_PI * 0.25; + vignetteMask = cos(coordFromCenter * vignetteAmount * piOver4); + vignetteMask = vignetteMask * vignetteMask; + vignetteMask = vignetteMask * vignetteMask; + + color *= clamp(vignetteMask.x * vignetteMask.y, 0, 1); +} + +#endif + +/// Lens pass entry point. +/// +/// @param Gtid Thread index within thread group (SV_GroupThreadID). +/// @param Gidx Group index of thread (SV_GroupID). +/// @ingroup FfxGPULens +void FfxLens(FfxUInt32 Gtid, FfxUInt32x2 Gidx) +{ + // Do remapping of local xy in workgroup for a more PS-like swizzle pattern. + // Assumes 64,1,1 threadgroup size and an 8x8 api dispatch + FfxInt32x2 Coord = FfxInt32x2(ffxRemapForWaveReduction(Gtid) + FfxUInt32x2(Gidx.x << 3u, Gidx.y << 3u)); + + // Run Lens +#if FFX_HALF + FfxFloat16x2 RGMag = FfxLensGetRGMag(FfxFloat16(ChromAb())); + FfxFloat16x3 Color = FfxLensSampleWithChromaticAberration(Coord, FfxInt32x2(Center()), RGMag.r, RGMag.g); + FfxLensApplyVignette(Coord, FfxInt32x2(Center()), Color, FfxFloat16(Vignette())); + FfxLensApplyFilmGrain(Coord, Color, FfxFloat16(GrainScale()), FfxFloat16(GrainAmount()), GrainSeed()); +#else // FFX_HALF + FfxFloat32x2 RGMag = FfxLensGetRGMag(ChromAb()); + FfxFloat32x3 Color = FfxLensSampleWithChromaticAberration(Coord, FfxInt32x2(Center()), RGMag.r, RGMag.g); + FfxLensApplyVignette(Coord, FfxInt32x2(Center()), Color, Vignette()); + FfxLensApplyFilmGrain(Coord, Color, GrainScale(), GrainAmount(), GrainSeed()); +#endif + + StoreLensOutput(Coord, Color); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_callbacks_glsl.h new file mode 100644 index 00000000..38b303e3 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_callbacks_glsl.h @@ -0,0 +1,178 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_lens_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#if defined(LENS_BIND_CB_LENS) + layout(set = 0, binding = LENS_BIND_CB_LENS, std140) uniform cbLens_t + { + FfxFloat32 grainScale; + FfxFloat32 grainAmount; + FfxUInt32 grainSeed; + FfxUInt32 pad; + + FfxUInt32x2 center; + FfxFloat32 chromAb; + FfxFloat32 vignette; + #define FFX_LENS_CONSTANT_BUFFER_1_SIZE 8 // Number of 32-bit values. This must be kept in sync with the cbLens size. + } cbLens; +#endif + +FfxFloat32 GrainScale() +{ +#ifdef LENS_BIND_CB_LENS + return cbLens.grainScale; +#else + return 0; +#endif +} + +FfxFloat32 GrainAmount() +{ +#ifdef LENS_BIND_CB_LENS + return cbLens.grainAmount; +#else + return 0.0; +#endif +} + +FfxUInt32 GrainSeed() +{ +#ifdef LENS_BIND_CB_LENS + return cbLens.grainSeed; +#else + return 0; +#endif +} + +FfxUInt32x2 Center() +{ +#ifdef LENS_BIND_CB_LENS + return cbLens.center; +#else + return FfxUInt32x2(0, 0); +#endif + +} + +FfxFloat32 Vignette() +{ +#ifdef LENS_BIND_CB_LENS + return cbLens.vignette; +#else + return 0.0; +#endif +} + +FfxFloat32 ChromAb() +{ +#ifdef LENS_BIND_CB_LENS + return cbLens.chromAb; +#else + return 0.0; +#endif +} + +layout(set = 0, binding = 1000) uniform sampler s_LinearClamp; + +// SRVs +#if defined LENS_BIND_SRV_INPUT_TEXTURE +layout(set = 0, binding = LENS_BIND_SRV_INPUT_TEXTURE) uniform texture2D r_input_texture; +#endif + +// UAVs +#if defined LENS_BIND_UAV_OUTPUT_TEXTURE +layout(set = 0, binding = LENS_BIND_UAV_OUTPUT_TEXTURE, rgba32f) uniform image2D rw_output_texture; +#endif + +#if FFX_HALF + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat16 FfxLensSampleR(FfxFloat32x2 fPxPos) +{ + return FfxFloat16(texture(sampler2D(r_input_texture, s_LinearClamp), fPxPos).r); +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat16 FfxLensSampleG(FfxFloat32x2 fPxPos) +{ + return FfxFloat16(texture(sampler2D(r_input_texture, s_LinearClamp), fPxPos).g); +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat16 FfxLensSampleB(FfxFloat32x2 fPxPos) +{ + return FfxFloat16(texture(sampler2D(r_input_texture, s_LinearClamp), fPxPos).b); +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_UAV_OUTPUT_TEXTURE) +void StoreLensOutput(FfxInt32x2 iPxPos, FfxFloat16x3 fColor) +{ + imageStore(rw_output_texture, iPxPos, FfxFloat32x4(fColor, 1.0)); +} +#endif // defined(LENS_BIND_UAV_OUTPUT_TEXTURE) + +#else // FFX_HALF + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat32 FfxLensSampleR(FfxFloat32x2 fPxPos) +{ + return texture(sampler2D(r_input_texture, s_LinearClamp), fPxPos).r; +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat32 FfxLensSampleG(FfxFloat32x2 fPxPos) +{ + return texture(sampler2D(r_input_texture, s_LinearClamp), fPxPos).g; +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat32 FfxLensSampleB(FfxFloat32x2 fPxPos) +{ + return texture(sampler2D(r_input_texture, s_LinearClamp), fPxPos).b; +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_UAV_OUTPUT_TEXTURE) +void StoreLensOutput(FfxInt32x2 iPxPos, FfxFloat32x3 fColor) +{ + imageStore(rw_output_texture, iPxPos, FfxFloat32x4(fColor, 1.0)); +} +#endif // defined(LENS_BIND_UAV_OUTPUT_TEXTURE) + +#endif // FFX_HALF + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_callbacks_hlsl.h new file mode 100644 index 00000000..52b96b7d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_callbacks_hlsl.h @@ -0,0 +1,196 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_lens_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_LENS_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_LENS_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_LENS_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(LENS_BIND_CB_LENS) + cbuffer cbLens : FFX_LENS_DECLARE_CB(LENS_BIND_CB_LENS) + { + FfxFloat32 grainScale; + FfxFloat32 grainAmount; + FfxUInt32 grainSeed; + FfxUInt32 pad; + + FfxUInt32x2 center; + FfxFloat32 chromAb; + FfxFloat32 vignette; + #define FFX_LENS_CONSTANT_BUFFER_1_SIZE 8 // Number of 32-bit values. This must be kept in sync with the cbLens size. + }; +#else + #define grainScale 0 + #define grainAmount 0 + #define grainSeed 0 + #define pad 0 + #define center uint2(0,0) + #define vignette 0.0 + #define chromAb 0.0 +#endif + +#if defined(FFX_GPU) +#define FFX_LENS_ROOTSIG_STRINGIFY(p) FFX_LENS_ROOTSIG_STR(p) +#define FFX_LENS_ROOTSIG_STR(p) #p +#define FFX_LENS_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_LENS_ROOTSIG_STRINGIFY(FFX_LENS_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_LENS_ROOTSIG_STRINGIFY(FFX_LENS_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_NEVER, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK)" )] + +#if defined(FFX_LENS_EMBED_ROOTSIG) +#define FFX_LENS_EMBED_ROOTSIG_CONTENT FFX_LENS_ROOTSIG +#else +#define FFX_LENS_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_LENS_EMBED_ROOTSIG +#endif // #if defined(FFX_GPU) + + +FfxFloat32 GrainScale() +{ + return grainScale; +} + +FfxFloat32 GrainAmount() +{ + return grainAmount; +} + +FfxUInt32 GrainSeed() +{ + return grainSeed; +} + +FfxUInt32x2 Center() +{ + return center; +} + +FfxFloat32 Vignette() +{ + return vignette; +} + +FfxFloat32 ChromAb() +{ + return chromAb; +} + +SamplerState s_LinearClamp : register(s0); + +// SRVs +#if defined LENS_BIND_SRV_INPUT_TEXTURE + Texture2D r_input_texture : FFX_LENS_DECLARE_SRV(LENS_BIND_SRV_INPUT_TEXTURE); +#endif + +// UAVs +#if defined LENS_BIND_UAV_OUTPUT_TEXTURE + RWTexture2D rw_output_texture : FFX_LENS_DECLARE_UAV(LENS_BIND_UAV_OUTPUT_TEXTURE); +#endif + +#if FFX_HALF + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat16 FfxLensSampleR(FfxFloat32x2 fPxPos) +{ + return FfxFloat16(r_input_texture.SampleLevel(s_LinearClamp, fPxPos, 0).r); +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat16 FfxLensSampleG(FfxFloat32x2 fPxPos) +{ + return FfxFloat16(r_input_texture.SampleLevel(s_LinearClamp, fPxPos, 0).g); +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat16 FfxLensSampleB(FfxFloat32x2 fPxPos) +{ + return FfxFloat16(r_input_texture.SampleLevel(s_LinearClamp, fPxPos, 0).b); +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_UAV_OUTPUT_TEXTURE) +void StoreLensOutput(FfxInt32x2 iPxPos, FfxFloat16x3 fColor) +{ + rw_output_texture[iPxPos] = FfxFloat32x4(fColor, 1.0); +} +#endif // defined(LENS_BIND_UAV_OUTPUT_TEXTURE) + +#else // FFX_HALF + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat32 FfxLensSampleR(FfxFloat32x2 fPxPos) +{ + return r_input_texture.SampleLevel(s_LinearClamp, fPxPos, 0).r; +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat32 FfxLensSampleG(FfxFloat32x2 fPxPos) +{ + return r_input_texture.SampleLevel(s_LinearClamp, fPxPos, 0).g; +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_SRV_INPUT_TEXTURE) +FfxFloat32 FfxLensSampleB(FfxFloat32x2 fPxPos) +{ + return r_input_texture.SampleLevel(s_LinearClamp, fPxPos, 0).b; +} +#endif // defined(LENS_BIND_SRV_INPUT_TEXTURE) + +#if defined(LENS_BIND_UAV_OUTPUT_TEXTURE) +void StoreLensOutput(FfxInt32x2 iPxPos, FfxFloat32x3 fColor) +{ + rw_output_texture[iPxPos] = FfxFloat32x4(fColor, 1.0); +} +#endif // defined(LENS_BIND_UAV_OUTPUT_TEXTURE) + +#endif // FFX_HALF + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_resources.h new file mode 100644 index 00000000..6487d327 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lens/ffx_lens_resources.h @@ -0,0 +1,38 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_LENS_RESOURCES_H +#define FFX_LENS_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) + +#define FFX_LENS_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_LENS_RESOURCE_IDENTIFIER_INPUT_TEXTURE 1 +#define FFX_LENS_RESOURCE_IDENTIFIER_OUTPUT_TEXTURE 2 +#define FFX_LENS_RESOURCE_IDENTIFIER_COUNT 3 + +// CBV resource definitions +#define FFX_LENS_CONSTANTBUFFER_IDENTIFIER_LENS 0 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif // FFX_LENS_RESOURCES_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/CMakeCompileLPMShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/CMakeCompileLPMShaders.txt new file mode 100644 index 00000000..af647087 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/CMakeCompileLPMShaders.txt @@ -0,0 +1,42 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(LPM_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(LPM_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/lpm") + +if (NOT LPM_SHADER_EXT) + set(LPM_SHADER_EXT *) +endif() + +file(GLOB LPM_SHADERS + "shaders/lpm/ffx_lpm_filter_pass.${LPM_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${LPM_BASE_ARGS}" "${LPM_API_BASE_ARGS}" "${LPM_PERMUTATION_ARGS}" "${LPM_INCLUDE_ARGS}" + "${LPM_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" LPM_PERMUTATION_OUTPUTS) + +add_shader_output("${LPM_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm.h new file mode 100644 index 00000000..4f446bda --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm.h @@ -0,0 +1,1147 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup FfxGPULpm FidelityFX LPM +/// FidelityFX Luma Preserving Mapper GPU documentation +/// +/// @ingroup FfxGPUEffects + +FFX_STATIC void LpmMatInv3x3(FFX_PARAMETER_OUT FfxFloat32x3 ox, FFX_PARAMETER_OUT FfxFloat32x3 oy, FFX_PARAMETER_OUT FfxFloat32x3 oz, + FfxFloat32x3 ix, FfxFloat32x3 iy, FfxFloat32x3 iz) +{ + FfxFloat32 i = ffxReciprocal(ix[0] * (iy[1] * iz[2] - iz[1] * iy[2]) - ix[1] * (iy[0] * iz[2] - iy[2] * iz[0]) + ix[2] * (iy[0] * iz[1] - iy[1] * iz[0])); + ox[0] = (iy[1] * iz[2] - iz[1] * iy[2]) * i; + ox[1] = (ix[2] * iz[1] - ix[1] * iz[2]) * i; + ox[2] = (ix[1] * iy[2] - ix[2] * iy[1]) * i; + oy[0] = (iy[2] * iz[0] - iy[0] * iz[2]) * i; + oy[1] = (ix[0] * iz[2] - ix[2] * iz[0]) * i; + oy[2] = (iy[0] * ix[2] - ix[0] * iy[2]) * i; + oz[0] = (iy[0] * iz[1] - iz[0] * iy[1]) * i; + oz[1] = (iz[0] * ix[1] - ix[0] * iz[1]) * i; + oz[2] = (ix[0] * iy[1] - iy[0] * ix[1]) * i; +} + +// Transpose. +FFX_STATIC void LpmMatTrn3x3(FFX_PARAMETER_OUT FfxFloat32x3 ox, FFX_PARAMETER_OUT FfxFloat32x3 oy, FFX_PARAMETER_OUT FfxFloat32x3 oz, + FfxFloat32x3 ix, FfxFloat32x3 iy, FfxFloat32x3 iz) +{ + ox[0] = ix[0]; + ox[1] = iy[0]; + ox[2] = iz[0]; + oy[0] = ix[1]; + oy[1] = iy[1]; + oy[2] = iz[1]; + oz[0] = ix[2]; + oz[1] = iy[2]; + oz[2] = iz[2]; +} + +FFX_STATIC void LpmMatMul3x3( + FFX_PARAMETER_OUT FfxFloat32x3 ox, FFX_PARAMETER_OUT FfxFloat32x3 oy, FFX_PARAMETER_OUT FfxFloat32x3 oz, + FfxFloat32x3 ax, FfxFloat32x3 ay, FfxFloat32x3 az, FfxFloat32x3 bx, FfxFloat32x3 by, FfxFloat32x3 bz) +{ + FfxFloat32x3 bx2; + FfxFloat32x3 by2; + FfxFloat32x3 bz2; + + LpmMatTrn3x3(bx2, by2, bz2, bx, by, bz); + ox[0] = ffxDot3(ax, bx2); + ox[1] = ffxDot3(ax, by2); + ox[2] = ffxDot3(ax, bz2); + oy[0] = ffxDot3(ay, bx2); + oy[1] = ffxDot3(ay, by2); + oy[2] = ffxDot3(ay, bz2); + oz[0] = ffxDot3(az, bx2); + oz[1] = ffxDot3(az, by2); + oz[2] = ffxDot3(az, bz2); +} + +// D65 xy coordinates. +FFX_STATIC FfxFloat32x2 lpmColD65 = {FfxFloat32(0.3127), FfxFloat32(0.3290)}; + +// Rec709 xy coordinates, (D65 white point). +FFX_STATIC FfxFloat32x2 lpmCol709R = {FfxFloat32(0.64), FfxFloat32(0.33)}; +FFX_STATIC FfxFloat32x2 lpmCol709G = {FfxFloat32(0.30), FfxFloat32(0.60)}; +FFX_STATIC FfxFloat32x2 lpmCol709B = {FfxFloat32(0.15), FfxFloat32(0.06)}; + +// DCI-P3 xy coordinates, (D65 white point). +FFX_STATIC FfxFloat32x2 lpmColP3R = {FfxFloat32(0.680), FfxFloat32(0.320)}; +FFX_STATIC FfxFloat32x2 lpmColP3G = {FfxFloat32(0.265), FfxFloat32(0.690)}; +FFX_STATIC FfxFloat32x2 lpmColP3B = {FfxFloat32(0.150), FfxFloat32(0.060)}; + +// Rec2020 xy coordinates, (D65 white point). +FFX_STATIC FfxFloat32x2 lpmCol2020R = {FfxFloat32(0.708), FfxFloat32(0.292)}; +FFX_STATIC FfxFloat32x2 lpmCol2020G = {FfxFloat32(0.170), FfxFloat32(0.797)}; +FFX_STATIC FfxFloat32x2 lpmCol2020B = {FfxFloat32(0.131), FfxFloat32(0.046)}; + +// Computes z from xy, returns xyz. +FFX_STATIC void LpmColXyToZ(FFX_PARAMETER_OUT FfxFloat32x3 d, FfxFloat32x2 s) +{ + d[0] = s[0]; + d[1] = s[1]; + d[2] = FfxFloat32(1.0) - (s[0] + s[1]); +} + +// Returns conversion matrix, rgbw inputs are xy chroma coordinates. +FFX_STATIC void LpmColRgbToXyz(FFX_PARAMETER_OUT FfxFloat32x3 ox, FFX_PARAMETER_OUT FfxFloat32x3 oy, FFX_PARAMETER_OUT FfxFloat32x3 oz, + FfxFloat32x2 r, FfxFloat32x2 g, FfxFloat32x2 b, FfxFloat32x2 w) +{ + // Expand from xy to xyz. + FfxFloat32x3 rz; + FfxFloat32x3 gz; + FfxFloat32x3 bz; + LpmColXyToZ(rz, r); + LpmColXyToZ(gz, g); + LpmColXyToZ(bz, b); + + FfxFloat32x3 r3; + FfxFloat32x3 g3; + FfxFloat32x3 b3; + LpmMatTrn3x3(r3, g3, b3, rz, gz, bz); + + // Convert white xyz to XYZ. + FfxFloat32x3 w3; + LpmColXyToZ(w3, w); + ffxOpAMulOneF3(w3, w3, ffxReciprocal(w[1])); + + // Compute xyz to XYZ scalars for primaries. + FfxFloat32x3 rv; + FfxFloat32x3 gv; + FfxFloat32x3 bv; + LpmMatInv3x3(rv, gv, bv, r3, g3, b3); + + FfxFloat32x3 s; + s[0] = ffxDot3(rv, w3); + s[1] = ffxDot3(gv, w3); + s[2] = ffxDot3(bv, w3); + + // Scale. + ffxOpAMulF3(ox, r3, s); + ffxOpAMulF3(oy, g3, s); + ffxOpAMulF3(oz, b3, s); +} + +#if defined(LPM_NO_SETUP) +FFX_STATIC void LpmSetupOut(FfxUInt32 i, FfxUInt32x4 v) +{ +} +#endif // #if defined(LPM_NO_SETUP) + +/// Setup required constant values for LPM (works on CPU or GPU). +/// Output goes to the user-defined LpmSetupOut() function. +/// +/// @param [in] shoulder Use optional extra shoulderContrast tuning (set to false if shoulderContrast is 1.0). +/// @param [in] con Use first RGB conversion matrix, if 'soft' then 'con' must be true also. +/// @param [in] soft Use soft gamut mapping. +/// @param [in] con2 Use last RGB conversion matrix. +/// @param [in] clip Use clipping in last conversion matrix. +/// @param [in] scaleOnly Scale only for last conversion matrix (used for 709 HDR to scRGB). +/// @param [in] xyRedW Red Chroma coordinates for working color space. +/// @param [in] xyGreenW Green Chroma coordinates for working color space. +/// @param [in] xyBlueW Blue Chroma coordinates for working color space. +/// @param [in] xyWhiteW White Chroma coordinates for working color space. +/// @param [in] xyRedO Red Chroma coordinates for output color space. +/// @param [in] xyGreenO Green Chroma coordinates for output color space. +/// @param [in] xyBlueO Blue Chroma coordinates for output color space. +/// @param [in] xyWhiteO White Chroma coordinates for output color space. +/// @param [in] xyRedC Red Chroma coordinates for output container or display colour space. +/// @param [in] xyGreenC Green Chroma coordinates for output container or display color space. +/// @param [in] xyBlueC Blue Chroma coordinates for output container or display color space. +/// @param [in] xyWhiteC White Chroma coordinates for output container or display color space. +/// @param [in] scaleC scale factor for PQ or scRGB adjustment +/// @param [in] softGap Range of 0 to a little over zero, controls how much feather region in out-of-gamut mapping, 0=clip. +/// @param [in] hdrMax Maximum input value. +/// @param [in] exposure Number of stops between 'hdrMax' and 18% mid-level on input. +/// @param [in] contrast Input range {0.0 (no extra contrast) to 1.0 (maximum contrast)}. +/// @param [in] shoulderContrast Shoulder shaping, 1.0 = no change (fast path). +/// @param [in] saturation A per channel adjustment, use <0 decrease, 0=no change, >0 increase. +/// @param [in] crosstalk One channel must be 1.0, the rest can be <= 1.0 but not zero. Lenghtnes colours path to white by walking across gamut. Check documentation for usage +/// +/// @ingroup FfxGPULpm +FFX_STATIC void FfxCalculateLpmConsts( + // Path control. + FfxBoolean shoulder, // Use optional extra shoulderContrast tuning (set to false if shoulderContrast is 1.0). + + // Prefab start, "LPM_CONFIG_". + FfxBoolean con, // Use first RGB conversion matrix, if 'soft' then 'con' must be true also. + FfxBoolean soft, // Use soft gamut mapping. + FfxBoolean con2, // Use last RGB conversion matrix. + FfxBoolean clip, // Use clipping in last conversion matrix. + FfxBoolean scaleOnly, // Scale only for last conversion matrix (used for 709 HDR to scRGB). + + // Gamut control, "LPM_COLORS_". + FfxFloat32x2 xyRedW, + FfxFloat32x2 xyGreenW, + FfxFloat32x2 xyBlueW, + FfxFloat32x2 xyWhiteW, // Chroma coordinates for working color space. + FfxFloat32x2 xyRedO, + FfxFloat32x2 xyGreenO, + FfxFloat32x2 xyBlueO, + FfxFloat32x2 xyWhiteO, // For the output color space. + FfxFloat32x2 xyRedC, + FfxFloat32x2 xyGreenC, + FfxFloat32x2 xyBlueC, + FfxFloat32x2 xyWhiteC, + FfxFloat32 scaleC, // For the output container color space (if con2). + + // Prefab end. + FfxFloat32 softGap, // Range of 0 to a little over zero, controls how much feather region in out-of-gamut mapping, 0=clip. + + // Tonemapping control. + FfxFloat32 hdrMax, // Maximum input value. + FfxFloat32 exposure, // Number of stops between 'hdrMax' and 18% mid-level on input. + FfxFloat32 contrast, // Input range {0.0 (no extra contrast) to 1.0 (maximum contrast)}. + FfxFloat32 shoulderContrast, // Shoulder shaping, 1.0 = no change (fast path). + FfxFloat32x3 saturation, // A per channel adjustment, use <0 decrease, 0=no change, >0 increase. + FfxFloat32x3 crosstalk) // One channel must be 1.0, the rest can be <= 1.0 but not zero. +{ + // Contrast needs to be 1.0 based for no contrast. + contrast += FfxFloat32(1.0); + + // Saturation is based on contrast. + ffxOpAAddOneF3(saturation, saturation, contrast); + + // The 'softGap' must actually be above zero. + softGap = ffxMax(softGap, FfxFloat32(1.0 / 1024.0)); + + FfxFloat32 midIn = hdrMax * FfxFloat32(0.18) * exp2(-exposure); + FfxFloat32 midOut = FfxFloat32(0.18); + + FfxFloat32x2 toneScaleBias; + FfxFloat32 cs = contrast * shoulderContrast; + FfxFloat32 z0 = -pow(midIn, contrast); + FfxFloat32 z1 = pow(hdrMax, cs) * pow(midIn, contrast); + FfxFloat32 z2 = pow(hdrMax, contrast) * pow(midIn, cs) * midOut; + FfxFloat32 z3 = pow(hdrMax, cs) * midOut; + FfxFloat32 z4 = pow(midIn, cs) * midOut; + toneScaleBias[0] = -((z0 + (midOut * (z1 - z2)) * ffxReciprocal(z3 - z4)) * ffxReciprocal(z4)); + + FfxFloat32 w0 = pow(hdrMax, cs) * pow(midIn, contrast); + FfxFloat32 w1 = pow(hdrMax, contrast) * pow(midIn, cs) * midOut; + FfxFloat32 w2 = pow(hdrMax, cs) * midOut; + FfxFloat32 w3 = pow(midIn, cs) * midOut; + toneScaleBias[1] = (w0 - w1) * ffxReciprocal(w2 - w3); + + FfxFloat32x3 lumaW; + FfxFloat32x3 rgbToXyzXW; + FfxFloat32x3 rgbToXyzYW; + FfxFloat32x3 rgbToXyzZW; + LpmColRgbToXyz(rgbToXyzXW, rgbToXyzYW, rgbToXyzZW, xyRedW, xyGreenW, xyBlueW, xyWhiteW); + + // Use the Y vector of the matrix for the associated luma coef. + // For safety, make sure the vector sums to 1.0. + ffxOpAMulOneF3(lumaW, rgbToXyzYW, ffxReciprocal(rgbToXyzYW[0] + rgbToXyzYW[1] + rgbToXyzYW[2])); + + // The 'lumaT' for crosstalk mapping is always based on the output color space, unless soft conversion is not used. + FfxFloat32x3 lumaT; + FfxFloat32x3 rgbToXyzXO; + FfxFloat32x3 rgbToXyzYO; + FfxFloat32x3 rgbToXyzZO; + LpmColRgbToXyz(rgbToXyzXO, rgbToXyzYO, rgbToXyzZO, xyRedO, xyGreenO, xyBlueO, xyWhiteO); + + if (soft) + ffxOpACpyF3(lumaT, rgbToXyzYO); + else + ffxOpACpyF3(lumaT, rgbToXyzYW); + + ffxOpAMulOneF3(lumaT, lumaT, ffxReciprocal(lumaT[0] + lumaT[1] + lumaT[2])); + FfxFloat32x3 rcpLumaT; + ffxOpARcpF3(rcpLumaT, lumaT); + + FfxFloat32x2 softGap2 = {0.0, 0.0}; + if (soft) + { + softGap2[0] = softGap; + softGap2[1] = (FfxFloat32(1.0) - softGap) * ffxReciprocal(softGap * FfxFloat32(0.693147180559)); + } + + // First conversion is always working to output. + FfxFloat32x3 conR = {0.0, 0.0, 0.0}; + FfxFloat32x3 conG = {0.0, 0.0, 0.0}; + FfxFloat32x3 conB = {0.0, 0.0, 0.0}; + + if (con) + { + FfxFloat32x3 xyzToRgbRO; + FfxFloat32x3 xyzToRgbGO; + FfxFloat32x3 xyzToRgbBO; + LpmMatInv3x3(xyzToRgbRO, xyzToRgbGO, xyzToRgbBO, rgbToXyzXO, rgbToXyzYO, rgbToXyzZO); + LpmMatMul3x3(conR, conG, conB, xyzToRgbRO, xyzToRgbGO, xyzToRgbBO, rgbToXyzXW, rgbToXyzYW, rgbToXyzZW); + } + + // The last conversion is always output to container. + FfxFloat32x3 con2R = {0.0, 0.0, 0.0}; + FfxFloat32x3 con2G = {0.0, 0.0, 0.0}; + FfxFloat32x3 con2B = {0.0, 0.0, 0.0}; + + if (con2) + { + FfxFloat32x3 rgbToXyzXC; + FfxFloat32x3 rgbToXyzYC; + FfxFloat32x3 rgbToXyzZC; + LpmColRgbToXyz(rgbToXyzXC, rgbToXyzYC, rgbToXyzZC, xyRedC, xyGreenC, xyBlueC, xyWhiteC); + + FfxFloat32x3 xyzToRgbRC; + FfxFloat32x3 xyzToRgbGC; + FfxFloat32x3 xyzToRgbBC; + LpmMatInv3x3(xyzToRgbRC, xyzToRgbGC, xyzToRgbBC, rgbToXyzXC, rgbToXyzYC, rgbToXyzZC); + LpmMatMul3x3(con2R, con2G, con2B, xyzToRgbRC, xyzToRgbGC, xyzToRgbBC, rgbToXyzXO, rgbToXyzYO, rgbToXyzZO); + ffxOpAMulOneF3(con2R, con2R, scaleC); + ffxOpAMulOneF3(con2G, con2G, scaleC); + ffxOpAMulOneF3(con2B, con2B, scaleC); + } + + if (scaleOnly) + con2R[0] = scaleC; + +#if defined(FFX_GPU) +#if defined(LPM_DEBUG_FORCE_16BIT_PRECISION) + // Debug force 16-bit precision for the 32-bit inputs, only works on the GPU. + saturation = FfxFloat32x3(FfxFloat16x3(saturation)); + contrast = FfxFloat32(FfxFloat16(contrast)); + toneScaleBias = FfxFloat32x2(FfxFloat16x2(toneScaleBias)); + lumaT = FfxFloat32x3(FfxFloat16x3(lumaT)); + crosstalk = FfxFloat32x3(FfxFloat16x3(crosstalk)); + rcpLumaT = FfxFloat32x3(FfxFloat16x3(rcpLumaT)); + con2R = FfxFloat32x3(FfxFloat16x3(con2R)); + con2G = FfxFloat32x3(FfxFloat16x3(con2G)); + con2B = FfxFloat32x3(FfxFloat16x3(con2B)); + shoulderContrast = FfxFloat32(FfxFloat16(shoulderContrast)); + lumaW = FfxFloat32x3(FfxFloat16x3(lumaW)); + softGap2 = FfxFloat32x2(FfxFloat16x2(softGap2)); + conR = FfxFloat32x3(FfxFloat16x3(conR)); + conG = FfxFloat32x3(FfxFloat16x3(conG)); + conB = FfxFloat32x3(FfxFloat16x3(conB)); +#endif // #if defined(LPM_DEBUG_FORCE_16BIT_PRECISION) +#endif // #if defined(FFX_GPU) + + // Pack into control block. + FfxUInt32x4 map0; + map0[0] = ffxAsUInt32(saturation[0]); + map0[1] = ffxAsUInt32(saturation[1]); + map0[2] = ffxAsUInt32(saturation[2]); + map0[3] = ffxAsUInt32(contrast); + LpmSetupOut(0, map0); + + FfxUInt32x4 map1; + map1[0] = ffxAsUInt32(toneScaleBias[0]); + map1[1] = ffxAsUInt32(toneScaleBias[1]); + map1[2] = ffxAsUInt32(lumaT[0]); + map1[3] = ffxAsUInt32(lumaT[1]); + LpmSetupOut(1, map1); + + FfxUInt32x4 map2; + map2[0] = ffxAsUInt32(lumaT[2]); + map2[1] = ffxAsUInt32(crosstalk[0]); + map2[2] = ffxAsUInt32(crosstalk[1]); + map2[3] = ffxAsUInt32(crosstalk[2]); + LpmSetupOut(2, map2); + + FfxUInt32x4 map3; + map3[0] = ffxAsUInt32(rcpLumaT[0]); + map3[1] = ffxAsUInt32(rcpLumaT[1]); + map3[2] = ffxAsUInt32(rcpLumaT[2]); + map3[3] = ffxAsUInt32(con2R[0]); + LpmSetupOut(3, map3); + + FfxUInt32x4 map4; + map4[0] = ffxAsUInt32(con2R[1]); + map4[1] = ffxAsUInt32(con2R[2]); + map4[2] = ffxAsUInt32(con2G[0]); + map4[3] = ffxAsUInt32(con2G[1]); + LpmSetupOut(4, map4); + + FfxUInt32x4 map5; + map5[0] = ffxAsUInt32(con2G[2]); + map5[1] = ffxAsUInt32(con2B[0]); + map5[2] = ffxAsUInt32(con2B[1]); + map5[3] = ffxAsUInt32(con2B[2]); + LpmSetupOut(5, map5); + + FfxUInt32x4 map6; + map6[0] = ffxAsUInt32(shoulderContrast); + map6[1] = ffxAsUInt32(lumaW[0]); + map6[2] = ffxAsUInt32(lumaW[1]); + map6[3] = ffxAsUInt32(lumaW[2]); + LpmSetupOut(6, map6); + + FfxUInt32x4 map7; + map7[0] = ffxAsUInt32(softGap2[0]); + map7[1] = ffxAsUInt32(softGap2[1]); + map7[2] = ffxAsUInt32(conR[0]); + map7[3] = ffxAsUInt32(conR[1]); + LpmSetupOut(7, map7); + + FfxUInt32x4 map8; + map8[0] = ffxAsUInt32(conR[2]); + map8[1] = ffxAsUInt32(conG[0]); + map8[2] = ffxAsUInt32(conG[1]); + map8[3] = ffxAsUInt32(conG[2]); + LpmSetupOut(8, map8); + + FfxUInt32x4 map9; + map9[0] = ffxAsUInt32(conB[0]); + map9[1] = ffxAsUInt32(conB[1]); + map9[2] = ffxAsUInt32(conB[2]); + map9[3] = ffxAsUInt32(0); + LpmSetupOut(9, map9); + + // Packed 16-bit part of control block. + FfxUInt32x4 map16; + FfxFloat32x2 map16x; + FfxFloat32x2 map16y; + FfxFloat32x2 map16z; + FfxFloat32x2 map16w; + map16x[0] = saturation[0]; + map16x[1] = saturation[1]; + map16y[0] = saturation[2]; + map16y[1] = contrast; + map16z[0] = toneScaleBias[0]; + map16z[1] = toneScaleBias[1]; + map16w[0] = lumaT[0]; + map16w[1] = lumaT[1]; + map16[0] = ffxPackHalf2x16(map16x); + map16[1] = ffxPackHalf2x16(map16y); + map16[2] = ffxPackHalf2x16(map16z); + map16[3] = ffxPackHalf2x16(map16w); + LpmSetupOut(16, map16); + + FfxUInt32x4 map17; + FfxFloat32x2 map17x; + FfxFloat32x2 map17y; + FfxFloat32x2 map17z; + FfxFloat32x2 map17w; + map17x[0] = lumaT[2]; + map17x[1] = crosstalk[0]; + map17y[0] = crosstalk[1]; + map17y[1] = crosstalk[2]; + map17z[0] = rcpLumaT[0]; + map17z[1] = rcpLumaT[1]; + map17w[0] = rcpLumaT[2]; + map17w[1] = con2R[0]; + map17[0] = ffxPackHalf2x16(map17x); + map17[1] = ffxPackHalf2x16(map17y); + map17[2] = ffxPackHalf2x16(map17z); + map17[3] = ffxPackHalf2x16(map17w); + LpmSetupOut(17, map17); + + FfxUInt32x4 map18; + FfxFloat32x2 map18x; + FfxFloat32x2 map18y; + FfxFloat32x2 map18z; + FfxFloat32x2 map18w; + map18x[0] = con2R[1]; + map18x[1] = con2R[2]; + map18y[0] = con2G[0]; + map18y[1] = con2G[1]; + map18z[0] = con2G[2]; + map18z[1] = con2B[0]; + map18w[0] = con2B[1]; + map18w[1] = con2B[2]; + map18[0] = ffxPackHalf2x16(map18x); + map18[1] = ffxPackHalf2x16(map18y); + map18[2] = ffxPackHalf2x16(map18z); + map18[3] = ffxPackHalf2x16(map18w); + LpmSetupOut(18, map18); + + FfxUInt32x4 map19; + FfxFloat32x2 map19x; + FfxFloat32x2 map19y; + FfxFloat32x2 map19z; + FfxFloat32x2 map19w; + map19x[0] = shoulderContrast; + map19x[1] = lumaW[0]; + map19y[0] = lumaW[1]; + map19y[1] = lumaW[2]; + map19z[0] = softGap2[0]; + map19z[1] = softGap2[1]; + map19w[0] = conR[0]; + map19w[1] = conR[1]; + map19[0] = ffxPackHalf2x16(map19x); + map19[1] = ffxPackHalf2x16(map19y); + map19[2] = ffxPackHalf2x16(map19z); + map19[3] = ffxPackHalf2x16(map19w); + LpmSetupOut(19, map19); + + FfxUInt32x4 map20; + FfxFloat32x2 map20x; + FfxFloat32x2 map20y; + FfxFloat32x2 map20z; + FfxFloat32x2 map20w; + map20x[0] = conR[2]; + map20x[1] = conG[0]; + map20y[0] = conG[1]; + map20y[1] = conG[2]; + map20z[0] = conB[0]; + map20z[1] = conB[1]; + map20w[0] = conB[2]; + map20w[1] = 0.0; + map20[0] = ffxPackHalf2x16(map20x); + map20[1] = ffxPackHalf2x16(map20y); + map20[2] = ffxPackHalf2x16(map20z); + map20[3] = ffxPackHalf2x16(map20w); + LpmSetupOut(20, map20); +} + +//============================================================================================================================== +// HDR10 RANGE LIMITING SCALAR +//------------------------------------------------------------------------------------------------------------------------------ +// As of 2019, HDR10 supporting TVs typically have PQ tonal curves with near clipping long before getting to the peak 10K nits. +// Unfortunately this clipping point changes per TV (requires some amount of user calibration). +// Some examples, +// https://youtu.be/M7OsbpU4oCQ?t=875 +// https://youtu.be/8mlTElC2z2A?t=1159 +// https://youtu.be/B5V5hCVXBAI?t=975 +// For this reason it can be useful to manually limit peak HDR10 output to some point before the clipping point. +// The following functions are useful to compute the scaling factor 'hdr10S' to use with LpmSetup() to manually limit peak. +//============================================================================================================================== +// Compute 'hdr10S' for raw HDR10 output, pass in peak nits (typically somewhere around 1000.0 to 2000.0). +FFX_STATIC FfxFloat32 LpmHdr10RawScalar(FfxFloat32 peakNits) +{ + return peakNits * (FfxFloat32(1.0) / FfxFloat32(10000.0)); +} + +// Compute 'hdr10S' for scRGB based HDR10 output, pass in peak nits (typically somewhere around 1000.0 to 2000.0). +FFX_STATIC FfxFloat32 LpmHdr10ScrgbScalar(FfxFloat32 peakNits) +{ + return peakNits * (FfxFloat32(1.0) / FfxFloat32(10000.0)) * (FfxFloat32(10000.0) / FfxFloat32(80.0)); +} + +//============================================================================================================================== +// FREESYNC2 SCRGB SCALAR +//------------------------------------------------------------------------------------------------------------------------------ +// The more expensive scRGB mode for FreeSync2 requires a complex scale factor based on display properties. +//============================================================================================================================== +// This computes the 'fs2S' factor used in LpmSetup(). +// TODO: Is this correct???????????????????????????????????????????????????????????????????????????????????????????????????????? +FFX_STATIC FfxFloat32 LpmFs2ScrgbScalar(FfxFloat32 minLuma, FfxFloat32 maxLuma) +{ + // Queried display properties. + return ((maxLuma - minLuma) + minLuma) * (FfxFloat32(1.0) / FfxFloat32(80.0)); +} + +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//_____________________________________________________________/\_______________________________________________________________ +//============================================================================================================================== +// CONFIGURATION PREFABS +//------------------------------------------------------------------------------------------------------------------------------ +// Use these to simplify some of the input(s) to the LpmSetup() and LpmFilter() functions. +// The 'LPM_CONFIG__' defines are used for the path control. +// The 'LPM_COLORS__' defines are used for the gamut control. +// This contains expected common configurations, anything else will need to be made by the user. +//------------------------------------------------------------------------------------------------------------------------------ +// WORKING COLOR SPACE +// =================== +// 2020 ......... Rec.2020 +// 709 .......... Rec.709 +// P3 ........... DCI-P3 with D65 white-point +// -------------- +// OUTPUT COLOR SPACE +// ================== +// FS2RAW ....... Faster 32-bit/pixel FreeSync2 raw gamma 2.2 output (native display primaries) +// FS2RAWPQ ..... Faster 32-bit/pixel FreeSync2 raw PQ output (native display primaries for gamut which are then converted to Rec.2020 primaries for transport) +// FS2SCRGB ..... Slower 64-bit/pixel FreeSync2 via the scRGB option (Rec.709 primaries with possible negative color) +// HDR10RAW ..... Faster 32-bit/pixel HDR10 raw (10:10:10:2 PQ output with Rec.2020 primaries) +// HDR10SCRGB ... Slower 64-bit/pixel scRGB (linear FP16, Rec.709 primaries with possible negative color) +// 709 .......... Rec.709, sRGB, Gamma 2.2, or traditional displays with Rec.709-like primaries +//------------------------------------------------------------------------------------------------------------------------------ +// FREESYNC2 VARIABLES +// =================== +// fs2R ..... Queried xy coordinates for display red +// fs2G ..... Queried xy coordinates for display green +// fs2B ..... Queried xy coordinates for display blue +// fs2W ..... Queried xy coordinates for display white point +// fs2S ..... Computed by LpmFs2ScrgbScalar() +//------------------------------------------------------------------------------------------------------------------------------ +// HDR10 VARIABLES +// =============== +// hdr10S ... Use LpmHdr10Scalar() to compute this value +//============================================================================================================================== +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2RAW_709 FFX_FALSE, FFX_FALSE, FFX_TRUE, FFX_TRUE, FFX_FALSE +#define LPM_COLORS_FS2RAW_709 \ + lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, fs2R, fs2G, fs2B, fs2W, FfxFloat32(1.0) +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2RAWPQ_709 FFX_FALSE, FFX_FALSE, FFX_TRUE, FFX_TRUE, FFX_FALSE +#define LPM_COLORS_FS2RAWPQ_709 \ + lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// FreeSync2 min-spec is larger than sRGB, so using 709 primaries all the way through as an optimization. +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2SCRGB_709 FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_TRUE +#define LPM_COLORS_FS2SCRGB_709 \ + lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, fs2S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_HDR10RAW_709 FFX_FALSE, FFX_FALSE, FFX_TRUE, FFX_TRUE, FFX_FALSE +#define LPM_COLORS_HDR10RAW_709 \ + lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_HDR10SCRGB_709 FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_TRUE +#define LPM_COLORS_HDR10SCRGB_709 \ + lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_709_709 FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_709_709 \ + lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, FfxFloat32(1.0) +//============================================================================================================================== +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2RAW_P3 FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_FS2RAW_P3 lpmColP3R, lpmColP3G, lpmColP3B, lpmColD65, fs2R, fs2G, fs2B, fs2W, fs2R, fs2G, fs2B, fs2W, FfxFloat32(1.0) +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2RAWPQ_P3 FFX_TRUE, FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_FS2RAWPQ_P3 lpmColP3R, lpmColP3G, lpmColP3B, lpmColD65, fs2R, fs2G, fs2B, fs2W, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// FreeSync2 gamut can be smaller than P3. +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2SCRGB_P3 FFX_TRUE, FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_FS2SCRGB_P3 lpmColP3R, lpmColP3G, lpmColP3B, lpmColD65, fs2R, fs2G, fs2B, fs2W, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, fs2S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_HDR10RAW_P3 FFX_FALSE, FFX_FALSE, FFX_TRUE, FFX_TRUE, FFX_FALSE +#define LPM_COLORS_HDR10RAW_P3 \ + lpmColP3R, lpmColP3G, lpmColP3B, lpmColD65, lpmColP3R, lpmColP3G, lpmColP3B, lpmColD65, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_HDR10SCRGB_P3 FFX_FALSE, FFX_FALSE, FFX_TRUE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_HDR10SCRGB_P3 \ + lpmColP3R, lpmColP3G, lpmColP3B, lpmColD65, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_709_P3 FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_709_P3 \ + lpmColP3R, lpmColP3G, lpmColP3B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, FfxFloat32(1.0) +//============================================================================================================================== +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2RAW_2020 FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_FS2RAW_2020 lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, fs2R, fs2G, fs2B, fs2W, fs2R, fs2G, fs2B, fs2W, FfxFloat32(1.0) +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2RAWPQ_2020 FFX_TRUE, FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_FS2RAWPQ_2020 lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, fs2R, fs2G, fs2B, fs2W, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_FS2SCRGB_2020 FFX_TRUE, FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_FS2SCRGB_2020 lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, fs2R, fs2G, fs2B, fs2W, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, fs2S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_HDR10RAW_2020 FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_FALSE, FFX_TRUE +#define LPM_COLORS_HDR10RAW_2020 \ + lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_HDR10SCRGB_2020 FFX_FALSE, FFX_FALSE, FFX_TRUE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_HDR10SCRGB_2020 \ + lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, hdr10S +//------------------------------------------------------------------------------------------------------------------------------ +// CON SOFT CON2 CLIP SCALEONLY +#define LPM_CONFIG_709_2020 FFX_TRUE, FFX_TRUE, FFX_FALSE, FFX_FALSE, FFX_FALSE +#define LPM_COLORS_709_2020 \ + lpmCol2020R, lpmCol2020G, lpmCol2020B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, lpmCol709R, lpmCol709G, lpmCol709B, lpmColD65, \ + FfxFloat32(1.0) + +#if defined(FFX_GPU) +// Visualize difference between two values, by bits of precision. +// This is useful when doing approximation to reference comparisons. +FfxBoolean LpmD(FfxFloat32 a, FfxFloat32 b) +{ + return abs(a - b) < 1.0; +} + +FfxFloat32 LpmC(FfxFloat32 a, FfxFloat32 b) +{ + FfxFloat32 c = 1.0; // 6-bits or less (the color) + if (LpmD(a * 127.0, b * 127.0)) + c = 0.875; // 7-bits + if (LpmD(a * 255.0, b * 255.0)) + c = 0.5; // 8-bits + if (LpmD(a * 512.0, b * 512.0)) + c = 0.125; // 9-bits + if (LpmD(a * 1024.0, b * 1024.0)) + c = 0.0; // 10-bits or better (black) + return c; +} + +FfxFloat32x3 LpmViewDiff(FfxFloat32x3 a, FfxFloat32x3 b) +{ + return FfxFloat32x3(LpmC(a.r, b.r), LpmC(a.g, b.g), LpmC(a.b, b.b)); +} + +//============================================================================================================================== +// MAPPER +//------------------------------------------------------------------------------------------------------------------------------ +// Do not call this directly, instead call the LpmFilter*() functions. +// This gets reconfigured based on inputs for all the various usage cases. +// Some of this has been explicitly ordered to increase precision. +//------------------------------------------------------------------------------------------------------------------------------ +// IDEAS +// ===== +// - Use ffxMed3() for soft falloff and for [A] color conversions. +// - Retry FP16 PQ conversion with different input range. +// - Possibly skip some work if entire wave is in gamut. +//============================================================================================================================== +// Use LpmFilter() instead of this. +void LpmMap(inout FfxFloat32 colorR, + inout FfxFloat32 colorG, + inout FfxFloat32 colorB, // Input and output color. + FfxFloat32x3 lumaW, // Luma coef for RGB working space. + FfxFloat32x3 lumaT, // Luma coef for crosstalk mapping (can be working or output color-space depending on usage case). + FfxFloat32x3 rcpLumaT, // 1/lumaT. + FfxFloat32x3 saturation, // Saturation powers. + FfxFloat32 contrast, // Contrast power. + FfxBoolean shoulder, // Using shoulder tuning (should be a compile-time immediate). + FfxFloat32 shoulderContrast, // Shoulder power. + FfxFloat32x2 toneScaleBias, // Other tonemapping parameters. + FfxFloat32x3 crosstalk, // Crosstalk scaling for over-exposure color shaping. + FfxBoolean con, // Use first RGB conversion matrix (should be a compile-time immediate), if 'soft' then 'con' must be true also. + FfxFloat32x3 conR, + FfxFloat32x3 conG, + FfxFloat32x3 conB, // RGB conversion matrix (working to output space conversion). + FfxBoolean soft, // Use soft gamut mapping (should be a compile-time immediate). + FfxFloat32x2 softGap, // {x,(1-x)/(x*0.693147180559)}, where 'x' is gamut mapping soft fall-off amount. + FfxBoolean con2, // Use last RGB conversion matrix (should be a compile-time immediate). + FfxBoolean clip, // Use clipping on last conversion matrix. + FfxBoolean scaleOnly, // Do scaling only (special case for 709 HDR to scRGB). + FfxFloat32x3 con2R, + FfxFloat32x3 con2G, + FfxFloat32x3 con2B) +{ + // Secondary RGB conversion matrix. + // Grab original RGB ratio (RCP, 3x MUL, MAX3). + FfxFloat32 rcpMax = ffxReciprocal(ffxMax3(colorR, colorG, colorB)); + FfxFloat32 ratioR = colorR * rcpMax; + FfxFloat32 ratioG = colorG * rcpMax; + FfxFloat32 ratioB = colorB * rcpMax; + + // Apply saturation, ratio must be max 1.0 for this to work right (3x EXP2, 3x LOG2, 3x MUL). + ratioR = pow(ratioR, FfxFloat32(saturation.r)); + ratioG = pow(ratioG, FfxFloat32(saturation.g)); + ratioB = pow(ratioB, FfxFloat32(saturation.b)); + + // Tonemap luma, note this uses the original color, so saturation is luma preserving. + // If not using 'con' this uses the output space luma directly to avoid needing extra constants. + // Note 'soft' should be a compile-time immediate (so no branch) (3x MAD). + FfxFloat32 luma; + if (soft) + luma = colorG * FfxFloat32(lumaW.g) + (colorR * FfxFloat32(lumaW.r) + (colorB * FfxFloat32(lumaW.b))); + else + luma = colorG * FfxFloat32(lumaT.g) + (colorR * FfxFloat32(lumaT.r) + (colorB * FfxFloat32(lumaT.b))); + luma = pow(luma, FfxFloat32(contrast)); // (EXP2, LOG2, MUL). + FfxFloat32 lumaShoulder = shoulder ? pow(luma, FfxFloat32(shoulderContrast)) : luma; // Optional (EXP2, LOG2, MUL). + luma = luma * ffxReciprocal(lumaShoulder * FfxFloat32(toneScaleBias.x) + FfxFloat32(toneScaleBias.y)); // (MAD, MUL, RCP). + + // If running soft clipping (this should be a compile-time immediate so branch will not exist). + if (soft) + { + // The 'con' should be a compile-time immediate so branch will not exist. + // Use of 'con' is implied if soft-falloff is enabled, but using the check here to make finding bugs easy. + if (con) + { + // Converting ratio instead of color. Change of primaries (9x MAD). + colorR = ratioR; + colorG = ratioG; + colorB = ratioB; + ratioR = colorR * FfxFloat32(conR.r) + (colorG * FfxFloat32(conR.g) + (colorB * FfxFloat32(conR.b))); + ratioG = colorG * FfxFloat32(conG.g) + (colorR * FfxFloat32(conG.r) + (colorB * FfxFloat32(conG.b))); + ratioB = colorB * FfxFloat32(conB.b) + (colorG * FfxFloat32(conB.g) + (colorR * FfxFloat32(conB.r))); + + // Convert ratio to max 1 again (RCP, 3x MUL, MAX3). + rcpMax = ffxReciprocal(ffxMax3(ratioR, ratioG, ratioB)); + ratioR *= rcpMax; + ratioG *= rcpMax; + ratioB *= rcpMax; + } + + // Absolute gamut mapping converted to soft falloff (maintains max 1 property). + // g = gap {0 to g} used for {-inf to 0} input range + // {g to 1} used for {0 to 1} input range + // x >= 0 := y = x * (1-g) + g + // x < 0 := g * 2^(x*h) + // Where h=(1-g)/(g*log(2)) --- where log() is the natural log + // The {g,h} above is passed in as softGap. + // Soft falloff (3x MIN, 3x MAX, 9x MAD, 3x EXP2). + ratioR = ffxMin(max(FfxFloat32(softGap.x), ffxSaturate(ratioR * FfxFloat32(-softGap.x) + ratioR)), + ffxSaturate(FfxFloat32(softGap.x) * exp2(ratioR * FfxFloat32(softGap.y)))); + ratioG = ffxMin(max(FfxFloat32(softGap.x), ffxSaturate(ratioG * FfxFloat32(-softGap.x) + ratioG)), + ffxSaturate(FfxFloat32(softGap.x) * exp2(ratioG * FfxFloat32(softGap.y)))); + ratioB = ffxMin(max(FfxFloat32(softGap.x), ffxSaturate(ratioB * FfxFloat32(-softGap.x) + ratioB)), + ffxSaturate(FfxFloat32(softGap.x) * exp2(ratioB * FfxFloat32(softGap.y)))); + } + + // Compute ratio scaler required to hit target luma (4x MAD, 1 RCP). + FfxFloat32 lumaRatio = ratioR * FfxFloat32(lumaT.r) + ratioG * FfxFloat32(lumaT.g) + ratioB * FfxFloat32(lumaT.b); + + // This is limited to not clip. + FfxFloat32 ratioScale = ffxSaturate(luma * ffxReciprocal(lumaRatio)); + + // Assume in gamut, compute output color (3x MAD). + colorR = ffxSaturate(ratioR * ratioScale); + colorG = ffxSaturate(ratioG * ratioScale); + colorB = ffxSaturate(ratioB * ratioScale); + + // Capability per channel to increase value (3x MAD). + // This factors in crosstalk factor to avoid multiplies later. + // '(1.0-ratio)*crosstalk' optimized to '-crosstalk*ratio+crosstalk' + FfxFloat32 capR = FfxFloat32(-crosstalk.r) * colorR + FfxFloat32(crosstalk.r); + FfxFloat32 capG = FfxFloat32(-crosstalk.g) * colorG + FfxFloat32(crosstalk.g); + FfxFloat32 capB = FfxFloat32(-crosstalk.b) * colorB + FfxFloat32(crosstalk.b); + + // Compute amount of luma needed to add to non-clipped channels to make up for clipping (3x MAD). + FfxFloat32 lumaAdd = ffxSaturate((-colorB) * FfxFloat32(lumaT.b) + ((-colorR) * FfxFloat32(lumaT.r) + ((-colorG) * FfxFloat32(lumaT.g) + luma))); + + // Amount to increase keeping over-exposure ratios constant and possibly exceeding clipping point (4x MAD, 1 RCP). + FfxFloat32 t = lumaAdd * ffxReciprocal(capG * FfxFloat32(lumaT.g) + (capR * FfxFloat32(lumaT.r) + (capB * FfxFloat32(lumaT.b)))); + + // Add amounts to base color but clip (3x MAD). + colorR = ffxSaturate(t * capR + colorR); + colorG = ffxSaturate(t * capG + colorG); + colorB = ffxSaturate(t * capB + colorB); + + // Compute amount of luma needed to add to non-clipped channel to make up for clipping (3x MAD). + lumaAdd = ffxSaturate((-colorB) * FfxFloat32(lumaT.b) + ((-colorR) * FfxFloat32(lumaT.r) + ((-colorG) * FfxFloat32(lumaT.g) + luma))); + + // Add to last channel (3x MAD). + colorR = ffxSaturate(lumaAdd * FfxFloat32(rcpLumaT.r) + colorR); + colorG = ffxSaturate(lumaAdd * FfxFloat32(rcpLumaT.g) + colorG); + colorB = ffxSaturate(lumaAdd * FfxFloat32(rcpLumaT.b) + colorB); + + // The 'con2' should be a compile-time immediate so branch will not exist. + // Last optional place to convert from smaller to larger gamut (or do clipped conversion). + // For the non-soft-falloff case, doing this after all other mapping saves intermediate re-scaling ratio to max 1.0. + if (con2) + { + // Change of primaries (9x MAD). + ratioR = colorR; + ratioG = colorG; + ratioB = colorB; + + if (clip) + { + colorR = ffxSaturate(ratioR * FfxFloat32(con2R.r) + (ratioG * FfxFloat32(con2R.g) + (ratioB * FfxFloat32(con2R.b)))); + colorG = ffxSaturate(ratioG * FfxFloat32(con2G.g) + (ratioR * FfxFloat32(con2G.r) + (ratioB * FfxFloat32(con2G.b)))); + colorB = ffxSaturate(ratioB * FfxFloat32(con2B.b) + (ratioG * FfxFloat32(con2B.g) + (ratioR * FfxFloat32(con2B.r)))); + } + else + { + colorR = ratioR * FfxFloat32(con2R.r) + (ratioG * FfxFloat32(con2R.g) + (ratioB * FfxFloat32(con2R.b))); + colorG = ratioG * FfxFloat32(con2G.g) + (ratioR * FfxFloat32(con2G.r) + (ratioB * FfxFloat32(con2G.b))); + colorB = ratioB * FfxFloat32(con2B.b) + (ratioG * FfxFloat32(con2B.g) + (ratioR * FfxFloat32(con2B.r))); + } + } + + if (scaleOnly) + { + colorR *= FfxFloat32(con2R.r); + colorG *= FfxFloat32(con2R.r); + colorB *= FfxFloat32(con2R.r); + } +} + +#if (FFX_HALF == 1) +// Packed FP16 version, see non-packed version above for all comments. +// Use LpmFilterH() instead of this. +void LpmMapH(inout FfxFloat16x2 colorR, + inout FfxFloat16x2 colorG, + inout FfxFloat16x2 colorB, + FfxFloat16x3 lumaW, + FfxFloat16x3 lumaT, + FfxFloat16x3 rcpLumaT, + FfxFloat16x3 saturation, + FfxFloat16 contrast, + FfxBoolean shoulder, + FfxFloat16 shoulderContrast, + FfxFloat16x2 toneScaleBias, + FfxFloat16x3 crosstalk, + FfxBoolean con, + FfxFloat16x3 conR, + FfxFloat16x3 conG, + FfxFloat16x3 conB, + FfxBoolean soft, + FfxFloat16x2 softGap, + FfxBoolean con2, + FfxBoolean clip, + FfxBoolean scaleOnly, + FfxFloat16x3 con2R, + FfxFloat16x3 con2G, + FfxFloat16x3 con2B) +{ + FfxFloat16x2 rcpMax = ffxReciprocalHalf(ffxMax3Half(colorR, colorG, colorB)); + FfxFloat16x2 ratioR = colorR * rcpMax; + FfxFloat16x2 ratioG = colorG * rcpMax; + FfxFloat16x2 ratioB = colorB * rcpMax; + ratioR = pow(ratioR, FFX_BROADCAST_FLOAT16X2(saturation.r)); + ratioG = pow(ratioG, FFX_BROADCAST_FLOAT16X2(saturation.g)); + ratioB = pow(ratioB, FFX_BROADCAST_FLOAT16X2(saturation.b)); + + FfxFloat16x2 luma; + if (soft) + luma = colorG * FFX_BROADCAST_FLOAT16X2(lumaW.g) + (colorR * FFX_BROADCAST_FLOAT16X2(lumaW.r) + (colorB * FFX_BROADCAST_FLOAT16X2(lumaW.b))); + else + luma = colorG * FFX_BROADCAST_FLOAT16X2(lumaT.g) + (colorR * FFX_BROADCAST_FLOAT16X2(lumaT.r) + (colorB * FFX_BROADCAST_FLOAT16X2(lumaT.b))); + luma = pow(luma, FFX_BROADCAST_FLOAT16X2(contrast)); + FfxFloat16x2 lumaShoulder = shoulder ? pow(luma, FFX_BROADCAST_FLOAT16X2(shoulderContrast)) : luma; + luma = luma * ffxReciprocalHalf(lumaShoulder * FFX_BROADCAST_FLOAT16X2(toneScaleBias.x) + FFX_BROADCAST_FLOAT16X2(toneScaleBias.y)); + + if (soft) + { + if (con) + { + colorR = ratioR; + colorG = ratioG; + colorB = ratioB; + ratioR = colorR * FFX_BROADCAST_FLOAT16X2(conR.r) + (colorG * FFX_BROADCAST_FLOAT16X2(conR.g) + (colorB * FFX_BROADCAST_FLOAT16X2(conR.b))); + ratioG = colorG * FFX_BROADCAST_FLOAT16X2(conG.g) + (colorR * FFX_BROADCAST_FLOAT16X2(conG.r) + (colorB * FFX_BROADCAST_FLOAT16X2(conG.b))); + ratioB = colorB * FFX_BROADCAST_FLOAT16X2(conB.b) + (colorG * FFX_BROADCAST_FLOAT16X2(conB.g) + (colorR * FFX_BROADCAST_FLOAT16X2(conB.r))); + rcpMax = ffxReciprocalHalf(ffxMax3Half(ratioR, ratioG, ratioB)); + ratioR *= rcpMax; + ratioG *= rcpMax; + ratioB *= rcpMax; + } + + ratioR = min(max(FFX_BROADCAST_FLOAT16X2(softGap.x), ffxSaturate(ratioR * FFX_BROADCAST_FLOAT16X2(-softGap.x) + ratioR)), + ffxSaturate(FFX_BROADCAST_FLOAT16X2(softGap.x) * exp2(ratioR * FFX_BROADCAST_FLOAT16X2(softGap.y)))); + ratioG = min(max(FFX_BROADCAST_FLOAT16X2(softGap.x), ffxSaturate(ratioG * FFX_BROADCAST_FLOAT16X2(-softGap.x) + ratioG)), + ffxSaturate(FFX_BROADCAST_FLOAT16X2(softGap.x) * exp2(ratioG * FFX_BROADCAST_FLOAT16X2(softGap.y)))); + ratioB = min(max(FFX_BROADCAST_FLOAT16X2(softGap.x), ffxSaturate(ratioB * FFX_BROADCAST_FLOAT16X2(-softGap.x) + ratioB)), + ffxSaturate(FFX_BROADCAST_FLOAT16X2(softGap.x) * exp2(ratioB * FFX_BROADCAST_FLOAT16X2(softGap.y)))); + } + + FfxFloat16x2 lumaRatio = ratioR * FFX_BROADCAST_FLOAT16X2(lumaT.r) + ratioG * FFX_BROADCAST_FLOAT16X2(lumaT.g) + ratioB * FFX_BROADCAST_FLOAT16X2(lumaT.b); + FfxFloat16x2 ratioScale = ffxSaturate(luma * ffxReciprocalHalf(lumaRatio)); + colorR = ffxSaturate(ratioR * ratioScale); + colorG = ffxSaturate(ratioG * ratioScale); + colorB = ffxSaturate(ratioB * ratioScale); + FfxFloat16x2 capR = FFX_BROADCAST_FLOAT16X2(-crosstalk.r) * colorR + FFX_BROADCAST_FLOAT16X2(crosstalk.r); + FfxFloat16x2 capG = FFX_BROADCAST_FLOAT16X2(-crosstalk.g) * colorG + FFX_BROADCAST_FLOAT16X2(crosstalk.g); + FfxFloat16x2 capB = FFX_BROADCAST_FLOAT16X2(-crosstalk.b) * colorB + FFX_BROADCAST_FLOAT16X2(crosstalk.b); + FfxFloat16x2 lumaAdd = ffxSaturate((-colorB) * FFX_BROADCAST_FLOAT16X2(lumaT.b) + + ((-colorR) * FFX_BROADCAST_FLOAT16X2(lumaT.r) + ((-colorG) * FFX_BROADCAST_FLOAT16X2(lumaT.g) + luma))); + FfxFloat16x2 t = lumaAdd * ffxReciprocalHalf(capG * FFX_BROADCAST_FLOAT16X2(lumaT.g) + + (capR * FFX_BROADCAST_FLOAT16X2(lumaT.r) + (capB * FFX_BROADCAST_FLOAT16X2(lumaT.b)))); + colorR = ffxSaturate(t * capR + colorR); + colorG = ffxSaturate(t * capG + colorG); + colorB = ffxSaturate(t * capB + colorB); + lumaAdd = ffxSaturate((-colorB) * FFX_BROADCAST_FLOAT16X2(lumaT.b) + + ((-colorR) * FFX_BROADCAST_FLOAT16X2(lumaT.r) + ((-colorG) * FFX_BROADCAST_FLOAT16X2(lumaT.g) + luma))); + colorR = ffxSaturate(lumaAdd * FFX_BROADCAST_FLOAT16X2(rcpLumaT.r) + colorR); + colorG = ffxSaturate(lumaAdd * FFX_BROADCAST_FLOAT16X2(rcpLumaT.g) + colorG); + colorB = ffxSaturate(lumaAdd * FFX_BROADCAST_FLOAT16X2(rcpLumaT.b) + colorB); + + if (con2) + { + ratioR = colorR; + ratioG = colorG; + ratioB = colorB; + if (clip) + { + colorR = ffxSaturate(ratioR * FFX_BROADCAST_FLOAT16X2(con2R.r) + + (ratioG * FFX_BROADCAST_FLOAT16X2(con2R.g) + (ratioB * FFX_BROADCAST_FLOAT16X2(con2R.b)))); + colorG = ffxSaturate(ratioG * FFX_BROADCAST_FLOAT16X2(con2G.g) + + (ratioR * FFX_BROADCAST_FLOAT16X2(con2G.r) + (ratioB * FFX_BROADCAST_FLOAT16X2(con2G.b)))); + colorB = ffxSaturate(ratioB * FFX_BROADCAST_FLOAT16X2(con2B.b) + + (ratioG * FFX_BROADCAST_FLOAT16X2(con2B.g) + (ratioR * FFX_BROADCAST_FLOAT16X2(con2B.r)))); + } + else + { + colorR = ratioR * FFX_BROADCAST_FLOAT16X2(con2R.r) + (ratioG * FFX_BROADCAST_FLOAT16X2(con2R.g) + (ratioB * FFX_BROADCAST_FLOAT16X2(con2R.b))); + colorG = ratioG * FFX_BROADCAST_FLOAT16X2(con2G.g) + (ratioR * FFX_BROADCAST_FLOAT16X2(con2G.r) + (ratioB * FFX_BROADCAST_FLOAT16X2(con2G.b))); + colorB = ratioB * FFX_BROADCAST_FLOAT16X2(con2B.b) + (ratioG * FFX_BROADCAST_FLOAT16X2(con2B.g) + (ratioR * FFX_BROADCAST_FLOAT16X2(con2B.r))); + } + } + + if (scaleOnly) + { + colorR *= FFX_BROADCAST_FLOAT16X2(con2R.r); + colorG *= FFX_BROADCAST_FLOAT16X2(con2R.r); + colorB *= FFX_BROADCAST_FLOAT16X2(con2R.r); + } +} +#endif // #if (FFX_HALF == 1) + +/// Filter call to tone and gamut map input pixel colour +/// +/// @param [inout] colorR Input of red value of pixel to be tone and gamut mapped and also where result will be stored. +/// @param [inout] colorG Input of green value of pixel to be tone and gamut mapped and also where result will be stored. +/// @param [inout] colorB Input of blue value of pixel to be tone and gamut mapped and also where result will be stored. +/// @param [in] shoulder Boolean to enable shoulder tuning +/// @param [in] con Same as described in setup call +/// @param [in] soft Same as described in setup call +/// @param [in] con2 Same as described in setup call +/// @param [in] clip Same as described in setup call +/// @param [in] scaleOnly Same as described in setup call +/// +/// @ingroup FfxGPULpm +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// +//_____________________________________________________________/\_______________________________________________________________ +//============================================================================================================================== +// FILTER +//------------------------------------------------------------------------------------------------------------------------------ +// Requires user define: FfxUInt32x4 LpmFilterCtl(FfxUInt32 index){...} to load control block values. +// Entry point for per-pixel color tone+gamut mapping. +// Input is linear color {0 to hdrMax} ranged. +// Output is linear color {0 to 1} ranged, except for scRGB where outputs can end up negative and larger than one. +//============================================================================================================================== +// 32-bit entry point. +void LpmFilter( + // Input and output color. + inout FfxFloat32 colorR, + inout FfxFloat32 colorG, + inout FfxFloat32 colorB, + // Path control should all be compile-time immediates. + FfxBoolean shoulder, // Using shoulder tuning. + // Prefab "LPM_CONFIG_" start, use the same as used for LpmSetup(). + FfxBoolean con, // Use first RGB conversion matrix, if 'soft' then 'con' must be true also. + FfxBoolean soft, // Use soft gamut mapping. + FfxBoolean con2, // Use last RGB conversion matrix. + FfxBoolean clip, // Use clipping in last conversion matrix. + FfxBoolean scaleOnly) // Scale only for last conversion matrix (used for 709 HDR to scRGB). +{ + // Grab control block, what is unused gets dead-code removal. + FfxUInt32x4 map0 = LpmFilterCtl(0); + FfxUInt32x4 map1 = LpmFilterCtl(1); + FfxUInt32x4 map2 = LpmFilterCtl(2); + FfxUInt32x4 map3 = LpmFilterCtl(3); + FfxUInt32x4 map4 = LpmFilterCtl(4); + FfxUInt32x4 map5 = LpmFilterCtl(5); + FfxUInt32x4 map6 = LpmFilterCtl(6); + FfxUInt32x4 map7 = LpmFilterCtl(7); + FfxUInt32x4 map8 = LpmFilterCtl(8); + FfxUInt32x4 map9 = LpmFilterCtl(9); + FfxUInt32x4 mapA = LpmFilterCtl(10); + FfxUInt32x4 mapB = LpmFilterCtl(11); + FfxUInt32x4 mapC = LpmFilterCtl(12); + FfxUInt32x4 mapD = LpmFilterCtl(13); + FfxUInt32x4 mapE = LpmFilterCtl(14); + FfxUInt32x4 mapF = LpmFilterCtl(15); + FfxUInt32x4 mapG = LpmFilterCtl(16); + FfxUInt32x4 mapH = LpmFilterCtl(17); + FfxUInt32x4 mapI = LpmFilterCtl(18); + FfxUInt32x4 mapJ = LpmFilterCtl(19); + FfxUInt32x4 mapK = LpmFilterCtl(20); + FfxUInt32x4 mapL = LpmFilterCtl(21); + FfxUInt32x4 mapM = LpmFilterCtl(22); + FfxUInt32x4 mapN = LpmFilterCtl(23); + + LpmMap(colorR, + colorG, + colorB, + FfxFloat32x3(ffxAsFloat(map6).g, ffxAsFloat(map6).b, ffxAsFloat(map6).a), // lumaW + FfxFloat32x3(ffxAsFloat(map1).b, ffxAsFloat(map1).a, ffxAsFloat(map2).r), // lumaT + FfxFloat32x3(ffxAsFloat(map3).r, ffxAsFloat(map3).g, ffxAsFloat(map3).b), // rcpLumaT + FfxFloat32x3(ffxAsFloat(map0).r, ffxAsFloat(map0).g, ffxAsFloat(map0).b), // saturation + ffxAsFloat(map0).a, // contrast + shoulder, + ffxAsFloat(map6).r, // shoulderContrast + FfxFloat32x2(ffxAsFloat(map1).r, ffxAsFloat(map1).g), // toneScaleBias + FfxFloat32x3(ffxAsFloat(map2).g, ffxAsFloat(map2).b, ffxAsFloat(map2).a), // crosstalk + con, + FfxFloat32x3(ffxAsFloat(map7).b, ffxAsFloat(map7).a, ffxAsFloat(map8).r), // conR + FfxFloat32x3(ffxAsFloat(map8).g, ffxAsFloat(map8).b, ffxAsFloat(map8).a), // conG + FfxFloat32x3(ffxAsFloat(map9).r, ffxAsFloat(map9).g, ffxAsFloat(map9).b), // conB + soft, + FfxFloat32x2(ffxAsFloat(map7).r, ffxAsFloat(map7).g), // softGap + con2, + clip, + scaleOnly, + FfxFloat32x3(ffxAsFloat(map3).a, ffxAsFloat(map4).r, ffxAsFloat(map4).g), // con2R + FfxFloat32x3(ffxAsFloat(map4).b, ffxAsFloat(map4).a, ffxAsFloat(map5).r), // con2G + FfxFloat32x3(ffxAsFloat(map5).g, ffxAsFloat(map5).b, ffxAsFloat(map5).a)); // con2B +} + +#if (FFX_HALF == 1) +// Packed 16-bit entry point (maps 2 colors at the same time). +void LpmFilterH(inout FfxFloat16x2 colorR, + inout FfxFloat16x2 colorG, + inout FfxFloat16x2 colorB, + FfxBoolean shoulder, + FfxBoolean con, + FfxBoolean soft, + FfxBoolean con2, + FfxBoolean clip, + FfxBoolean scaleOnly) +{ + // Grab control block, what is unused gets dead-code removal. + FfxUInt32x4 map0 = LpmFilterCtl(0); + FfxUInt32x4 map1 = LpmFilterCtl(1); + FfxUInt32x4 map2 = LpmFilterCtl(2); + FfxUInt32x4 map3 = LpmFilterCtl(3); + FfxUInt32x4 map4 = LpmFilterCtl(4); + FfxUInt32x4 map5 = LpmFilterCtl(5); + FfxUInt32x4 map6 = LpmFilterCtl(6); + FfxUInt32x4 map7 = LpmFilterCtl(7); + FfxUInt32x4 map8 = LpmFilterCtl(8); + FfxUInt32x4 map9 = LpmFilterCtl(9); + FfxUInt32x4 mapA = LpmFilterCtl(10); + FfxUInt32x4 mapB = LpmFilterCtl(11); + FfxUInt32x4 mapC = LpmFilterCtl(12); + FfxUInt32x4 mapD = LpmFilterCtl(13); + FfxUInt32x4 mapE = LpmFilterCtl(14); + FfxUInt32x4 mapF = LpmFilterCtl(15); + FfxUInt32x4 mapG = LpmFilterCtl(16); + FfxUInt32x4 mapH = LpmFilterCtl(17); + FfxUInt32x4 mapI = LpmFilterCtl(18); + FfxUInt32x4 mapJ = LpmFilterCtl(19); + FfxUInt32x4 mapK = LpmFilterCtl(20); + FfxUInt32x4 mapL = LpmFilterCtl(21); + FfxUInt32x4 mapM = LpmFilterCtl(22); + FfxUInt32x4 mapN = LpmFilterCtl(23); + + // Pre-limit inputs to provide enough head-room for computation in FP16. + // TODO: Document this better!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! + colorR = min(colorR, FFX_BROADCAST_FLOAT16X2(4096.0)); + colorG = min(colorG, FFX_BROADCAST_FLOAT16X2(4096.0)); + colorB = min(colorB, FFX_BROADCAST_FLOAT16X2(4096.0)); + + // Apply filter. + LpmMapH(colorR, + colorG, + colorB, + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapJ.r).y, FFX_UINT32_TO_FLOAT16X2(mapJ.g).x, FFX_UINT32_TO_FLOAT16X2(mapJ.g).y), // lumaW + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapG.a).x, FFX_UINT32_TO_FLOAT16X2(mapG.a).y, FFX_UINT32_TO_FLOAT16X2(mapH.r).x), // lumaT + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapH.b).x, FFX_UINT32_TO_FLOAT16X2(mapH.b).y, FFX_UINT32_TO_FLOAT16X2(mapH.a).x), // rcpLumaT + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapG.r).x, FFX_UINT32_TO_FLOAT16X2(mapG.r).y, FFX_UINT32_TO_FLOAT16X2(mapG.g).x), // saturation + FFX_UINT32_TO_FLOAT16X2(mapG.g).y, // contrast + shoulder, + FFX_UINT32_TO_FLOAT16X2(mapJ.r).x, // shoulderContrast + FFX_UINT32_TO_FLOAT16X2(mapG.b), // toneScaleBias + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapH.r).y, FFX_UINT32_TO_FLOAT16X2(mapH.g).x, FFX_UINT32_TO_FLOAT16X2(mapH.g).y), // crosstalk + con, + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapJ.a).x, FFX_UINT32_TO_FLOAT16X2(mapJ.a).y, FFX_UINT32_TO_FLOAT16X2(mapK.r).x), // conR + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapK.r).y, FFX_UINT32_TO_FLOAT16X2(mapK.g).x, FFX_UINT32_TO_FLOAT16X2(mapK.g).y), // conG + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapK.b).x, FFX_UINT32_TO_FLOAT16X2(mapK.b).y, FFX_UINT32_TO_FLOAT16X2(mapK.a).x), // conB + soft, + FFX_UINT32_TO_FLOAT16X2(mapJ.b), // softGap + con2, + clip, + scaleOnly, + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapH.a).y, FFX_UINT32_TO_FLOAT16X2(mapI.r).x, FFX_UINT32_TO_FLOAT16X2(mapI.r).y), // con2R + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapI.g).x, FFX_UINT32_TO_FLOAT16X2(mapI.g).y, FFX_UINT32_TO_FLOAT16X2(mapI.b).x), // con2G + FfxFloat16x3(FFX_UINT32_TO_FLOAT16X2(mapI.b).y, FFX_UINT32_TO_FLOAT16X2(mapI.a).x, FFX_UINT32_TO_FLOAT16X2(mapI.a).y)); // con2B +} +#endif // #if (FFX_HALF == 1) +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_callbacks_glsl.h new file mode 100644 index 00000000..d02758a0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_callbacks_glsl.h @@ -0,0 +1,171 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_lpm_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(LPM_BIND_CB_LPM) + layout (set = 0, binding = LPM_BIND_CB_LPM, std140) uniform cbLPM_t + { + FfxUInt32x4 ctl[24]; + FfxBoolean shoulder; + FfxBoolean con; + FfxBoolean soft; + FfxBoolean con2; + FfxBoolean clip; + FfxBoolean scaleOnly; + FfxUInt32 displayMode; + FfxUInt32 pad; + } cbLPM; +#else + #define ctl 0 + #define shoulder 0 + #define con 0 + #define soft 0 + #define con2 0 + #define clip 0 + #define scaleOnly 0 + #define displayMode 0 + #define pad 0 +#endif + +FfxUInt32x4 LpmFilterCtl(FfxUInt32 i) +{ + return cbLPM.ctl[i]; +} + +FfxBoolean GetShoulder() +{ + return cbLPM.shoulder; +} + +FfxBoolean GetCon() +{ + return cbLPM.con; +} + +FfxBoolean GetSoft() +{ + return cbLPM.soft; +} + +FfxBoolean GetCon2() +{ + return cbLPM.con2; +} + +FfxBoolean GetClip() +{ + return cbLPM.clip; +} + +FfxBoolean GetScaleOnly() +{ + return cbLPM.scaleOnly; +} + +FfxUInt32 GetMonitorDisplayMode() +{ + return cbLPM.displayMode; +} + +#if FFX_HALF +FfxFloat16x3 ApplyGamma(FfxFloat16x3 color) +{ + color = pow(color, FfxFloat16x3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2)); + return color; +} + +FfxFloat16x3 ApplyPQ(FfxFloat16x3 color) +{ + // Apply ST2084 curve + FfxFloat16 m1 = FfxFloat16(2610.0 / 4096.0 / 4.0); + FfxFloat16 m2 = FfxFloat16(2523.0 / 4096.0 * 128.0); + FfxFloat16 c1 = FfxFloat16(3424.0 / 4096.0); + FfxFloat16 c2 = FfxFloat16(2413.0 / 4096.0 * 32.0); + FfxFloat16 c3 = FfxFloat16(2392.0 / 4096.0 * 32.0); + FfxFloat16x3 cp = pow(abs(color.xyz), FfxFloat16x3(m1, m1, m1)); + color.xyz = pow((c1 + c2 * cp) / (FfxFloat16(1.0) + c3 * cp), FfxFloat16x3(m2, m2, m2)); + return color; +} +#else +FfxFloat32x3 ApplyGamma(FfxFloat32x3 color) +{ + color = pow(color, FfxFloat32x3(1.0 / 2.2, 1.0 / 2.2, 1.0 / 2.2)); + return color; +} + +FfxFloat32x3 ApplyPQ(FfxFloat32x3 color) +{ + // Apply ST2084 curve + FfxFloat32 m1 = 2610.0 / 4096.0 / 4; + FfxFloat32 m2 = 2523.0 / 4096.0 * 128; + FfxFloat32 c1 = 3424.0 / 4096.0; + FfxFloat32 c2 = 2413.0 / 4096.0 * 32; + FfxFloat32 c3 = 2392.0 / 4096.0 * 32; + FfxFloat32x3 cp = pow(abs(color.xyz), FfxFloat32x3(m1, m1, m1)); + color.xyz = pow((c1 + c2 * cp) / (1 + c3 * cp), FfxFloat32x3(m2, m2, m2)); + return color; +} +#endif + +layout (set = 0, binding = 1000) uniform sampler s_LinearClamp; + +#if FFX_HALF +#define ColorFormat FfxFloat16x4 +#define OutputFormat rgba16f +#else +#define ColorFormat FfxFloat32x4 +#define OutputFormat rgba32f +#endif + +// SRVs +#if defined LPM_BIND_SRV_INPUT_COLOR + layout (set = 0, binding = LPM_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color; +#endif + +// UAV declarations +#if defined LPM_BIND_UAV_OUTPUT_COLOR + layout (set = 0, binding = LPM_BIND_UAV_OUTPUT_COLOR, OutputFormat) uniform image2D rw_output_color; +#endif + +#if defined(LPM_BIND_SRV_INPUT_COLOR) +ColorFormat LoadInput(FfxUInt32x2 iPxPos) +{ + return ColorFormat(texelFetch(r_input_color, FfxInt32x2(iPxPos), 0)); +} +#endif // defined(LPM_BIND_SRV_INPUT_COLOR) + +#if defined(LPM_BIND_UAV_OUTPUT_COLOR) +void StoreOutput(FfxUInt32x2 iPxPos, ColorFormat fColor) +{ + imageStore(rw_output_color, FfxInt32x2(iPxPos), fColor); +} +#endif // defined(LPM_BIND_UAV_OUTPUT_COLOR) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_callbacks_hlsl.h new file mode 100644 index 00000000..99b62287 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_callbacks_hlsl.h @@ -0,0 +1,205 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_lpm_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_LPM_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_LPM_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_LPM_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(LPM_BIND_CB_LPM) + cbuffer cbLPM : FFX_LPM_DECLARE_CB(LPM_BIND_CB_LPM) + { + FfxUInt32x4 ctl[24]; + FfxBoolean shoulder; + FfxBoolean con; + FfxBoolean soft; + FfxBoolean con2; + FfxBoolean clip; + FfxBoolean scaleOnly; + FfxUInt32 displayMode; + FfxUInt32 pad; + #define FFX_LPM_CONSTANT_BUFFER_1_SIZE 32 // Number of 32-bit values. This must be kept in sync with the cbLPM size. + }; +#else + #define ctl 0 + #define shoulder 0 + #define con 0 + #define soft 0 + #define con2 0 + #define clip 0 + #define scaleOnly 0 + #define displayMode 0 + #define pad 0 +#endif + +#if defined(FFX_GPU) +#define FFX_LPM_ROOTSIG_STRINGIFY(p) FFX_LPM_ROOTSIG_STR(p) +#define FFX_LPM_ROOTSIG_STR(p) #p +#define FFX_LPM_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_LPM_ROOTSIG_STRINGIFY(FFX_LPM_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_LPM_ROOTSIG_STRINGIFY(FFX_LPM_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_NEVER, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK)" )] + +#if defined(FFX_LPM_EMBED_ROOTSIG) +#define FFX_LPM_EMBED_ROOTSIG_CONTENT FFX_LPM_ROOTSIG +#else +#define FFX_LPM_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_LPM_EMBED_ROOTSIG +#endif // #if defined(FFX_GPU) + +FfxUInt32x4 LpmFilterCtl(FfxUInt32 i) +{ + return ctl[i]; +} + +FfxBoolean GetShoulder() +{ + return shoulder; +} + +FfxBoolean GetCon() +{ + return con; +} + +FfxBoolean GetSoft() +{ + return soft; +} + +FfxBoolean GetCon2() +{ + return con2; +} + +FfxBoolean GetClip() +{ + return clip; +} + +FfxBoolean GetScaleOnly() +{ + return scaleOnly; +} + +FfxUInt32 GetMonitorDisplayMode() +{ + return displayMode; +} + +#if FFX_HALF +FfxFloat16x3 ApplyGamma(FfxFloat16x3 color) +{ + color = ffxPow(color, FfxFloat16(1.0f / 2.2f)); + return color; +} + +FfxFloat16x3 ApplyPQ(FfxFloat16x3 color) +{ + // Apply ST2084 curve + FfxFloat16 m1 = 2610.0 / 4096.0 / 4; + FfxFloat16 m2 = 2523.0 / 4096.0 * 128; + FfxFloat16 c1 = 3424.0 / 4096.0; + FfxFloat16 c2 = 2413.0 / 4096.0 * 32; + FfxFloat16 c3 = 2392.0 / 4096.0 * 32; + FfxFloat16x3 cp = ffxPow(abs(color.xyz), m1); + color.xyz = ffxPow((c1 + c2 * cp) / (1 + c3 * cp), m2); + return color; +} +#else +FfxFloat32x3 ApplyGamma(FfxFloat32x3 color) +{ + color = ffxPow(color, 1.0f / 2.2f); + return color; +} + +FfxFloat32x3 ApplyPQ(FfxFloat32x3 color) +{ + // Apply ST2084 curve + FfxFloat32 m1 = 2610.0 / 4096.0 / 4; + FfxFloat32 m2 = 2523.0 / 4096.0 * 128; + FfxFloat32 c1 = 3424.0 / 4096.0; + FfxFloat32 c2 = 2413.0 / 4096.0 * 32; + FfxFloat32 c3 = 2392.0 / 4096.0 * 32; + FfxFloat32x3 cp = ffxPow(abs(color.xyz), m1); + color.xyz = ffxPow((c1 + c2 * cp) / (1 + c3 * cp), m2); + return color; +} +#endif + +SamplerState s_LinearClamp : register(s0); + +#if FFX_HALF +#define ColorFormat FfxFloat16x4 +#else +#define ColorFormat FfxFloat32x4 +#endif + + // SRVs + #if defined LPM_BIND_SRV_INPUT_COLOR + Texture2D r_input_color : FFX_LPM_DECLARE_SRV(LPM_BIND_SRV_INPUT_COLOR); + #endif + // UAV declarations + #if defined LPM_BIND_UAV_OUTPUT_COLOR + RWTexture2D rw_output_color : FFX_LPM_DECLARE_UAV(LPM_BIND_UAV_OUTPUT_COLOR); + #endif + +#if defined(LPM_BIND_SRV_INPUT_COLOR) +ColorFormat LoadInput(FfxUInt32x2 iPxPos) +{ + return r_input_color[iPxPos]; +} +#endif // defined(LPM_BIND_SRV_INPUT_COLOR) + +#if defined(LPM_BIND_UAV_OUTPUT_COLOR) +void StoreOutput(FfxUInt32x2 iPxPos, ColorFormat fColor) +{ + rw_output_color[iPxPos] = fColor; +} +#endif // defined(LPM_BIND_UAV_OUTPUT_COLOR) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_filter.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_filter.h new file mode 100644 index 00000000..01a41fb4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_filter.h @@ -0,0 +1,129 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#define LPM_NO_SETUP 1 +#include "lpm/ffx_lpm.h" + +#if FFX_HALF + void CurrFilter(FfxUInt32x4 twoPixelPosInQuad) + { + FfxFloat16x4 pixelOneColor = LoadInput(twoPixelPosInQuad.xy); + FfxFloat16x4 pixelTwoColor = LoadInput(twoPixelPosInQuad.zw); + + FfxFloat16x2 redPair = FfxFloat16x2(pixelOneColor.r, pixelTwoColor.r); + FfxFloat16x2 greenPair = FfxFloat16x2(pixelOneColor.g, pixelTwoColor.g); + FfxFloat16x2 bluePair = FfxFloat16x2(pixelOneColor.b, pixelTwoColor.b); + + LpmFilterH(redPair, greenPair, bluePair, GetShoulder(), GetCon(), GetSoft(), GetCon2(), GetClip(), GetScaleOnly()); + + pixelOneColor.rgb = FfxFloat16x3(redPair.x, greenPair.x, bluePair.x); + pixelTwoColor.rgb = FfxFloat16x3(redPair.y, greenPair.y, bluePair.y); + + switch (GetMonitorDisplayMode()) + { + case 0: // Corresponds to FFX_LPM_DISPLAYMODE_LDR + pixelOneColor.xyz = ApplyGamma(pixelOneColor.xyz); + pixelTwoColor.xyz = ApplyGamma(pixelTwoColor.xyz); + break; + + case 1: // Corresponds to FFX_LPM_DISPLAYMODE_HDR10_2084 + case 3: // Corresponds to FFX_LPM_DISPLAYMODE_FSHDR_2084 + pixelOneColor.xyz = ApplyPQ(pixelOneColor.xyz); + pixelTwoColor.xyz = ApplyPQ(pixelTwoColor.xyz); + break; + } + + StoreOutput(twoPixelPosInQuad.xy, pixelOneColor); + StoreOutput(twoPixelPosInQuad.zw, pixelTwoColor); + } +#else + void CurrFilter(FfxUInt32x2 onePixelPosInQuad) + { + FfxFloat32x4 color = LoadInput(onePixelPosInQuad); + LpmFilter(color.r, color.g, color.b, GetShoulder(), GetCon(), GetSoft(), GetCon2(), GetClip(), GetScaleOnly()); + + switch (GetMonitorDisplayMode()) + { + case 0: // Corresponds to FFX_LPM_DISPLAYMODE_LDR + color.xyz = ApplyGamma(color.xyz); + break; + + case 1: // Corresponds to FFX_LPM_DISPLAYMODE_HDR10_2084 + case 3: // Corresponds to FFX_LPM_DISPLAYMODE_FSHDR_2084 + color.xyz = ApplyPQ(color.xyz); + break; + } + + StoreOutput(onePixelPosInQuad, color); + } +#endif + +void LPMFilter(FfxUInt32x3 LocalThreadId, FfxUInt32x3 WorkGroupId, FfxUInt32x3 Dtid) +{ + #if FFX_HALF + // Do remapping of local xy in workgroup for a more PS-like swizzle pattern. + // But this time for fp16 since LPM can output two colors at a time, we will store coordinates of two pixels at a time + FfxUInt32x4 twoPixelPosInQuad; + + // Get top left pixel in quad and store in xy component + twoPixelPosInQuad.xy = ffxRemapForQuad(LocalThreadId.x) + FfxUInt32x2(WorkGroupId.x << 4u, WorkGroupId.y << 4u); + + // Get top right pixel in quad and store in zw component + twoPixelPosInQuad.zw = twoPixelPosInQuad.xy; + twoPixelPosInQuad.z += 8u; + + // now call lpm fp16 on both together + CurrFilter(twoPixelPosInQuad); + + // Get bottom right pixel in quad and store in xy component + twoPixelPosInQuad.xy = twoPixelPosInQuad.zw; + twoPixelPosInQuad.y += 8u; + + // Get bottom left pixel in quad and store in zw component + twoPixelPosInQuad.zw = twoPixelPosInQuad.xy; + twoPixelPosInQuad.z -= 8u; + + // now call lpm fp16 on both together + CurrFilter(twoPixelPosInQuad); + #else + // Do remapping of local xy in workgroup for a more PS-like swizzle pattern. + FfxUInt32x2 onePixelPosInQuad; + + // Get top left pixel in quad + onePixelPosInQuad = ffxRemapForQuad(LocalThreadId.x) + FfxUInt32x2(WorkGroupId.x << 4u, WorkGroupId.y << 4u); + CurrFilter(onePixelPosInQuad); + + // Get top right + onePixelPosInQuad.x += 8u; + CurrFilter(onePixelPosInQuad); + + // Get bottom right + onePixelPosInQuad.y += 8u; + CurrFilter(onePixelPosInQuad); + + // Get bottom left + onePixelPosInQuad.x -= 8u; + CurrFilter(onePixelPosInQuad); + #endif +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_resources.h new file mode 100644 index 00000000..5491ca6c --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/lpm/ffx_lpm_resources.h @@ -0,0 +1,37 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_LPM_RESOURCES_H +#define FFX_LPM_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) +#define FFX_LPM_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_LPM_RESOURCE_IDENTIFIER_INPUT_COLOR 1 +#define FFX_LPM_RESOURCE_IDENTIFIER_OUTPUT_COLOR 2 + +#define FFX_LPM_RESOURCE_IDENTIFIER_COUNT 3 + +#define FFX_LPM_CONSTANTBUFFER_IDENTIFIER_LPM 0 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif //!defined( FFX_LPM_RESOURCES_H ) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/opticalflow/CMakeCompileOpticalflowShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/opticalflow/CMakeCompileOpticalflowShaders.txt new file mode 100644 index 00000000..5e4c2733 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/opticalflow/CMakeCompileOpticalflowShaders.txt @@ -0,0 +1,55 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(OPTICALFLOW_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(OPTICALFLOW_PERMUTATION_ARGS + -DFFX_OPTICALFLOW_OPTION_HDR_COLOR_INPUT={0,1} + ) + +set(OPTICALFLOW_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/opticalflow") + +if (NOT OPTICALFLOW_SHADER_EXT) + set(OPTICALFLOW_SHADER_EXT *) +endif() + +file(GLOB OPTICALFLOW_SHADERS + "shaders/opticalflow/ffx_opticalflow_prepare_luma_pass.${OPTICALFLOW_SHADER_EXT}" + "shaders/opticalflow/ffx_opticalflow_compute_luminance_pyramid_pass.${OPTICALFLOW_SHADER_EXT}" + "shaders/opticalflow/ffx_opticalflow_generate_scd_histogram_pass.${OPTICALFLOW_SHADER_EXT}" + "shaders/opticalflow/ffx_opticalflow_compute_scd_divergence_pass.${OPTICALFLOW_SHADER_EXT}" + "shaders/opticalflow/ffx_opticalflow_compute_optical_flow_advanced_pass_v5.${OPTICALFLOW_SHADER_EXT}" + "shaders/opticalflow/ffx_opticalflow_filter_optical_flow_pass_v5.${OPTICALFLOW_SHADER_EXT}" + "shaders/opticalflow/ffx_opticalflow_scale_optical_flow_advanced_pass_v5.${OPTICALFLOW_SHADER_EXT}" +) + +# compile all the shaders +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${OPTICALFLOW_BASE_ARGS}" "${OPTICALFLOW_API_BASE_ARGS}" "${OPTICALFLOW_PERMUTATION_ARGS}" "${OPTICALFLOW_INCLUDE_ARGS}" + "${OPTICALFLOW_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" OPTICALFLOW_PERMUTATION_OUTPUTS) + +# add the header files they generate to the main list of dependencies +add_shader_output("${OPTICALFLOW_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/opticalflow/ffx_opticalflow_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/opticalflow/ffx_opticalflow_callbacks_glsl.h new file mode 100644 index 00000000..da315ec3 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/opticalflow/ffx_opticalflow_callbacks_glsl.h @@ -0,0 +1,578 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_OPTICALFLOW_CALLBACKS_HLSL_H +#define FFX_OPTICALFLOW_CALLBACKS_HLSL_H + +#include "opticalflow/ffx_opticalflow_resources.h" + +// no msad4 in glsl +#define FFX_OPTICALFLOW_USE_MSAD4_INSTRUCTION 0 +#define FFX_OPTICALFLOW_FIX_TOP_LEFT_BIAS 1 +#define FFX_OPTICALFLOW_USE_HEURISTICS 1 +#define FFX_OPTICALFLOW_BLOCK_SIZE 8 +#define FFX_LOCAL_SEARCH_FALLBACK 1 + +// perf optimization for h/w not supporting accelerated msad4() +//#if !defined(FFX_PREFER_WAVE64) && defined(FFX_OPTICALFLOW_USE_MSAD4_INSTRUCTION) +//#undef FFX_OPTICALFLOW_USE_MSAD4_INSTRUCTION +//#endif + +#if defined(FFX_GPU) +#include "ffx_core.h" +#endif // #if defined(FFX_GPU) + +#if defined(FFX_GPU) +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #if defined(FFX_GPU) + + +#include "opticalflow/ffx_opticalflow_common.h" + + +#if defined(FFX_OPTICALFLOW_BIND_CB_COMMON) + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_CB_COMMON, std140) uniform cbOF_t + { + FfxInt32x2 iInputLumaResolution; + FfxUInt32 uOpticalFlowPyramidLevel; + FfxUInt32 uOpticalFlowPyramidLevelCount; + + FfxUInt32 iFrameIndex; + FfxUInt32 backbufferTransferFunction; + FfxFloat32x2 minMaxLuminance; + } cbOF; + +FfxInt32x2 DisplaySize() +{ + return cbOF.iInputLumaResolution; +} + +FfxUInt32 FrameIndex() +{ + return cbOF.iFrameIndex; +} + +FfxUInt32 BackbufferTransferFunction() +{ + return cbOF.backbufferTransferFunction; +} + +FfxFloat32x2 MinMaxLuminance() +{ + return cbOF.minMaxLuminance; +} + +FfxBoolean CrossedSceneChangeThreshold(FfxFloat32 sceneChangeValue) +{ + return sceneChangeValue > 0.45f; +} + +FfxUInt32 OpticalFlowPyramidLevel() +{ + return cbOF.uOpticalFlowPyramidLevel; +} + +FfxUInt32 OpticalFlowPyramidLevelCount() +{ + return cbOF.uOpticalFlowPyramidLevelCount; +} + +FfxInt32x2 OpticalFlowHistogramMaxVelocity() +{ + const FfxInt32 searchRadius = 8; + FfxInt32 scale = FfxInt32(1) << (OpticalFlowPyramidLevelCount() - 1 - OpticalFlowPyramidLevel()); + FfxInt32 maxVelocity = searchRadius * scale; + return FfxInt32x2(maxVelocity, maxVelocity); +} +#endif //FFX_OPTICALFLOW_BIND_CB_COMMON + +#if defined(FFX_OPTICALFLOW_BIND_CB_SPD) + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_CB_SPD, std140) uniform cbOF_SPD_t + { + FfxUInt32 mips; + FfxUInt32 numWorkGroups; + FfxUInt32x2 workGroupOffset; + FfxUInt32 numWorkGroupOpticalFlowInputPyramid; + FfxUInt32 pad0_; + FfxUInt32 pad1_; + FfxUInt32 pad2_; + } cbOF_SPD; + +uint NumWorkGroups() +{ + return cbOF_SPD.numWorkGroupOpticalFlowInputPyramid; +} +#endif // defined(FFX_OPTICALFLOW_BIND_CB_SPD) + + #if defined FFX_OPTICALFLOW_BIND_SRV_INPUT_COLOR + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_INPUT_MOTION_VECTORS + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_INPUT_MOTION_VECTORS) uniform texture2D r_input_motion_vectors; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_INPUT + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_INPUT) uniform utexture2D r_optical_flow_input; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_PREVIOUS_INPUT + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_PREVIOUS_INPUT) uniform utexture2D r_optical_flow_previous_input; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW) uniform itexture2D r_optical_flow; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_PREVIOUS + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_PREVIOUS) uniform itexture2D r_optical_flow_previous; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_ADDITIONAL_INFO + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_ADDITIONAL_INFO) uniform utexture2D r_optical_flow_additional_info; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_ADDITIONAL_INFO_PREVIOUS + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_ADDITIONAL_INFO_PREVIOUS) uniform utexture2D r_optical_flow_additional_info_previous; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_HISTOGRAM + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_HISTOGRAM) uniform utexture2D r_optical_flow_histogram; + #endif + #if defined FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH) uniform utexture2D r_optical_flow_global_motion_search; + #endif + + // UAV declarations + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT, r8ui) uniform uimage2D rw_optical_flow_input; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_1 + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_1, r8ui) uniform uimage2D rw_optical_flow_input_level_1; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_2 + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_2, r8ui) uniform uimage2D rw_optical_flow_input_level_2; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_3 + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_3, r8ui) uniform uimage2D rw_optical_flow_input_level_3; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_4 + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_4, r8ui) uniform uimage2D rw_optical_flow_input_level_4; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_5 + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_5, r8ui) uniform uimage2D rw_optical_flow_input_level_5; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_6 + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_6, r8ui) uniform uimage2D rw_optical_flow_input_level_6; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW, rg16i) uniform iimage2D rw_optical_flow; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_NEXT_LEVEL + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_NEXT_LEVEL, rg16i) uniform iimage2D rw_optical_flow_next_level; + #endif + //#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO + // RWTexture2D rw_optical_flow_additional_info : FFX_OPTICALFLOW_DECLARE_UAV(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO); + // layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO, r32ui) uniform uimage2D rw_optical_flow_additional_info; + //#endif + //#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO_NEXT_LEVEL + // RWTexture2D rw_optical_flow_additional_info_next_level : FFX_OPTICALFLOW_DECLARE_UAV(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO_NEXT_LEVEL); + // layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO_NEXT_LEVEL, r32ui) uniform uimage2D rw_optical_flow_additional_info_next_level; + //#endif + //#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_HISTOGRAM + // RWTexture2D rw_optical_flow_histogram : FFX_OPTICALFLOW_DECLARE_UAV(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_HISTOGRAM); + // layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_HISTOGRAM, r32ui) uniform uimage2D rw_optical_flow_histogram; + //#endif + //#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH + // globallycoherent RWTexture2D rw_optical_flow_global_motion_search: FFX_OPTICALFLOW_DECLARE_UAV(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH); + // layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH, r32ui) coherent uniform uimage2D rw_optical_flow_global_motion_search; + //#endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_HISTOGRAM + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_HISTOGRAM, r32ui) uniform uimage2D rw_optical_flow_scd_histogram; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_PREVIOUS_HISTOGRAM + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_PREVIOUS_HISTOGRAM, r32f) uniform image2D rw_optical_flow_scd_previous_histogram; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_TEMP + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_TEMP, r32ui) uniform uimage2D rw_optical_flow_scd_temp; + #endif + #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_OUTPUT + layout (set = 0, binding = FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_OUTPUT, r32ui) uniform uimage2D rw_optical_flow_scd_output; + #endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_INPUT_COLOR) +FfxFloat32x4 LoadInputColor(FfxUInt32x2 iPxHistory) +{ + return texelFetch(r_input_color, FfxInt32x2(iPxHistory), 0); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_INPUT_MOTION_VECTORS) +FfxFloat32x2 LoadGameMotionVector(FfxInt32x2 iPxPos) +{ + FfxFloat32x2 positionScale = FfxFloat32x2(RenderSize()) / DisplaySize(); + return texelFetch(r_input_motion_vectors, FfxInt32x2(iPxPos * positionScale), 0).xy * motionVectorScale / positionScale; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT) +void StoreOpticalFlowInput(FfxInt32x2 iPxPos, FfxUInt32 fLuma) +{ + imageStore(rw_optical_flow_input, iPxPos, FfxUInt32x4(fLuma, 0, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_INPUT) +FfxUInt32 LoadOpticalFlowInput(FfxInt32x2 iPxPos) +{ +#if FFX_OPTICALFLOW_USE_MSAD4_INSTRUCTION == 1 + return max(1, texelFetch(r_optical_flow_input, iPxPos, 0).x); +#else + return texelFetch(r_optical_flow_input, iPxPos, 0).x; +#endif +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT) +FfxUInt32 LoadRwOpticalFlowInput(FfxInt32x2 iPxPos) +{ + return imageLoad(rw_optical_flow_input, iPxPos).x; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_PREVIOUS_INPUT) +FfxUInt32 LoadOpticalFlowPreviousInput(FfxInt32x2 iPxPos) +{ +#if FFX_OPTICALFLOW_USE_MSAD4_INSTRUCTION == 1 + return max(1, texelFetch(r_optical_flow_previous_input, iPxPos, 0).x); +#else + return texelFetch(r_optical_flow_previous_input, iPxPos, 0).x; +#endif +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW) +FfxInt32x2 LoadOpticalFlow(FfxInt32x2 iPxPos) +{ + return texelFetch(r_optical_flow, iPxPos, 0).xy; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW) +FfxInt32x2 LoadRwOpticalFlow(FfxInt32x2 iPxPos) +{ + return imageLoad(rw_optical_flow, iPxPos).xy; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_PREVIOUS) +FfxInt32x2 LoadPreviousOpticalFlow(FfxInt32x2 iPxPos) +{ + return texelFetch(r_optical_flow_previous, iPxPos, 0).xy; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW) +void StoreOpticalFlow(FfxInt32x2 iPxPos, FfxInt32x2 motionVector) +{ + imageStore(rw_optical_flow, iPxPos, FfxInt32x4(motionVector, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_NEXT_LEVEL) +void StoreOpticalFlowNextLevel(FfxInt32x2 iPxPos, FfxInt32x2 motionVector) +{ + imageStore(rw_optical_flow_next_level, iPxPos, FfxInt32x4(motionVector, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_ADDITIONAL_INFO) +FfxUInt32x2 LoadOpticalFlowAdditionalInfo(FfxInt32x2 iPxPos) +{ + return texelFetch(r_optical_flow_additional_info, iPxPos, 0).xy; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO) +FfxUInt32x2 LoadRwOpticalFlowAdditionalInfo(FfxInt32x2 iPxPos) +{ + return imageLoad(rw_optical_flow_additional_info, iPxPos).xy; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_ADDITIONAL_INFO_PREVIOUS) +FfxUInt32x2 LoadPreviousOpticalFlowAdditionalInfo(FfxInt32x2 iPxPos) +{ + return texelFetch(r_optical_flow_additional_info_previous, iPxPos, 0).xy; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO) +void StoreOpticalFlowAdditionalInfo(FfxInt32x2 iPxPos, FfxUInt32x2 additionalInfo) +{ + imageStore(rw_optical_flow_additional_info, iPxPos, FfxUInt32x4(additionalInfo, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_ADDITIONAL_INFO_NEXT_LEVEL) +void StoreOpticalFlowNextLevelAdditionalInfo(FfxInt32x2 iPxPos, FfxUInt32x2 additionalInfo) +{ + imageStore(rw_optical_flow_additional_info_next_level, iPxPos, FfxUInt32x4(additionalInfo, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_HISTOGRAM) +FfxUInt32 LoadOpticalFlowHistogram(FfxInt32x2 iBucketId) +{ + return texelFetch(r_optical_flow_histogram, iBucketId, 0).x; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_HISTOGRAM) +void AtomicIncrementOpticalFlowHistogram(FfxInt32x2 iBucketId) +{ + imageAtomicAdd(rw_optical_flow_histogram, iBucketId, 1); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH) +FfxInt32x2 LoadGlobalMotionVector() +{ + FfxInt32 vx = FfxInt32(texelFetch(r_optical_flow_global_motion_search, FfxInt32x2(0, 0), 0).x); + FfxInt32 vy = FfxInt32(texelFetch(r_optical_flow_global_motion_search, FfxInt32x2(1, 0), 0).x); + return FfxInt32x2(vx, vy); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH) +FfxInt32x2 LoadRwGlobalMotionVector() +{ + FfxInt32 vx = FfxInt32(imageLoad(rw_optical_flow_global_motion_search, FfxInt32x2(0, 0)).x); + FfxInt32 vy = FfxInt32(imageLoad(rw_optical_flow_global_motion_search, FfxInt32x2(1, 0)).x); + return FfxInt32x2(vx, vy); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH) +FfxUInt32 LoadGlobalMotionValue(FfxInt32 index) +{ + return imageLoad(rw_optical_flow_global_motion_search, FfxInt32x2(index, 0)).x; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH) +void StoreGlobalMotionValue(FfxInt32 index, FfxUInt32 value) +{ + imageStore(rw_optical_flow_global_motion_search, FfxInt32x2(index, 0), FfxUInt32x4(value, 0, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_GLOBAL_MOTION_SEARCH) +FfxUInt32 AtomicIncrementGlobalMotionValue(FfxInt32 index) +{ + return imageAtomicAdd(rw_optical_flow_global_motion_search, FfxInt32x2(index, 0), 1); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_HISTOGRAM) +FfxUInt32 LoadRwSCDHistogram(FfxInt32 iIndex) +{ + return imageLoad(rw_optical_flow_scd_histogram, FfxInt32x2(iIndex, 0)).x; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_HISTOGRAM) +void StoreSCDHistogram(FfxInt32 iIndex, FfxUInt32 value) +{ + imageStore(rw_optical_flow_scd_histogram, FfxInt32x2(iIndex, 0), FfxUInt32x4(value, 0, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_HISTOGRAM) +void AtomicIncrementSCDHistogram(FfxInt32 iIndex, FfxUInt32 valueToAdd) +{ + imageAtomicAdd(rw_optical_flow_scd_histogram, FfxInt32x2(iIndex, 0), valueToAdd); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_PREVIOUS_HISTOGRAM) +FfxFloat32 LoadRwSCDPreviousHistogram(FfxInt32 iIndex) +{ + return imageLoad(rw_optical_flow_scd_previous_histogram, FfxInt32x2(iIndex, 0)).x; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_PREVIOUS_HISTOGRAM) +void StoreSCDPreviousHistogram(FfxInt32 iIndex, FfxFloat32 value) +{ + imageStore(rw_optical_flow_scd_previous_histogram, FfxInt32x2(iIndex, 0), FfxFloat32x4(value, 0.0, 0.0, 0.0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_TEMP) +FfxUInt32 LoadRwSCDTemp(FfxInt32 iIndex) +{ + return imageLoad(rw_optical_flow_scd_temp, FfxInt32x2(iIndex, 0)).x; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_TEMP) +void AtomicIncrementSCDTemp(FfxInt32 iIndex, FfxUInt32 valueToAdd) +{ + imageAtomicAdd(rw_optical_flow_scd_temp, FfxInt32x2(iIndex, 0), valueToAdd); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_TEMP) +void ResetSCDTemp() +{ + imageStore(rw_optical_flow_scd_temp, FfxInt32x2(0, 0), FfxUInt32x4(0, 0, 0, 0)); + imageStore(rw_optical_flow_scd_temp, FfxInt32x2(1, 0), FfxUInt32x4(0, 0, 0, 0)); + imageStore(rw_optical_flow_scd_temp, FfxInt32x2(2, 0), FfxUInt32x4(0, 0, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_OUTPUT) +FfxUInt32 LoadRwSCDOutput(FfxInt32 iIndex) +{ + return imageLoad(rw_optical_flow_scd_output, FfxInt32x2(iIndex, 0)).x; +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_OUTPUT) +void StoreSCDOutput(FfxInt32 iIndex, FfxUInt32 value) +{ + imageStore(rw_optical_flow_scd_output, FfxInt32x2(iIndex, 0), FfxUInt32x4(value, 0, 0, 0)); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_OUTPUT) +FfxUInt32 AtomicIncrementSCDOutput(FfxInt32 iIndex, FfxUInt32 valueToAdd) +{ + return imageAtomicAdd(rw_optical_flow_scd_output, FfxInt32x2(iIndex, 0), valueToAdd); +} +#endif + +//#if defined(FFX_OPTICALFLOW_BIND_UAV_DEBUG_VISUALIZATION) +//void StoreDebugVisualization(FfxUInt32x2 iPxPos, FfxFloat32x3 fColor) +//{ +// imageStore(rw_debug_visualization, iPxPos, FfxFloat32x4(fColor, 1.f)); +//} +//#endif + +#if defined(FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_SCD_OUTPUT) +FfxFloat32 GetSceneChangeValue() +{ + if (FrameIndex() <= 5) + return 1.0; + else + return ffxAsFloat(LoadRwSCDOutput(SCD_OUTPUT_SCENE_CHANGE_SLOT)); +} + +FfxBoolean IsSceneChanged() +{ + if (FrameIndex() <= 5) + { + return true; + } + else + { + return (LoadRwSCDOutput(SCD_OUTPUT_HISTORY_BITS_SLOT) & 0xfu) != 0; + } +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_INPUT) +FfxUInt32 LoadFirstImagePackedLuma(FfxInt32x2 iPxPos) +{ + const FfxInt32 lumaTextureWidth = DisplaySize().x >> OpticalFlowPyramidLevel(); + const FfxInt32 lumaTextureHeight = DisplaySize().y >> OpticalFlowPyramidLevel(); + + FfxInt32x2 adjustedPos = FfxInt32x2( + ffxClamp(iPxPos.x, 0, lumaTextureWidth - 4), + ffxClamp(iPxPos.y, 0, lumaTextureHeight - 1) + ); + + FfxUInt32 luma0 = LoadOpticalFlowInput(adjustedPos + FfxInt32x2(0, 0)); + FfxUInt32 luma1 = LoadOpticalFlowInput(adjustedPos + FfxInt32x2(1, 0)); + FfxUInt32 luma2 = LoadOpticalFlowInput(adjustedPos + FfxInt32x2(2, 0)); + FfxUInt32 luma3 = LoadOpticalFlowInput(adjustedPos + FfxInt32x2(3, 0)); + + return GetPackedLuma(lumaTextureWidth, iPxPos.x, luma0, luma1, luma2, luma3); +} +#endif + +#if defined(FFX_OPTICALFLOW_BIND_SRV_OPTICAL_FLOW_PREVIOUS_INPUT) +FfxUInt32 LoadSecondImagePackedLuma(FfxInt32x2 iPxPos) +{ + const FfxInt32 lumaTextureWidth = DisplaySize().x >> OpticalFlowPyramidLevel(); + const FfxInt32 lumaTextureHeight = DisplaySize().y >> OpticalFlowPyramidLevel(); + + FfxInt32x2 adjustedPos = FfxInt32x2( + ffxClamp(iPxPos.x, 0, lumaTextureWidth - 4), + ffxClamp(iPxPos.y, 0, lumaTextureHeight - 1) + ); + + FfxUInt32 luma0 = LoadOpticalFlowPreviousInput(adjustedPos + FfxInt32x2(0, 0)); + FfxUInt32 luma1 = LoadOpticalFlowPreviousInput(adjustedPos + FfxInt32x2(1, 0)); + FfxUInt32 luma2 = LoadOpticalFlowPreviousInput(adjustedPos + FfxInt32x2(2, 0)); + FfxUInt32 luma3 = LoadOpticalFlowPreviousInput(adjustedPos + FfxInt32x2(3, 0)); + + return GetPackedLuma(lumaTextureWidth, iPxPos.x, luma0, luma1, luma2, luma3); +} +#endif + + +void SPD_SetMipmap(FfxInt32x2 iPxPos, FfxUInt32 index, FfxFloat32 value) +{ + FfxUInt32x4 value4 = FfxUInt32x4(value, 0.0, 0.0, 0.0); + switch (index) + { + case 0: +#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_1 + imageStore(rw_optical_flow_input_level_1, iPxPos, value4); +#endif // #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_1 + break; + case 1: +#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_2 + imageStore(rw_optical_flow_input_level_2, iPxPos, value4); +#endif // #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_2 + break; + case 2: +#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_3 + imageStore(rw_optical_flow_input_level_3, iPxPos, value4); +#endif // #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_3 + break; + case 3: +#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_4 + imageStore(rw_optical_flow_input_level_4, iPxPos, value4); +#endif // #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_4 + break; + case 4: +#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_5 + imageStore(rw_optical_flow_input_level_5, iPxPos, value4); +#endif // #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_5 + break; + case 5: +#if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_6 + imageStore(rw_optical_flow_input_level_6, iPxPos, value4); +#endif // #if defined FFX_OPTICALFLOW_BIND_UAV_OPTICAL_FLOW_INPUT_LEVEL_6 + break; + } +} + +#endif // #if defined(FFX_GPU) + +#endif // FFX_OPTICALFLOW_CALLBACKS_HLSL_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/CMakeCompileParallelSortShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/CMakeCompileParallelSortShaders.txt new file mode 100644 index 00000000..28b54016 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/CMakeCompileParallelSortShaders.txt @@ -0,0 +1,54 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(PARALLELSORT_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(PARALLELSORT_PERMUTATION_ARGS + -DFFX_PARALLELSORT_OPTION_HAS_PAYLOAD={0,1}) + +set(PARALLELSORT_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/parallelsort") + +set(PARALLELSORT_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/parallelsort") + +if (NOT PARALLELSORT_SHADER_EXT) + set(PARALLELSORT_SHADER_EXT *) +endif() + +file(GLOB PARALLELSORT_SHADERS + "shaders/parallelsort/ffx_parallelsort_reduce_pass.${PARALLELSORT_SHADER_EXT}" + "shaders/parallelsort/ffx_parallelsort_scan_add_pass.${PARALLELSORT_SHADER_EXT}" + "shaders/parallelsort/ffx_parallelsort_scan_pass.${PARALLELSORT_SHADER_EXT}" + "shaders/parallelsort/ffx_parallelsort_scatter_pass.${PARALLELSORT_SHADER_EXT}" + "shaders/parallelsort/ffx_parallelsort_setup_indirect_args_pass.${PARALLELSORT_SHADER_EXT}" + "shaders/parallelsort/ffx_parallelsort_sum_pass.${PARALLELSORT_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${PARALLELSORT_BASE_ARGS}" "${PARALLELSORT_API_BASE_ARGS}" "${PARALLELSORT_PERMUTATION_ARGS}" "${PARALLELSORT_INCLUDE_ARGS}" + "${PARALLELSORT_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" PARALLELSORT_PERMUTATION_OUTPUTS) + +add_shader_output("${PARALLELSORT_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort.h new file mode 100644 index 00000000..d9ef41f6 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort.h @@ -0,0 +1,592 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup FfxGPUParallelSort FidelityFX Parallel Sort +/// FidelityFX Parallel Sort GPU documentation +/// +/// @ingroup FfxGPUEffects + +/// The number of bits we are sorting per pass. +/// Changing this value requires +/// internal changes in LDS distribution and count, +/// reduce, scan, and scatter passes +/// +/// @ingroup FfxGPUParallelSort +#define FFX_PARALLELSORT_SORT_BITS_PER_PASS 4 + +/// The number of bins used for the counting phase +/// of the algorithm. Changing this value requires +/// internal changes in LDS distribution and count, +/// reduce, scan, and scatter passes +/// +/// @ingroup FfxGPUParallelSort +#define FFX_PARALLELSORT_SORT_BIN_COUNT (1 << FFX_PARALLELSORT_SORT_BITS_PER_PASS) + +/// The number of elements dealt with per running +/// thread +/// +/// @ingroup FfxGPUParallelSort +#define FFX_PARALLELSORT_ELEMENTS_PER_THREAD 4 + +/// The number of threads to execute in parallel +/// for each dispatch group +/// +/// @ingroup FfxGPUParallelSort +#define FFX_PARALLELSORT_THREADGROUP_SIZE 128 + +/// The maximum number of thread groups to run +/// in parallel. Modifying this value can help +/// or hurt GPU occupancy, but is very hardware +/// class specific +/// +/// @ingroup FfxGPUParallelSort +#define FFX_PARALLELSORT_MAX_THREADGROUPS_TO_RUN 800 + +#if defined(FFX_CPU) + /// Constant buffer information needed for + /// the execution of each pass in parallel + /// sort. + /// + /// @ingroup FfxGPUParallelSort + typedef struct FfxParallelSortConstants + { + FfxUInt32 numKeys; ///< The number of keys to sort + FfxInt32 numBlocksPerThreadGroup; ///< How many blocks of keys each thread group needs to process + FfxUInt32 numThreadGroups; ///< How many thread groups are being run concurrently for sort + FfxUInt32 numThreadGroupsWithAdditionalBlocks; ///< How many thread groups need to process additional block data + FfxUInt32 numReduceThreadgroupPerBin; ///< How many thread groups are summed together for each reduced bin entry + FfxUInt32 numScanValues; ///< How many values to perform scan prefix (+ add) on + FfxUInt32 shift; ///< What bits are being sorted (4 bit increments) + FfxUInt32 padding; ///< Padding - unused + + } FfxParallelSortConstants; + + /// Call to calculate the required size for the scratch and reduce + /// scratch buffers used by parallel sort algorithm. + /// + /// @param [in] maxNumKeys The maximum number of keys the algorithm will be asked to sort through. + /// @param [out] scratchBufferSize The size of the scratch buffer that needs to be allocated. + /// @param [out] reduceScratchBufferSize The size of the reduce scratch buffer that needs to be allocated. + /// + /// @ingroup FfxGPUParallelSort + inline void ffxParallelSortCalculateScratchResourceSize(uint32_t maxNumKeys, uint32_t& scratchBufferSize, uint32_t& reduceScratchBufferSize) + { + uint32_t BlockSize = FFX_PARALLELSORT_ELEMENTS_PER_THREAD * FFX_PARALLELSORT_THREADGROUP_SIZE; + uint32_t NumBlocks = FFX_DIVIDE_ROUNDING_UP(maxNumKeys, BlockSize); + uint32_t NumReducedBlocks = FFX_DIVIDE_ROUNDING_UP(NumBlocks, BlockSize); + + scratchBufferSize = FFX_PARALLELSORT_SORT_BIN_COUNT * NumBlocks * sizeof(uint32_t); + reduceScratchBufferSize = FFX_PARALLELSORT_SORT_BIN_COUNT * NumReducedBlocks * sizeof(uint32_t); + } + + /// Call to setup the constant buffer data needed to bind to + /// the GPU for Parallel Sort execution (all passes). Note + /// that the implementor is left to manually modify the shift + /// (bit shift for each pass) value. + /// + /// @param [in] numKeys The number of keys the algorithm will be sorting through. + /// @param [in] maxThreadGroups The maximum number of thread groups to use in parallel. + /// @param [out] constantBuffer The FfxParallelSortConstants buffer to fill with information. + /// @param [out] numThreadGroupsToRun The number of thread groups (dispatch size) to run for this sort run. + /// @param [out] numReducedThreadGroupsToRun The number of reduce thread groups (dispatch size) to run for this sort run. + /// + /// @ingroup FfxGPUParallelSort + inline void ffxParallelSortSetConstantAndDispatchData(uint32_t numKeys, uint32_t maxThreadGroups, FfxParallelSortConstants& constantBuffer, uint32_t& numThreadGroupsToRun, uint32_t& numReducedThreadGroupsToRun) + { + constantBuffer.numKeys = numKeys; + + uint32_t BlockSize = FFX_PARALLELSORT_ELEMENTS_PER_THREAD * FFX_PARALLELSORT_THREADGROUP_SIZE; + uint32_t NumBlocks = FFX_DIVIDE_ROUNDING_UP(numKeys, BlockSize); + + // Figure out data distribution + numThreadGroupsToRun = maxThreadGroups; + uint32_t BlocksPerThreadGroup = (NumBlocks / numThreadGroupsToRun); + constantBuffer.numThreadGroupsWithAdditionalBlocks = NumBlocks % numThreadGroupsToRun; + + if (NumBlocks < numThreadGroupsToRun) + { + BlocksPerThreadGroup = 1; + numThreadGroupsToRun = NumBlocks; + constantBuffer.numThreadGroupsWithAdditionalBlocks = 0; + } + + constantBuffer.numThreadGroups = numThreadGroupsToRun; + constantBuffer.numBlocksPerThreadGroup = BlocksPerThreadGroup; + + // Calculate the number of thread groups to run for reduction (each thread group can process BlockSize number of entries) + numReducedThreadGroupsToRun = FFX_PARALLELSORT_SORT_BIN_COUNT * ((BlockSize > numThreadGroupsToRun) ? 1 : (numThreadGroupsToRun + BlockSize - 1) / BlockSize); + constantBuffer.numReduceThreadgroupPerBin = numReducedThreadGroupsToRun / FFX_PARALLELSORT_SORT_BIN_COUNT; + constantBuffer.numScanValues = numReducedThreadGroupsToRun; // The number of reduce thread groups becomes our scan count (as each thread group writes out 1 value that needs scan prefix) + } + + // We are using some optimizations to hide buffer load latency, so make sure anyone changing this define is made aware of that fact. + static_assert(FFX_PARALLELSORT_ELEMENTS_PER_THREAD == 4, "FFX_ParallelSort Shaders currently explicitly rely on FFX_PARALLELSORT_ELEMENTS_PER_THREAD being set to 4 in order to optimize buffer loads. Please adjust the optimization to factor in the new define value."); +#endif // #if defined(FFX_CPU) + +#if defined(FFX_GPU) + +#if defined(FFX_GLSL) + #extension GL_KHR_shader_subgroup_quad : require + #extension GL_ARB_shader_ballot : require + #extension GL_KHR_shader_subgroup_arithmetic : require +#endif + + FFX_GROUPSHARED FfxUInt32 gs_FFX_PARALLELSORT_Histogram[FFX_PARALLELSORT_THREADGROUP_SIZE * FFX_PARALLELSORT_SORT_BIN_COUNT]; + void ffxParallelSortCountUInt(FfxUInt32 localID, FfxUInt32 groupID, FfxUInt32 ShiftBit) + { + // Start by clearing our local counts in LDS + for (FfxInt32 i = 0; i < FFX_PARALLELSORT_SORT_BIN_COUNT; i++) + gs_FFX_PARALLELSORT_Histogram[(i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID] = 0; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Data is processed in blocks, and how many we process can changed based on how much data we are processing + // versus how many thread groups we are processing with + FfxInt32 BlockSize = FFX_PARALLELSORT_ELEMENTS_PER_THREAD * FFX_PARALLELSORT_THREADGROUP_SIZE; + + // Figure out this thread group's index into the block data (taking into account thread groups that need to do extra reads) + FfxUInt32 NumBlocksPerThreadGroup = FfxNumBlocksPerThreadGroup(); + FfxUInt32 NumThreadGroups = FfxNumThreadGroups(); + FfxUInt32 NumThreadGroupsWithAdditionalBlocks = FfxNumThreadGroupsWithAdditionalBlocks(); + FfxUInt32 NumKeys = FfxNumKeys(); + + FfxUInt32 ThreadgroupBlockStart = (BlockSize * NumBlocksPerThreadGroup * groupID); + FfxUInt32 NumBlocksToProcess = NumBlocksPerThreadGroup; + + if (groupID >= NumThreadGroups - NumThreadGroupsWithAdditionalBlocks) + { + ThreadgroupBlockStart += (groupID - (NumThreadGroups - NumThreadGroupsWithAdditionalBlocks)) * BlockSize; + NumBlocksToProcess++; + } + + // Get the block start index for this thread + FfxUInt32 BlockIndex = ThreadgroupBlockStart + localID; + + // Count value occurrence + for (FfxUInt32 BlockCount = 0; BlockCount < NumBlocksToProcess; BlockCount++, BlockIndex += BlockSize) + { + FfxUInt32 DataIndex = BlockIndex; + + // Pre-load the key values in order to hide some of the read latency + FfxUInt32 srcKeys[FFX_PARALLELSORT_ELEMENTS_PER_THREAD]; + srcKeys[0] = (DataIndex < NumKeys ? FfxLoadKey(DataIndex) : 0xffffffff); + srcKeys[1] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE < NumKeys ? FfxLoadKey(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE) : 0xffffffff); + srcKeys[2] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 2 < NumKeys ? FfxLoadKey(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 2) : 0xffffffff); + srcKeys[3] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 3 < NumKeys ? FfxLoadKey(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 3) : 0xffffffff); + + for (FfxUInt32 i = 0; i < FFX_PARALLELSORT_ELEMENTS_PER_THREAD; i++) + { + if (DataIndex < NumKeys) + { + FfxUInt32 localKey = (srcKeys[i] >> ShiftBit) & 0xf; + FFX_ATOMIC_ADD(gs_FFX_PARALLELSORT_Histogram[(localKey * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID], 1); + DataIndex += FFX_PARALLELSORT_THREADGROUP_SIZE; + } + } + } + + // Even though our LDS layout guarantees no collisions, our thread group size is greater than a wave + // so we need to make sure all thread groups are done counting before we start tallying up the results + FFX_GROUP_MEMORY_BARRIER; + + if (localID < FFX_PARALLELSORT_SORT_BIN_COUNT) + { + FfxUInt32 sum = 0; + for (FfxInt32 i = 0; i < FFX_PARALLELSORT_THREADGROUP_SIZE; i++) + { + sum += gs_FFX_PARALLELSORT_Histogram[localID * FFX_PARALLELSORT_THREADGROUP_SIZE + i]; + } + FfxStoreSum(localID * NumThreadGroups + groupID, sum); + } + } + + FFX_GROUPSHARED FfxUInt32 gs_FFX_PARALLELSORT_LDSSums[FFX_PARALLELSORT_THREADGROUP_SIZE]; + FfxUInt32 ffxParallelSortThreadgroupReduce(FfxUInt32 localSum, FfxUInt32 localID) + { + // Do wave local reduce +#if defined(FFX_HLSL) + FfxUInt32 waveReduced = WaveActiveSum(localSum); + + // First lane in a wave writes out wave reduction to LDS (this accounts for num waves per group greater than HW wave size) + // Note that some hardware with very small HW wave sizes (i.e. <= 8) may exhibit issues with this algorithm, and have not been tested. + FfxUInt32 waveID = localID / WaveGetLaneCount(); + if (WaveIsFirstLane()) + gs_FFX_PARALLELSORT_LDSSums[waveID] = waveReduced; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // First wave worth of threads sum up wave reductions + if (!waveID) + waveReduced = WaveActiveSum((localID < FFX_PARALLELSORT_THREADGROUP_SIZE / WaveGetLaneCount()) ? gs_FFX_PARALLELSORT_LDSSums[localID] : 0); + +#elif defined(FFX_GLSL) + + FfxUInt32 waveReduced = subgroupAdd(localSum); + + // First lane in a wave writes out wave reduction to LDS (this accounts for num waves per group greater than HW wave size) + // Note that some hardware with very small HW wave sizes (i.e. <= 8) may exhibit issues with this algorithm, and have not been tested. + FfxUInt32 waveID = localID / gl_SubGroupSizeARB; + if (subgroupElect()) + gs_FFX_PARALLELSORT_LDSSums[waveID] = waveReduced; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // First wave worth of threads sum up wave reductions + if (waveID == 0) + waveReduced = subgroupAdd((localID < FFX_PARALLELSORT_THREADGROUP_SIZE / gl_SubGroupSizeARB) ? gs_FFX_PARALLELSORT_LDSSums[localID] : 0); + +#endif // #if defined(FFX_HLSL) + + // Returned the reduced sum + return waveReduced; + } + + void ffxParallelSortReduceCount(FfxUInt32 localID, FfxUInt32 groupID) + { + FfxUInt32 NumReduceThreadgroupPerBin = FfxNumReduceThreadgroupPerBin(); + FfxUInt32 NumThreadGroups = FfxNumThreadGroups(); + + // Figure out what bin data we are reducing + FfxUInt32 BinID = groupID / NumReduceThreadgroupPerBin; + FfxUInt32 BinOffset = BinID * NumThreadGroups; + + // Get the base index for this thread group + FfxUInt32 BaseIndex = (groupID % NumReduceThreadgroupPerBin) * FFX_PARALLELSORT_ELEMENTS_PER_THREAD * FFX_PARALLELSORT_THREADGROUP_SIZE; + + // Calculate partial sums for entries this thread reads in + FfxUInt32 threadgroupSum = 0; + for (FfxUInt32 i = 0; i < FFX_PARALLELSORT_ELEMENTS_PER_THREAD; ++i) + { + FfxUInt32 DataIndex = BaseIndex + (i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID; + threadgroupSum += (DataIndex < NumThreadGroups) ? FfxLoadSum(BinOffset + DataIndex) : 0; + } + + // Reduce across the entirety of the thread group + threadgroupSum = ffxParallelSortThreadgroupReduce(threadgroupSum, localID); + + // First thread of the group writes out the reduced sum for the bin + if (localID == 0) + FfxStoreReduce(groupID, threadgroupSum); + + // What this will look like in the reduced table is: + // [ [bin0 ... bin0] [bin1 ... bin1] ... ] + } + + FfxUInt32 ffxParallelSortBlockScanPrefix(FfxUInt32 localSum, FfxUInt32 localID) + { +#if defined(FFX_HLSL) + + // Do wave local scan-prefix + FfxUInt32 wavePrefixed = WavePrefixSum(localSum); + + // Since we are dealing with thread group sizes greater than HW wave size, we need to account for what wave we are in. + FfxUInt32 waveID = localID / WaveGetLaneCount(); + FfxUInt32 laneID = WaveGetLaneIndex(); + + // Last element in a wave writes out partial sum to LDS + if (laneID == WaveGetLaneCount() - 1) + gs_FFX_PARALLELSORT_LDSSums[waveID] = wavePrefixed + localSum; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // First wave prefixes partial sums + if (!waveID) + gs_FFX_PARALLELSORT_LDSSums[localID] = WavePrefixSum(gs_FFX_PARALLELSORT_LDSSums[localID]); + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Add the partial sums back to each wave prefix + wavePrefixed += gs_FFX_PARALLELSORT_LDSSums[waveID]; + +#elif defined(FFX_GLSL) + + // Do wave local scan-prefix + FfxUInt32 wavePrefixed = subgroupExclusiveAdd(localSum); + + // Since we are dealing with thread group sizes greater than HW wave size, we need to account for what wave we are in. + FfxUInt32 waveID = localID / gl_SubGroupSizeARB; + FfxUInt32 laneID = gl_SubGroupInvocationARB; + + // Last element in a wave writes out partial sum to LDS + if (laneID == gl_SubGroupSizeARB - 1) + gs_FFX_PARALLELSORT_LDSSums[waveID] = wavePrefixed + localSum; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // First wave prefixes partial sums + if (waveID == 0) + gs_FFX_PARALLELSORT_LDSSums[localID] = subgroupExclusiveAdd(gs_FFX_PARALLELSORT_LDSSums[localID]); + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Add the partial sums back to each wave prefix + wavePrefixed += gs_FFX_PARALLELSORT_LDSSums[waveID]; + +#endif // #if defined(FFX_HLSL) + + return wavePrefixed; + } + + // This is to transform uncoalesced loads into coalesced loads and + // then scattered loads from LDS + FFX_GROUPSHARED FfxUInt32 gs_FFX_PARALLELSORT_LDS[FFX_PARALLELSORT_ELEMENTS_PER_THREAD][FFX_PARALLELSORT_THREADGROUP_SIZE]; + void ffxParallelSortScanPrefix(FfxUInt32 numValuesToScan, FfxUInt32 localID, FfxUInt32 groupID, FfxUInt32 BinOffset, FfxUInt32 BaseIndex, bool AddPartialSums) + { + // Perform coalesced loads into LDS + for (FfxUInt32 i = 0; i < FFX_PARALLELSORT_ELEMENTS_PER_THREAD; i++) + { + FfxUInt32 DataIndex = BaseIndex + (i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID; + + FfxUInt32 col = ((i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID) / FFX_PARALLELSORT_ELEMENTS_PER_THREAD; + FfxUInt32 row = ((i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID) % FFX_PARALLELSORT_ELEMENTS_PER_THREAD; + gs_FFX_PARALLELSORT_LDS[row][col] = (DataIndex < numValuesToScan) ? FfxLoadScanSource(BinOffset + DataIndex) : 0; + } + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + FfxUInt32 threadgroupSum = 0; + // Calculate the local scan-prefix for current thread + for (FfxUInt32 i = 0; i < FFX_PARALLELSORT_ELEMENTS_PER_THREAD; i++) + { + FfxUInt32 tmp = gs_FFX_PARALLELSORT_LDS[i][localID]; + gs_FFX_PARALLELSORT_LDS[i][localID] = threadgroupSum; + threadgroupSum += tmp; + } + + // Scan prefix partial sums + threadgroupSum = ffxParallelSortBlockScanPrefix(threadgroupSum, localID); + + // Add reduced partial sums if requested + FfxUInt32 partialSum = 0; + if (AddPartialSums) + { + // Partial sum additions are a little special as they are tailored to the optimal number of + // thread groups we ran in the beginning, so need to take that into account + partialSum = FfxLoadScanScratch(groupID); + } + + // Add the block scanned-prefixes back in + for (FfxUInt32 i = 0; i < FFX_PARALLELSORT_ELEMENTS_PER_THREAD; i++) + gs_FFX_PARALLELSORT_LDS[i][localID] += threadgroupSum; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Perform coalesced writes to scan dst + for (FfxUInt32 i = 0; i < FFX_PARALLELSORT_ELEMENTS_PER_THREAD; i++) + { + FfxUInt32 DataIndex = BaseIndex + (i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID; + + FfxUInt32 col = ((i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID) / FFX_PARALLELSORT_ELEMENTS_PER_THREAD; + FfxUInt32 row = ((i * FFX_PARALLELSORT_THREADGROUP_SIZE) + localID) % FFX_PARALLELSORT_ELEMENTS_PER_THREAD; + + if (DataIndex < numValuesToScan) + FfxStoreScanDest(BinOffset + DataIndex, gs_FFX_PARALLELSORT_LDS[row][col] + partialSum); + } + } + + // Offset cache to avoid loading the offsets all the time + FFX_GROUPSHARED FfxUInt32 gs_FFX_PARALLELSORT_BinOffsetCache[FFX_PARALLELSORT_THREADGROUP_SIZE]; + // Local histogram for offset calculations + FFX_GROUPSHARED FfxUInt32 gs_FFX_PARALLELSORT_LocalHistogram[FFX_PARALLELSORT_SORT_BIN_COUNT]; + // Scratch area for algorithm + FFX_GROUPSHARED FfxUInt32 gs_FFX_PARALLELSORT_LDSScratch[FFX_PARALLELSORT_THREADGROUP_SIZE]; + + void ffxParallelSortScatterUInt(FfxUInt32 localID, FfxUInt32 groupID, FfxUInt32 ShiftBit) + { + FfxUInt32 NumBlocksPerThreadGroup = FfxNumBlocksPerThreadGroup(); + FfxUInt32 NumThreadGroups = FfxNumThreadGroups(); + FfxUInt32 NumThreadGroupsWithAdditionalBlocks = FfxNumThreadGroupsWithAdditionalBlocks(); + FfxUInt32 NumKeys = FfxNumKeys(); + + // Load the sort bin threadgroup offsets into LDS for faster referencing + if (localID < FFX_PARALLELSORT_SORT_BIN_COUNT) + gs_FFX_PARALLELSORT_BinOffsetCache[localID] = FfxLoadSum(localID * NumThreadGroups + groupID); + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Data is processed in blocks, and how many we process can changed based on how much data we are processing + // versus how many thread groups we are processing with + int BlockSize = FFX_PARALLELSORT_ELEMENTS_PER_THREAD * FFX_PARALLELSORT_THREADGROUP_SIZE; + + // Figure out this thread group's index into the block data (taking into account thread groups that need to do extra reads) + FfxUInt32 ThreadgroupBlockStart = (BlockSize * NumBlocksPerThreadGroup * groupID); + FfxUInt32 NumBlocksToProcess = NumBlocksPerThreadGroup; + + if (groupID >= NumThreadGroups - NumThreadGroupsWithAdditionalBlocks) + { + ThreadgroupBlockStart += (groupID - (NumThreadGroups - NumThreadGroupsWithAdditionalBlocks)) * BlockSize; + NumBlocksToProcess++; + } + + // Get the block start index for this thread + FfxUInt32 BlockIndex = ThreadgroupBlockStart + localID; + + // Count value occurences + FfxUInt32 newCount; + for (int BlockCount = 0; BlockCount < NumBlocksToProcess; BlockCount++, BlockIndex += BlockSize) + { + FfxUInt32 DataIndex = BlockIndex; + + // Pre-load the key values in order to hide some of the read latency + FfxUInt32 srcKeys[FFX_PARALLELSORT_ELEMENTS_PER_THREAD]; + srcKeys[0] = (DataIndex < NumKeys ? FfxLoadKey(DataIndex) : 0xffffffff); + srcKeys[1] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE < NumKeys ? FfxLoadKey(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE) : 0xffffffff); + srcKeys[2] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 2 < NumKeys ? FfxLoadKey(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 2) : 0xffffffff); + srcKeys[3] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 3 < NumKeys ? FfxLoadKey(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 3) : 0xffffffff); + + +#ifdef FFX_PARALLELSORT_COPY_VALUE + FfxUInt32 srcValues[FFX_PARALLELSORT_ELEMENTS_PER_THREAD]; + srcValues[0] = (DataIndex < NumKeys ? FfxLoadPayload(DataIndex) : 0); + srcValues[1] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE < NumKeys ? FfxLoadPayload(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE) : 0); + srcValues[2] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 2 < NumKeys ? FfxLoadPayload(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 2) : 0); + srcValues[3] = (DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 3 < NumKeys ? FfxLoadPayload(DataIndex + FFX_PARALLELSORT_THREADGROUP_SIZE * 3) : 0); + +#endif // FFX_PARALLELSORT_COPY_VALUE + + for (int i = 0; i < FFX_PARALLELSORT_ELEMENTS_PER_THREAD; i++) + { + // Clear the local histogram + if (localID < FFX_PARALLELSORT_SORT_BIN_COUNT) + gs_FFX_PARALLELSORT_LocalHistogram[localID] = 0; + + FfxUInt32 localKey = srcKeys[i]; +#ifdef FFX_PARALLELSORT_COPY_VALUE + FfxUInt32 localValue = srcValues[i]; +#endif // FFX_PARALLELSORT_COPY_VALUE + + // Sort the keys locally in LDS + for (FfxUInt32 bitShift = 0; bitShift < FFX_PARALLELSORT_SORT_BITS_PER_PASS; bitShift += 2) + { + // Figure out the keyIndex + FfxUInt32 keyIndex = (localKey >> ShiftBit) & 0xf; + FfxUInt32 bitKey = (keyIndex >> bitShift) & 0x3; + + // Create a packed histogram + FfxUInt32 packedHistogram = 1 << (bitKey * 8); + + // Sum up all the packed keys (generates counted offsets up to current thread group) + FfxUInt32 localSum = ffxParallelSortBlockScanPrefix(packedHistogram, localID); + + // Last thread stores the updated histogram counts for the thread group + // Scratch = 0xsum3|sum2|sum1|sum0 for thread group + if (localID == (FFX_PARALLELSORT_THREADGROUP_SIZE - 1)) + gs_FFX_PARALLELSORT_LDSScratch[0] = localSum + packedHistogram; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Load the sums value for the thread group + packedHistogram = gs_FFX_PARALLELSORT_LDSScratch[0]; + + // Add prefix offsets for all 4 bit "keys" (packedHistogram = 0xsum2_1_0|sum1_0|sum0|0) + packedHistogram = (packedHistogram << 8) + (packedHistogram << 16) + (packedHistogram << 24); + + // Calculate the proper offset for this thread's value + localSum += packedHistogram; + + // Calculate target offset + FfxUInt32 keyOffset = (localSum >> (bitKey * 8)) & 0xff; + + // Re-arrange the keys (store, sync, load) + gs_FFX_PARALLELSORT_LDSSums[keyOffset] = localKey; + FFX_GROUP_MEMORY_BARRIER; + localKey = gs_FFX_PARALLELSORT_LDSSums[localID]; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + +#ifdef FFX_PARALLELSORT_COPY_VALUE + // Re-arrange the values if we have them (store, sync, load) + gs_FFX_PARALLELSORT_LDSSums[keyOffset] = localValue; + FFX_GROUP_MEMORY_BARRIER; + localValue = gs_FFX_PARALLELSORT_LDSSums[localID]; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; +#endif // FFX_PARALLELSORT_COPY_VALUE + } + + // Need to recalculate the keyIndex on this thread now that values have been copied around the thread group + FfxUInt32 keyIndex = (localKey >> ShiftBit) & 0xf; + + // Reconstruct histogram + FFX_ATOMIC_ADD(gs_FFX_PARALLELSORT_LocalHistogram[keyIndex], 1); + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Prefix histogram +#if defined(FFX_HLSL) + FfxUInt32 histogramPrefixSum = WavePrefixSum(localID < FFX_PARALLELSORT_SORT_BIN_COUNT ? gs_FFX_PARALLELSORT_LocalHistogram[localID] : 0); +#elif defined(FFX_GLSL) + FfxUInt32 histogramPrefixSum = subgroupExclusiveAdd(localID < FFX_PARALLELSORT_SORT_BIN_COUNT ? gs_FFX_PARALLELSORT_LocalHistogram[localID] : 0); +#endif // #if defined(FFX_HLSL) + + // Broadcast prefix-sum via LDS + if (localID < FFX_PARALLELSORT_SORT_BIN_COUNT) + gs_FFX_PARALLELSORT_LDSScratch[localID] = histogramPrefixSum; + + // Get the global offset for this key out of the cache + FfxUInt32 globalOffset = gs_FFX_PARALLELSORT_BinOffsetCache[keyIndex]; + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Get the local offset (at this point the keys are all in increasing order from 0 -> num bins in localID 0 -> thread group size) + FfxUInt32 localOffset = localID - gs_FFX_PARALLELSORT_LDSScratch[keyIndex]; + + // Write to destination + FfxUInt32 totalOffset = globalOffset + localOffset; + + if (totalOffset < NumKeys) + { + FfxStoreKey(totalOffset, localKey); + +#ifdef FFX_PARALLELSORT_COPY_VALUE + FfxStorePayload(totalOffset, localValue); +#endif // FFX_PARALLELSORT_COPY_VALUE + } + + // Wait for everyone to catch up + FFX_GROUP_MEMORY_BARRIER; + + // Update the cached histogram for the next set of entries + if (localID < FFX_PARALLELSORT_SORT_BIN_COUNT) + gs_FFX_PARALLELSORT_BinOffsetCache[localID] += gs_FFX_PARALLELSORT_LocalHistogram[localID]; + + DataIndex += FFX_PARALLELSORT_THREADGROUP_SIZE; // Increase the data offset by thread group size + } + } + } + +#endif // defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_callbacks_glsl.h new file mode 100644 index 00000000..56d7e89e --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_callbacks_glsl.h @@ -0,0 +1,245 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_parallelsort_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT, std140) uniform cbParallelSort_t + { + FfxUInt32 numKeys; + FfxInt32 numBlocksPerThreadGroup; + FfxUInt32 numThreadGroups; + FfxUInt32 numThreadGroupsWithAdditionalBlocks; + FfxUInt32 numReduceThreadgroupPerBin; + FfxUInt32 numScanValues; + FfxUInt32 shiftBit; + FfxUInt32 padding; + } cbParallelSort; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + +FfxUInt32 NumKeys() +{ +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + return cbParallelSort.numKeys; +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) +} + +FfxInt32 NumBlocksPerThreadGroup() +{ +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + return cbParallelSort.numBlocksPerThreadGroup; +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) +} + +FfxUInt32 NumThreadGroups() +{ +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + return cbParallelSort.numThreadGroups; +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) +} + +FfxUInt32 NumThreadGroupsWithAdditionalBlocks() +{ +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + return cbParallelSort.numThreadGroupsWithAdditionalBlocks; +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) +} + +FfxUInt32 NumReduceThreadgroupPerBin() +{ +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + return cbParallelSort.numReduceThreadgroupPerBin; +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) +} + +FfxUInt32 NumScanValues() +{ +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + return cbParallelSort.numScanValues; +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) +} + +FfxUInt32 ShiftBit() +{ +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + return cbParallelSort.shiftBit; +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) +} + + +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS, std430) coherent buffer ParallelSortSrcKeys_t { uint source_keys[]; } rw_source_keys; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_DEST_KEYS, std430) coherent buffer ParallelSortDstKeys_t { uint dest_keys[]; } rw_dest_keys; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS, std430) coherent buffer ParallelSortSrcPayload_t { uint source_payloads[]; } rw_source_payloads; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS, std430) coherent buffer ParallelSortDstPayload_t { uint dest_payloads[]; } rw_dest_payloads; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_SUM_TABLE, std430) coherent buffer ParallelSortSumTable_t { uint sum_table[]; } rw_sum_table; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE, std430) coherent buffer ParallelSortReduceTable_t { uint reduce_table[]; } rw_reduce_table; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE, std430) coherent buffer ParallelSortScanSrc_t { uint scan_source[]; } rw_scan_source; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_SCAN_DEST, std430) coherent buffer ParallelSortScanDst_t { uint scan_dest[]; } rw_scan_dest; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH, std430) coherent buffer ParallelSortScanScratch_t { uint scan_scratch[]; } rw_scan_scratch; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + +// UAV declarations +#if defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS, std430) coherent buffer ParallelSortCountScatterArgs_t { uint count_scatter_args[]; } rw_count_scatter_args; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + layout(set = 0, binding = FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS, std430) coherent buffer ParallelSortReduceScanArgs_t { uint reduce_scan_args[]; } rw_reduce_scan_args; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + FfxUInt32 LoadSourceKey(FfxUInt32 index) + { + return rw_source_keys.source_keys[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + void StoreDestKey(FfxUInt32 index, FfxUInt32 value) + { + rw_dest_keys.dest_keys[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + FfxUInt32 LoadSourcePayload(FfxUInt32 index) + { + return rw_source_payloads.source_payloads[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + void StoreDestPayload(FfxUInt32 index, FfxUInt32 value) + { + rw_dest_payloads.dest_payloads[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + FfxUInt32 LoadSumTable(FfxUInt32 index) + { + return rw_sum_table.sum_table[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + void StoreSumTable(FfxUInt32 index, FfxUInt32 value) + { + rw_sum_table.sum_table[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + void StoreReduceTable(FfxUInt32 index, FfxUInt32 value) + { + rw_reduce_table.reduce_table[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + FfxUInt32 LoadScanSource(FfxUInt32 index) + { + return rw_scan_source.scan_source[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + void StoreScanDest(FfxUInt32 index, FfxUInt32 value) + { + rw_scan_dest.scan_dest[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + FfxUInt32 LoadScanScratch(FfxUInt32 index) + { + return rw_scan_scratch.scan_scratch[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + +#if defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + void StoreCountScatterArgs(FfxUInt32 x, FfxUInt32 y, FfxUInt32 z) + { + rw_count_scatter_args.count_scatter_args[0] = x; + rw_count_scatter_args.count_scatter_args[1] = y; + rw_count_scatter_args.count_scatter_args[2] = z; + } +#endif // defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + void StoreReduceScanArgs(FfxUInt32 x, FfxUInt32 y, FfxUInt32 z) + { + rw_reduce_scan_args.reduce_scan_args[0] = x; + rw_reduce_scan_args.reduce_scan_args[1] = y; + rw_reduce_scan_args.reduce_scan_args[2] = z; + } +#endif // defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_callbacks_hlsl.h new file mode 100644 index 00000000..35dd4af0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_callbacks_hlsl.h @@ -0,0 +1,250 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_parallelsort_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define FFX_DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define FFX_DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_PARALLELSORT_DECLARE_UAV(regIndex) register(FFX_DECLARE_UAV_REGISTER(regIndex)) +#define FFX_PARALLELSORT_DECLARE_CB(regIndex) register(FFX_DECLARE_CB_REGISTER(regIndex)) + +#if defined(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + cbuffer cbParallelSort : FFX_PARALLELSORT_DECLARE_CB(FFX_PARALLELSORT_BIND_CB_PARALLEL_SORT) + { + FfxUInt32 numKeys; + FfxInt32 numBlocksPerThreadGroup; + FfxUInt32 numThreadGroups; + FfxUInt32 numThreadGroupsWithAdditionalBlocks; + FfxUInt32 numReduceThreadgroupPerBin; + FfxUInt32 numScanValues; + FfxUInt32 shift; + FfxUInt32 padding; + }; +#else + #define numKeys 0 + #define numBlocksPerThreadGroup 0 + #define numThreadGroups 0 + #define numThreadGroupsWithAdditionalBlocks 0 + #define numReduceThreadgroupPerBin 0 + #define numScanValues 0 + #define shift 0 + #define padding 0 +#endif + +#define FFX_PARALLELSORT_CONSTANT_BUFFER_1_SIZE 8 // Number of 32-bit float/uint values in the constant buffer. + +#define FFX_PARALLELSORT_ROOTSIG_STRINGIFY(p) FFX_PARALLELSORT_ROOTSIG_STR(p) +#define FFX_PARALLELSORT_ROOTSIG_STR(p) #p +#define FFX_PARALLELSORT_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_PARALLELSORT_ROOTSIG_STRINGIFY(FFX_PARALLELSORT_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0)")] + +#if defined(FFX_PARALLELSORT_EMBED_ROOTSIG) +#define FFX_PARALLELSORT_EMBED_ROOTSIG_CONTENT FFX_PARALLELSORT_ROOTSIG +#else +#define FFX_PARALLELSORT_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_PARALLELSORT_EMBED_ROOTSIG + +FfxUInt32 NumKeys() +{ + return numKeys; +} + +FfxInt32 NumBlocksPerThreadGroup() +{ + return numBlocksPerThreadGroup; +} + +FfxUInt32 NumThreadGroups() +{ + return numThreadGroups; +} + +FfxUInt32 NumThreadGroupsWithAdditionalBlocks() +{ + return numThreadGroupsWithAdditionalBlocks; +} + +FfxUInt32 NumReduceThreadgroupPerBin() +{ + return numReduceThreadgroupPerBin; +} + +FfxUInt32 NumScanValues() +{ + return numScanValues; +} + +FfxUInt32 ShiftBit() +{ + return shift; +} + + #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + RWStructuredBuffer rw_source_keys : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + + #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + RWStructuredBuffer rw_dest_keys : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + + #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + RWStructuredBuffer rw_source_payloads : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + + #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + RWStructuredBuffer rw_dest_payloads : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + + #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + RWStructuredBuffer rw_sum_table : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + + #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + RWStructuredBuffer rw_reduce_table : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + + #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + RWStructuredBuffer rw_scan_source : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + + #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + RWStructuredBuffer rw_scan_dest : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + + #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + RWStructuredBuffer rw_scan_scratch : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + + // UAV declarations + #if defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + RWStructuredBuffer rw_count_scatter_args : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + + #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + RWStructuredBuffer rw_reduce_scan_args : FFX_PARALLELSORT_DECLARE_UAV(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS); + #endif // #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + FfxUInt32 LoadSourceKey(FfxUInt32 index) + { + return rw_source_keys[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + void StoreDestKey(FfxUInt32 index, FfxUInt32 value) + { + rw_dest_keys[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + FfxUInt32 LoadSourcePayload(FfxUInt32 index) + { + return rw_source_payloads[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + void StoreDestPayload(FfxUInt32 index, FfxUInt32 value) + { + rw_dest_payloads[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + FfxUInt32 LoadSumTable(FfxUInt32 index) + { + return rw_sum_table[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + void StoreSumTable(FfxUInt32 index, FfxUInt32 value) + { + rw_sum_table[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + void StoreReduceTable(FfxUInt32 index, FfxUInt32 value) + { + rw_reduce_table[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + FfxUInt32 LoadScanSource(FfxUInt32 index) + { + return rw_scan_source[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + void StoreScanDest(FfxUInt32 index, FfxUInt32 value) + { + rw_scan_dest[index] = value; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + FfxUInt32 LoadScanScratch(FfxUInt32 index) + { + return rw_scan_scratch[index]; + } +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + +#if defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + void StoreCountScatterArgs(FfxUInt32 x, FfxUInt32 y, FfxUInt32 z) + { + rw_count_scatter_args[0] = x; + rw_count_scatter_args[1] = y; + rw_count_scatter_args[2] = z; + } +#endif // defined(FFX_PARALLELSORT_BIND_UAV_COUNT_SCATTER_ARGS) + +#if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + void StoreReduceScanArgs(FfxUInt32 x, FfxUInt32 y, FfxUInt32 z) + { + rw_reduce_scan_args[0] = x; + rw_reduce_scan_args[1] = y; + rw_reduce_scan_args[2] = z; + } +#endif // defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_SCAN_ARGS) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_common.h new file mode 100644 index 00000000..20569a6e --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_common.h @@ -0,0 +1,126 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +FfxUInt32 FfxNumBlocksPerThreadGroup() +{ + return NumBlocksPerThreadGroup(); +} + +FfxUInt32 FfxNumThreadGroups() +{ + return NumThreadGroups(); +} + +FfxUInt32 FfxNumThreadGroupsWithAdditionalBlocks() +{ + return NumThreadGroupsWithAdditionalBlocks(); +} + +FfxUInt32 FfxNumReduceThreadgroupPerBin() +{ + return NumReduceThreadgroupPerBin(); +} + +FfxUInt32 FfxNumKeys() +{ + return NumKeys(); +} + +FfxUInt32 FfxLoadKey(FfxUInt32 index) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) + return LoadSourceKey(index); +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_KEYS) +} + +void FfxStoreKey(FfxUInt32 index, FfxUInt32 value) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) + StoreDestKey(index, value); +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_KEYS) +} + +FfxUInt32 FfxLoadPayload(FfxUInt32 index) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) + return LoadSourcePayload(index); +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SOURCE_PAYLOADS) +} + +void FfxStorePayload(FfxUInt32 index, FfxUInt32 value) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) + StoreDestPayload(index, value); +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_DEST_PAYLOADS) +} + +FfxUInt32 FfxLoadSum(FfxUInt32 index) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + return LoadSumTable(index); +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) +} + +void FfxStoreSum(FfxUInt32 index, FfxUInt32 value) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) + StoreSumTable(index, value); +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SUM_TABLE) +} + +void FfxStoreReduce(FfxUInt32 index, FfxUInt32 value) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) + StoreReduceTable(index, value); +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_REDUCE_TABLE) +} + +FfxUInt32 FfxLoadScanSource(FfxUInt32 index) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) + return LoadScanSource(index); +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SOURCE) +} + +void FfxStoreScanDest(FfxUInt32 index, FfxUInt32 value) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) + StoreScanDest(index, value); +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_DEST) +} + +FfxUInt32 FfxLoadScanScratch(FfxUInt32 index) +{ +#if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) + return LoadScanScratch(index); +#else + return 0; +#endif // #if defined(FFX_PARALLELSORT_BIND_UAV_SCAN_SCRATCH) +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_reduce.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_reduce.h new file mode 100644 index 00000000..29904cad --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_reduce.h @@ -0,0 +1,34 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#if FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + #define FFX_PARALLELSORT_COPY_VALUE 1 +#endif // FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + +#include "parallelsort/ffx_parallelsort.h" + +void FfxParallelSortReduce(FfxUInt32 LocalID, FfxUInt32 GroupID) +{ + ffxParallelSortReduceCount(LocalID, GroupID); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_resources.h new file mode 100644 index 00000000..e319a563 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_resources.h @@ -0,0 +1,57 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_PARALLELSORT_RESOURCES_H +#define FFX_PARALLELSORT_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) + +// Physical resources +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_INPUT_KEY_BUFFER 1 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_INPUT_PAYLOAD_BUFFER 2 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_KEY_SCRATCH_BUFFER 3 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_PAYLOAD_SCRATCH_BUFFER 4 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_SCRATCH_BUFFER 5 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_REDUCED_SCRATCH_BUFFER 6 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_INDIRECT_COUNT_SCATTER_ARGS_BUFFER 7 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_INDIRECT_REDUCE_SCAN_ARGS_BUFER 8 + +// Binding resources +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_SUM_TABLE 10 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_REDUCE_TABLE 11 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_SCAN_SOURCE 12 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_SCAN_DST 13 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_SCAN_SCRATCH 14 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_KEY_SRC 15 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_KEY_DST 16 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_PAYLOAD_SRC 17 +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_PAYLOAD_DST 18 + +#define FFX_PARALLELSORT_RESOURCE_IDENTIFIER_COUNT 19 + +// CBV resource definitions +#define FFX_PARALLELSORT_CONSTANTBUFFER_IDENTIFIER_PARALLEL_SORT 0 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif // FFX_PARALLELSORT_RESOURCES_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scan.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scan.h new file mode 100644 index 00000000..124eecd5 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scan.h @@ -0,0 +1,35 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#if FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + #define FFX_PARALLELSORT_COPY_VALUE 1 +#endif // FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + +#include "parallelsort/ffx_parallelsort.h" + +void FfxParallelSortScan(FfxUInt32 LocalID, FfxUInt32 GroupID) +{ + FfxUInt32 BaseIndex = FFX_PARALLELSORT_ELEMENTS_PER_THREAD * FFX_PARALLELSORT_THREADGROUP_SIZE * GroupID; + ffxParallelSortScanPrefix(NumScanValues(), LocalID, GroupID, 0, BaseIndex, false); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scan_add.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scan_add.h new file mode 100644 index 00000000..dd248e5a --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scan_add.h @@ -0,0 +1,44 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#if FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + #define FFX_PARALLELSORT_COPY_VALUE 1 +#endif // FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + +#include "parallelsort/ffx_parallelsort.h" + +void FfxParallelSortScanAdd(FfxUInt32 LocalID, FfxUInt32 GroupID) +{ + // When doing adds, we need to access data differently because reduce + // has a more specialized access pattern to match optimized count + // Access needs to be done similarly to reduce + // Figure out what bin data we are reducing + FfxUInt32 BinID = GroupID / NumReduceThreadgroupPerBin(); + FfxUInt32 BinOffset = BinID * NumThreadGroups(); + + // Get the base index for this thread group + FfxUInt32 BaseIndex = (GroupID % NumReduceThreadgroupPerBin()) * FFX_PARALLELSORT_ELEMENTS_PER_THREAD * FFX_PARALLELSORT_THREADGROUP_SIZE; + + ffxParallelSortScanPrefix(NumThreadGroups(), LocalID, GroupID, BinOffset, BaseIndex, true); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scatter.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scatter.h new file mode 100644 index 00000000..71c7eb9c --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_scatter.h @@ -0,0 +1,34 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#if FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + #define FFX_PARALLELSORT_COPY_VALUE 1 +#endif // FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + +#include "parallelsort/ffx_parallelsort.h" + +void FfxParallelSortScatter(FfxUInt32 LocalID, FfxUInt32 GroupID) +{ + ffxParallelSortScatterUInt(LocalID, GroupID, ShiftBit()); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_setup_indirect_args.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_setup_indirect_args.h new file mode 100644 index 00000000..dca76ad2 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_setup_indirect_args.h @@ -0,0 +1,35 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#if FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + #define FFX_PARALLELSORT_COPY_VALUE 1 +#endif // FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + +void FfxParallelSortSetupIndirectArgs(FfxUInt32 LocalThreadId) +{ + // Just copy the appropriate data from the constant buffer to control number of jobs to dispatch + // for count, reduce, scan, and scatter passes + StoreCountScatterArgs(NumThreadGroups(), 1, 1); + StoreReduceScanArgs(NumScanValues(), 1, 1); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_sum.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_sum.h new file mode 100644 index 00000000..80a83b5d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/parallelsort/ffx_parallelsort_sum.h @@ -0,0 +1,34 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#if FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + #define FFX_PARALLELSORT_COPY_VALUE 1 +#endif // FFX_PARALLELSORT_OPTION_HAS_PAYLOAD + +#include "parallelsort/ffx_parallelsort.h" + +void FfxParallelSortCount(FfxUInt32 LocalID, FfxUInt32 GroupID) +{ + ffxParallelSortCountUInt(LocalID, GroupID, ShiftBit()); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/CMakeCompileSPDShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/CMakeCompileSPDShaders.txt new file mode 100644 index 00000000..daeaad4f --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/CMakeCompileSPDShaders.txt @@ -0,0 +1,47 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(SPD_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(SPD_PERMUTATION_ARGS + -DFFX_SPD_OPTION_LINEAR_SAMPLE={0,1} + -DFFX_SPD_OPTION_WAVE_INTEROP_LDS={0,1} + -DFFX_SPD_OPTION_DOWNSAMPLE_FILTER={0,1,2}) + +set(SPD_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/spd") + +if (NOT SPD_SHADER_EXT) + set(SPD_SHADER_EXT *) +endif() + +file(GLOB SPD_SHADERS + "shaders/spd/ffx_spd_downsample_pass.${SPD_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${SPD_BASE_ARGS}" "${SPD_API_BASE_ARGS}" "${SPD_PERMUTATION_ARGS}" "${SPD_INCLUDE_ARGS}" + "${SPD_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" SPD_PERMUTATION_OUTPUTS) + +add_shader_output("${SPD_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_callbacks_glsl.h new file mode 100644 index 00000000..55244eb4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_callbacks_glsl.h @@ -0,0 +1,181 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_spd_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(FFX_SPD_BIND_CB_SPD) + layout (set = 0, binding = FFX_SPD_BIND_CB_SPD, std140) uniform cbFSR1_t + { + FfxUInt32 mips; + FfxUInt32 numWorkGroups; + FfxUInt32x2 workGroupOffset; + FfxFloat32x2 invInputSize; // Only used for linear sampling mode + FfxFloat32x2 padding; + } cbFSR1; +#endif + + +FfxUInt32 Mips() +{ + return cbFSR1.mips; +} + +FfxUInt32 NumWorkGroups() +{ + return cbFSR1.numWorkGroups; +} + +FfxUInt32x2 WorkGroupOffset() +{ + return cbFSR1.workGroupOffset; +} + +FfxFloat32x2 InvInputSize() +{ + return cbFSR1.invInputSize; +} + +layout (set = 0, binding = 1000) uniform sampler s_LinearClamp; + +// SRVs +#if defined FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC + layout (set = 0, binding = FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) uniform texture2DArray r_input_downsample_src; +#endif + +// UAV declarations +#if defined FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC + layout (set = 0, binding = FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC, std430) coherent buffer rw_internal_global_atomic_t + { + FfxUInt32 counter[6]; + } rw_internal_global_atomic; +#endif + +#if defined FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP + layout (set = 0, binding = FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP, rgba32f) coherent uniform image2DArray rw_input_downsample_src_mid_mip; +#endif + +#if defined FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS + layout (set = 0, binding = FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS, rgba32f) uniform image2DArray rw_input_downsample_src_mips[SPD_MAX_MIP_LEVELS+1]; +#endif + +#if FFX_HALF + +#if defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + FfxFloat16x4 SampleSrcImageH(FfxFloat32x2 uv, FfxUInt32 slice) + { + FfxFloat32x2 textureCoord = FfxFloat32x2(uv) * InvInputSize() + InvInputSize(); + FfxFloat32x4 result = textureLod(sampler2DArray(r_input_downsample_src, s_LinearClamp), FfxFloat32x3(textureCoord, slice), 0); + return FfxFloat16x4(ffxSrgbFromLinear(result.x), ffxSrgbFromLinear(result.y), ffxSrgbFromLinear(result.z), result.w); + } +#endif // defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + FfxFloat16x4 LoadSrcImageH(FfxFloat32x2 uv, FfxUInt32 slice) + { + return FfxFloat16x4(imageLoad(rw_input_downsample_src_mips[0], FfxInt32x3(uv, slice))); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + void StoreSrcMipH(FfxFloat16x4 value, FfxInt32x2 uv, FfxUInt32 slice, FfxUInt32 mip) + { + imageStore(rw_input_downsample_src_mips[mip], FfxInt32x3(uv, slice), FfxFloat32x4(value)); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + FfxFloat16x4 LoadMidMipH(FfxInt32x2 uv, FfxUInt32 slice) + { + return FfxFloat16x4(imageLoad(rw_input_downsample_src_mid_mip, FfxInt32x3(uv, slice))); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + void StoreMidMipH(FfxFloat16x4 value, FfxInt32x2 uv, FfxUInt32 slice) + { + imageStore(rw_input_downsample_src_mid_mip, FfxInt32x3(uv, slice), FfxFloat32x4(value));\ + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#else // FFX_HALF + +#if defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + FfxFloat32x4 SampleSrcImage(FfxInt32x2 uv, FfxUInt32 slice) + { + FfxFloat32x2 textureCoord = FfxFloat32x2(uv) * InvInputSize() + InvInputSize(); + FfxFloat32x4 result = textureLod(sampler2DArray(r_input_downsample_src, s_LinearClamp), FfxFloat32x3(textureCoord, slice), 0); + return FfxFloat32x4(ffxSrgbFromLinear(result.x), ffxSrgbFromLinear(result.y), ffxSrgbFromLinear(result.z), result.w); + } +#endif // defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + FfxFloat32x4 LoadSrcImage(FfxInt32x2 uv, FfxUInt32 slice) + { + return imageLoad(rw_input_downsample_src_mips[0], FfxInt32x3(uv, slice)); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + void StoreSrcMip(FfxFloat32x4 value, FfxInt32x2 uv, FfxUInt32 slice, FfxUInt32 mip) + { + imageStore(rw_input_downsample_src_mips[mip], FfxInt32x3(uv, slice), value); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + FfxFloat32x4 LoadMidMip(FfxInt32x2 uv, FfxUInt32 slice) + { + return imageLoad(rw_input_downsample_src_mid_mip, FfxInt32x3(uv, slice)); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + void StoreMidMip(FfxFloat32x4 value, FfxInt32x2 uv, FfxUInt32 slice) + { + imageStore(rw_input_downsample_src_mid_mip, FfxInt32x3(uv, slice), value); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#endif // FFX_HALF + +#if defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) +void IncreaseAtomicCounter(FFX_PARAMETER_IN FfxUInt32 slice, FFX_PARAMETER_INOUT FfxUInt32 counter) +{ + counter = atomicAdd(rw_internal_global_atomic.counter[slice], 1); +} +#endif // defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) + +#if defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) +void ResetAtomicCounter(FFX_PARAMETER_IN FfxUInt32 slice) +{ + rw_internal_global_atomic.counter[slice] = 0; +} +#endif // defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_callbacks_hlsl.h new file mode 100644 index 00000000..d86f66ff --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_callbacks_hlsl.h @@ -0,0 +1,218 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_spd_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define FFX_DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define FFX_DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define FFX_DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_SPD_DECLARE_SRV(regIndex) register(FFX_DECLARE_SRV_REGISTER(regIndex)) +#define FFX_SPD_DECLARE_UAV(regIndex) register(FFX_DECLARE_UAV_REGISTER(regIndex)) +#define FFX_SPD_DECLARE_CB(regIndex) register(FFX_DECLARE_CB_REGISTER(regIndex)) + +#if defined(FFX_SPD_BIND_CB_SPD) + cbuffer cbSPD : FFX_SPD_DECLARE_CB(FFX_SPD_BIND_CB_SPD) + { + FfxUInt32 mips; + FfxUInt32 numWorkGroups; + FfxUInt32x2 workGroupOffset; + FfxFloat32x2 invInputSize; // Only used for linear sampling mode + FfxFloat32x2 padding; + + #define FFX_SPD_CONSTANT_BUFFER_1_SIZE 8 // Number of 32-bit values. This must be kept in sync with the cbSPD size. + }; +#else + #define mips 0 + #define numWorkGroups 0 + #define workGroupOffset 0 + #define invInputSize 0 + #define padding 0 +#endif + +#define FFX_SPD_ROOTSIG_STRINGIFY(p) FFX_SPD_ROOTSIG_STR(p) +#define FFX_SPD_ROOTSIG_STR(p) #p +#define FFX_SPD_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_SPD_ROOTSIG_STRINGIFY(FFX_SPD_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_SPD_ROOTSIG_STRINGIFY(FFX_SPD_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_LINEAR_MIP_POINT, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_CLAMP, " \ + "comparisonFunc = COMPARISON_NEVER, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK)" )] + +#if defined(FFX_SPD_EMBED_ROOTSIG) +#define FFX_SPD_EMBED_ROOTSIG_CONTENT FFX_SPD_ROOTSIG +#else +#define FFX_SPD_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_SPD_EMBED_ROOTSIG + +FfxUInt32 Mips() +{ + return mips; +} + +FfxUInt32 NumWorkGroups() +{ + return numWorkGroups; +} + +FfxUInt32x2 WorkGroupOffset() +{ + return workGroupOffset; +} + +FfxFloat32x2 InvInputSize() +{ + return invInputSize; +} + +SamplerState s_LinearClamp : register(s0); + + // SRVs + #if defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + Texture2DArray r_input_downsample_src : FFX_SPD_DECLARE_SRV(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC); + #endif + + // UAV declarations + #if defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) + struct SpdGlobalAtomicBuffer { FfxUInt32 counter[6]; }; + globallycoherent RWStructuredBuffer rw_internal_global_atomic : FFX_SPD_DECLARE_UAV(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC); + #endif + #if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + globallycoherent RWTexture2DArray rw_input_downsample_src_mid_mip : FFX_SPD_DECLARE_UAV(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP); + #endif + #if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + RWTexture2DArray rw_input_downsample_src_mips[SPD_MAX_MIP_LEVELS+1] : FFX_SPD_DECLARE_UAV(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS); + #endif + +#if FFX_HALF + +#if defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + FfxFloat16x4 SampleSrcImageH(FfxFloat32x2 uv, FfxUInt32 slice) + { + FfxFloat32x2 textureCoord = FfxFloat32x2(uv) * InvInputSize() + InvInputSize(); + FfxFloat32x4 result = r_input_downsample_src.SampleLevel(s_LinearClamp, FfxFloat32x3(textureCoord, slice), 0); + return FfxFloat16x4(ffxSrgbFromLinear(result.x), ffxSrgbFromLinear(result.y), ffxSrgbFromLinear(result.z), result.w); + } + #endif // defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + FfxFloat16x4 LoadSrcImageH(FfxFloat32x2 uv, FfxUInt32 slice) + { + return FfxFloat16x4(rw_input_downsample_src_mips[0][FfxUInt32x3(uv, slice)]); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + void StoreSrcMipH(FfxFloat16x4 value, FfxInt32x2 uv, FfxUInt32 slice, FfxUInt32 mip) + { + rw_input_downsample_src_mips[mip][FfxUInt32x3(uv, slice)] = FfxFloat32x4(value); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + FfxFloat16x4 LoadMidMipH(FfxInt32x2 uv, FfxUInt32 slice) + { + return FfxFloat16x4(rw_input_downsample_src_mid_mip[FfxUInt32x3(uv, slice)]); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + void StoreMidMipH(FfxFloat16x4 value, FfxInt32x2 uv, FfxUInt32 slice) + { + rw_input_downsample_src_mid_mip[FfxUInt32x3(uv, slice)] = FfxFloat32x4(value); + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#else // FFX_HALF + +#if defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + FfxFloat32x4 SampleSrcImage(FfxInt32x2 uv, FfxUInt32 slice) + { + FfxFloat32x2 textureCoord = FfxFloat32x2(uv) * InvInputSize() + InvInputSize(); + FfxFloat32x4 result = r_input_downsample_src.SampleLevel(s_LinearClamp, FfxFloat32x3(textureCoord, slice), 0); + return FfxFloat32x4(ffxSrgbFromLinear(result.x), ffxSrgbFromLinear(result.y), ffxSrgbFromLinear(result.z), result.w); + } +#endif // defined(FFX_SPD_BIND_SRV_INPUT_DOWNSAMPLE_SRC) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + FfxFloat32x4 LoadSrcImage(FfxInt32x2 uv, FfxUInt32 slice) + { + return rw_input_downsample_src_mips[0][FfxUInt32x3(uv, slice)]; + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + void StoreSrcMip(FfxFloat32x4 value, FfxInt32x2 uv, FfxUInt32 slice, FfxUInt32 mip) + { + rw_input_downsample_src_mips[mip][FfxUInt32x3(uv, slice)] = value; + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MIPS) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + FfxFloat32x4 LoadMidMip(FfxInt32x2 uv, FfxUInt32 slice) + { + return rw_input_downsample_src_mid_mip[FfxUInt32x3(uv, slice)]; + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#if defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + void StoreMidMip(FfxFloat32x4 value, FfxInt32x2 uv, FfxUInt32 slice) + { + rw_input_downsample_src_mid_mip[FfxUInt32x3(uv, slice)] = value; + } +#endif // defined(FFX_SPD_BIND_UAV_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP) + +#endif // FFX_HALF + +#if defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) +void IncreaseAtomicCounter(FFX_PARAMETER_IN FfxUInt32 slice, FFX_PARAMETER_INOUT FfxUInt32 counter) +{ + InterlockedAdd(rw_internal_global_atomic[0].counter[slice], 1, counter); +} +#endif // defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) + +#if defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) +void ResetAtomicCounter(FFX_PARAMETER_IN FfxUInt32 slice) +{ + rw_internal_global_atomic[0].counter[slice] = 0; +} +#endif // defined(FFX_SPD_BIND_UAV_INTERNAL_GLOBAL_ATOMIC) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_downsample.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_downsample.h new file mode 100644 index 00000000..84d40397 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_downsample.h @@ -0,0 +1,171 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_core.h" + +#if FFX_HALF + #define FFX_SPD_PACKED_ONLY 1 +#endif // FFX_HALF + +#if FFX_SPD_OPTION_LINEAR_SAMPLE + #define SPD_LINEAR_SAMPLER 1 +#endif // FFX_SPD_OPTION_LINEAR_SAMPLE + +#if FFX_SPD_OPTION_WAVE_INTEROP_LDS + #define FFX_SPD_NO_WAVE_OPERATIONS 1 +#endif // FFX_SPD_OPTION_WAVE_INTEROP_LDS + +FFX_GROUPSHARED FfxUInt32 spdCounter; + +void SpdIncreaseAtomicCounter(FfxUInt32 slice) +{ + IncreaseAtomicCounter(slice, spdCounter); +} + +FfxUInt32 SpdGetAtomicCounter() +{ + return spdCounter; +} + +void SpdResetAtomicCounter(FfxUInt32 slice) +{ + ResetAtomicCounter(slice); +} + +#if FFX_HALF + +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateRG[16][16]; +FFX_GROUPSHARED FfxFloat16x2 spdIntermediateBA[16][16]; + +FfxFloat16x4 SpdLoadSourceImageH(FfxInt32x2 tex, FfxUInt32 slice) +{ +#if defined SPD_LINEAR_SAMPLER + return SampleSrcImageH(tex, slice); +#else + return LoadSrcImageH(tex, slice); +#endif // SPD_LINEAR_SAMPLER +} + +FfxFloat16x4 SpdLoadH(FfxInt32x2 p, FfxUInt32 slice) +{ + return LoadMidMipH(p, slice); +} + +void SpdStoreH(FfxInt32x2 pix, FfxFloat16x4 value, FfxUInt32 mip, FfxUInt32 slice) +{ + if (mip == 5) + StoreMidMipH(value, pix, slice); + else + StoreSrcMipH(value, pix, slice, mip + 1); +} + +FfxFloat16x4 SpdLoadIntermediateH(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat16x4( + spdIntermediateRG[x][y].x, + spdIntermediateRG[x][y].y, + spdIntermediateBA[x][y].x, + spdIntermediateBA[x][y].y); +} + +void SpdStoreIntermediateH(FfxUInt32 x, FfxUInt32 y, FfxFloat16x4 value) +{ + spdIntermediateRG[x][y] = value.xy; + spdIntermediateBA[x][y] = value.zw; +} + +FfxFloat16x4 SpdReduce4H(FfxFloat16x4 v0, FfxFloat16x4 v1, FfxFloat16x4 v2, FfxFloat16x4 v3) +{ +#if FFX_SPD_OPTION_DOWNSAMPLE_FILTER == 1 + return min(min(v0, v1), min(v2, v3)); +#elif FFX_SPD_OPTION_DOWNSAMPLE_FILTER == 2 + return max(max(v0, v1), max(v2, v3)); +#else + return (v0 + v1 + v2 + v3) * FfxFloat16(0.25); +#endif +} + +#else + +FFX_GROUPSHARED FfxFloat32 spdIntermediateR[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateG[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateB[16][16]; +FFX_GROUPSHARED FfxFloat32 spdIntermediateA[16][16]; + +FfxFloat32x4 SpdLoadSourceImage(FfxInt32x2 tex, FfxUInt32 slice) +{ +#if defined SPD_LINEAR_SAMPLER + return SampleSrcImage(tex, slice); +#else + return LoadSrcImage(tex, slice); +#endif // SPD_LINEAR_SAMPLER +} + +FfxFloat32x4 SpdLoad(FfxInt32x2 tex, FfxUInt32 slice) +{ + return LoadMidMip(tex, slice); +} + +void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 mip, FfxUInt32 slice) +{ + if (mip == 5) + StoreMidMip(outValue, pix, slice); + else + StoreSrcMip(outValue, pix, slice, mip + 1); +} + +FfxFloat32x4 SpdLoadIntermediate(FfxUInt32 x, FfxUInt32 y) +{ + return FfxFloat32x4(spdIntermediateR[x][y], spdIntermediateG[x][y], spdIntermediateB[x][y], spdIntermediateA[x][y]); +} + +void SpdStoreIntermediate(FfxUInt32 x, FfxUInt32 y, FfxFloat32x4 value) +{ + spdIntermediateR[x][y] = value.x; + spdIntermediateG[x][y] = value.y; + spdIntermediateB[x][y] = value.z; + spdIntermediateA[x][y] = value.w; +} + +FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3) +{ +#if FFX_SPD_OPTION_DOWNSAMPLE_FILTER == 1 + return ffxMin(ffxMin(v0, v1), ffxMin(v2, v3)); +#elif FFX_SPD_OPTION_DOWNSAMPLE_FILTER == 2 + return ffxMax(ffxMax(v0, v1), ffxMax(v2, v3)); +#else + return (v0 + v1 + v2 + v3) * 0.25; +#endif +} + +#endif // FFX_HALF + +#include "spd/ffx_spd.h" + +void DOWNSAMPLE(FfxUInt32 LocalThreadId, FfxUInt32x3 WorkGroupId) +{ +#if FFX_HALF + SpdDownsampleH(WorkGroupId.xy, LocalThreadId, Mips(), NumWorkGroups(), WorkGroupId.z, WorkGroupOffset()); +#else + SpdDownsample(WorkGroupId.xy, LocalThreadId, Mips(), NumWorkGroups(), WorkGroupId.z, WorkGroupOffset()); +#endif // FFX_HALF +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_resources.h new file mode 100644 index 00000000..a346656a --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/spd/ffx_spd_resources.h @@ -0,0 +1,58 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_SPD_RESOURCES_H +#define FFX_SPD_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) + +// Assumes a maximum on 12 mips. If larger base resolution support is added, +// extra mip resources need to also be added +#define SPD_MAX_MIP_LEVELS 12 + +#define FFX_SPD_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_GLOBAL_ATOMIC 1 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MID_MIPMAP 2 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC 3 // same as FFX_SPD_RESOURCE_DOWNSAMPLE_SRC_MIPMAP_0 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_0 3 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_1 4 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_2 5 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_3 6 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_4 7 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_5 8 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_6 9 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_7 10 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_8 11 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_9 12 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_10 13 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_11 14 +#define FFX_SPD_RESOURCE_IDENTIFIER_INPUT_DOWNSAMPLE_SRC_MIPMAP_12 15 +#define FFX_SPD_RESOURCE_IDENTIFIER_INTERNAL_GLOBAL_ATOMIC 16 + +#define FFX_SPD_RESOURCE_IDENTIFIER_COUNT 17 + +// CBV resource definitions +#define FFX_SPD_CONSTANTBUFFER_IDENTIFIER_SPD 0 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif // FFX_SPD_RESOURCES_H diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/CMakeCompileSSSRShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/CMakeCompileSSSRShaders.txt new file mode 100644 index 00000000..42935d84 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/CMakeCompileSSSRShaders.txt @@ -0,0 +1,49 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(SSSR_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(SSSR_PERMUTATION_ARGS + -DFFX_SSSR_OPTION_INVERTED_DEPTH={0,1}) + +set(SSSR_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/sssr") + +if (NOT SSSR_SHADER_EXT) + set(SSSR_SHADER_EXT *) +endif() + +file(GLOB SSSR_SHADERS + "shaders/sssr/ffx_sssr_classify_tiles_pass.${SSSR_SHADER_EXT}" + "shaders/sssr/ffx_sssr_depth_downsample_pass.${SSSR_SHADER_EXT}" + "shaders/sssr/ffx_sssr_intersect_pass.${SSSR_SHADER_EXT}" + "shaders/sssr/ffx_sssr_prepare_blue_noise_texture_pass.${SSSR_SHADER_EXT}" + "shaders/sssr/ffx_sssr_prepare_indirect_args_pass.${SSSR_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${SSSR_BASE_ARGS}" "${SSSR_API_BASE_ARGS}" "${SSSR_PERMUTATION_ARGS}" "${SSSR_INCLUDE_ARGS}" + "${SSSR_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" SSSR_PERMUTATION_OUTPUTS) + +add_shader_output("${SSSR_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_callbacks_glsl.h new file mode 100644 index 00000000..5bdffa5d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_callbacks_glsl.h @@ -0,0 +1,644 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_sssr_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(SSSR_BIND_CB_SSSR) + layout (set = 0, binding = SSSR_BIND_CB_SSSR, std140) uniform cbSSSR_t + { + FfxFloat32Mat4 invViewProjection; + FfxFloat32Mat4 projection; + FfxFloat32Mat4 invProjection; + FfxFloat32Mat4 viewMatrix; + FfxFloat32Mat4 invView; + FfxFloat32Mat4 prevViewProjection; + FfxUInt32x2 renderSize; + FfxFloat32x2 inverseRenderSize; + FfxFloat32 normalsUnpackMul; + FfxFloat32 normalsUnpackAdd; + FfxUInt32 roughnessChannel; + FfxBoolean isRoughnessPerceptual; + FfxFloat32 iblFactor; + FfxFloat32 temporalStabilityFactor; + FfxFloat32 depthBufferThickness; + FfxFloat32 roughnessThreshold; + FfxFloat32 varianceThreshold; + FfxUInt32 frameIndex; + FfxUInt32 maxTraversalIntersections; + FfxUInt32 minTraversalOccupancy; + FfxUInt32 mostDetailedMip; + FfxUInt32 samplesPerQuad; + FfxUInt32 temporalVarianceGuidedTracingEnabled; + } cbSSSR; + +FfxFloat32Mat4 InvViewProjection() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.invViewProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 Projection() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.projection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 InvProjection() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.invProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 ViewMatrix() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.viewMatrix; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 InvView() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.invView; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32Mat4 PrevViewProjection() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.prevViewProjection; +#else + return FfxFloat32Mat4(0.0f); +#endif +} + +FfxFloat32 NormalsUnpackMul() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.normalsUnpackMul; +#else + return 0.0f; +#endif +} + +FfxFloat32 NormalsUnpackAdd() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.normalsUnpackAdd; +#else + return 0.0f; +#endif +} + +FfxUInt32 RoughnessChannel() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.roughnessChannel; +#else + return 0; +#endif +} + +FfxBoolean IsRoughnessPerceptual() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.isRoughnessPerceptual; +#else + return false; +#endif +} + +FfxUInt32x2 RenderSize() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.renderSize; +#else + return FfxUInt32x2(0); +#endif +} + +FfxFloat32x2 InverseRenderSize() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.inverseRenderSize; +#else + return FfxFloat32x2(0.0f); +#endif +} + +FfxFloat32 IBLFactor() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.iblFactor; +#else + return 0.0f; +#endif +} + +FfxFloat32 TemporalStabilityFactor() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.temporalStabilityFactor; +#else + return 0.0f; +#endif +} + +FfxFloat32 DepthBufferThickness() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.depthBufferThickness; +#else + return 0.0f; +#endif +} + +FfxFloat32 RoughnessThreshold() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.roughnessThreshold; +#else + return 0.0f; +#endif +} + +FfxFloat32 VarianceThreshold() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.varianceThreshold; +#else + return 0.0f; +#endif +} + +FfxUInt32 FrameIndex() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.frameIndex; +#else + return 0; +#endif +} + +FfxUInt32 MaxTraversalIntersections() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.maxTraversalIntersections; +#else + return 0; +#endif +} + +FfxUInt32 MinTraversalOccupancy() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.minTraversalOccupancy; +#else + return 0; +#endif +} + +FfxUInt32 MostDetailedMip() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.mostDetailedMip; +#else + return 0; +#endif +} + +FfxUInt32 SamplesPerQuad() +{ +#if defined SSSR_BIND_CB_SSSR + return cbSSSR.samplesPerQuad; +#else + return 0; +#endif +} + +FfxBoolean TemporalVarianceGuidedTracingEnabled() +{ +#if defined SSSR_BIND_CB_SSSR + return FfxBoolean(cbSSSR.temporalVarianceGuidedTracingEnabled); +#else + return false; +#endif +} + +#endif // #if defined(SSSR_BIND_CB_SSSR) + +layout (set = 0, binding = 1000) uniform sampler s_EnvironmentMapSampler; +layout (set = 0, binding = 1001) uniform sampler s_LinearSampler; + +// SRVs +#if defined SSSR_BIND_SRV_INPUT_COLOR + layout (set = 0, binding = SSSR_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color; +#endif +#if defined SSSR_BIND_SRV_INPUT_DEPTH + layout (set = 0, binding = SSSR_BIND_SRV_INPUT_DEPTH) uniform texture2D r_input_depth; +#endif +#if defined SSSR_BIND_SRV_DEPTH_HIERARCHY + layout (set = 0, binding = SSSR_BIND_SRV_DEPTH_HIERARCHY) uniform texture2D r_depth_hierarchy; +#endif +#if defined SSSR_BIND_SRV_INPUT_NORMAL + layout (set = 0, binding = SSSR_BIND_SRV_INPUT_NORMAL) uniform texture2D r_input_normal; +#endif +#if defined SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS + layout (set = 0, binding = SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS) uniform texture2D r_input_material_parameters; +#endif +#if defined SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP + layout (set = 0, binding = SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP) uniform textureCube r_input_environment_map; +#endif +#if defined SSSR_BIND_SRV_RADIANCE + layout (set = 0, binding = SSSR_BIND_SRV_RADIANCE) uniform texture2D r_radiance; +#endif +#if defined SSSR_BIND_SRV_RADIANCE_HISTORY + layout (set = 0, binding = SSSR_BIND_SRV_RADIANCE_HISTORY) uniform texture2D r_radiance_history; +#endif +#if defined SSSR_BIND_SRV_VARIANCE + layout (set = 0, binding = SSSR_BIND_SRV_VARIANCE) uniform texture2D r_variance; +#endif +#if defined SSSR_BIND_SRV_EXTRACTED_ROUGHNESS + layout (set = 0, binding = SSSR_BIND_SRV_EXTRACTED_ROUGHNESS) uniform texture2D r_extracted_roughness; +#endif +#if defined SSSR_BIND_SRV_SOBOL_BUFFER + layout (set = 0, binding = SSSR_BIND_SRV_SOBOL_BUFFER) uniform utexture2D r_sobol_buffer; +#endif +#if defined SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER + layout (set = 0, binding = SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER) uniform utexture2D r_scrambling_tile_buffer; +#endif +#if defined SSSR_BIND_SRV_BLUE_NOISE_TEXTURE + layout (set = 0, binding = SSSR_BIND_SRV_BLUE_NOISE_TEXTURE) uniform texture2D r_blue_noise_texture; +#endif +#if defined SSSR_BIND_SRV_INPUT_BRDF_TEXTURE + layout (set = 0, binding = SSSR_BIND_SRV_INPUT_BRDF_TEXTURE) uniform texture2D r_input_brdf_texture; +#endif + +// UAVs +#if defined SSSR_BIND_UAV_OUTPUT + layout (set = 0, binding = SSSR_BIND_UAV_OUTPUT, rgba32f) uniform image2D rw_output; +#endif +#if defined SSSR_BIND_UAV_RADIANCE + layout (set = 0, binding = SSSR_BIND_UAV_RADIANCE, rgba32f) uniform image2D rw_radiance; +#endif +#if defined SSSR_BIND_UAV_VARIANCE + layout (set = 0, binding = SSSR_BIND_UAV_VARIANCE, r32f) uniform image2D rw_variance; +#endif +#if defined SSSR_BIND_UAV_RAY_LIST + layout (set = 0, binding = SSSR_BIND_UAV_RAY_LIST, std430) buffer rw_ray_list_t + { + FfxUInt32 data[]; + } rw_ray_list; +#endif +#if defined SSSR_BIND_UAV_DENOISER_TILE_LIST + layout (set = 0, binding = SSSR_BIND_UAV_DENOISER_TILE_LIST, std430) buffer rw_denoiser_tile_list_t + { + FfxUInt32 data[]; + } rw_denoiser_tile_list; +#endif +#if defined SSSR_BIND_UAV_RAY_COUNTER + layout (set = 0, binding = SSSR_BIND_UAV_RAY_COUNTER, std430) buffer rw_ray_counter_t + { + FfxUInt32 data[]; + } rw_ray_counter; +#endif +#if defined SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS + layout (set = 0, binding = SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS, std430) buffer rw_intersection_pass_indirect_args_t + { + FfxUInt32 data[]; + } rw_intersection_pass_indirect_args; +#endif +#if defined SSSR_BIND_UAV_EXTRACTED_ROUGHNESS + layout (set = 0, binding = SSSR_BIND_UAV_EXTRACTED_ROUGHNESS, r32f) uniform image2D rw_extracted_roughness; +#endif +#if defined SSSR_BIND_UAV_BLUE_NOISE_TEXTURE + layout (set = 0, binding = SSSR_BIND_UAV_BLUE_NOISE_TEXTURE, rg32f) uniform image2D rw_blue_noise_texture; +#endif +#if defined SSSR_BIND_UAV_DEPTH_HIERARCHY + layout (set = 0, binding = SSSR_BIND_UAV_DEPTH_HIERARCHY, r32f) uniform image2D rw_depth_hierarchy[13]; +#endif + +// SPD UAV +#if defined SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC + layout (set = 0, binding = SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC, std430) buffer rw_spd_global_atomic_t + { + FfxUInt32 data[]; + } rw_spd_global_atomic; +#endif + +#if FFX_HALF + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +FfxFloat16x4 SpdLoadH(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return FfxFloat16x4(imageLoad(rw_depth_hierarchy[6], coordinate).x); // 5 -> 6 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_SRV_INPUT_DEPTH) +FfxFloat16x4 SpdLoadSourceImageH(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return FfxFloat16x4(texelFetch(r_input_depth, coordinate, 0).x); +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_DEPTH) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void SpdStoreH(FfxInt32x2 pix, FfxFloat16x4 outValue, FfxUInt32 coordinate, FfxUInt32 slice) +{ + imageStore(rw_depth_hierarchy[coordinate + 1], pix, FfxFloat16x4(outValue.x)); // + 1 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#endif // #if defined(FFX_HALF) + +#if defined(SSSR_BIND_SRV_INPUT_NORMAL) +FfxFloat32x3 FFX_SSSR_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ + // Normals are + return normalize(NormalsUnpackMul() * texelFetch(r_input_normal, pixel_coordinate, 0).xyz + NormalsUnpackAdd()); +} +#endif // #if defined(SSSR_BIND_SRV_INPUT_NORMAL) + +#if defined(SSSR_BIND_SRV_DEPTH_HIERARCHY) +FfxFloat32 FFX_SSSR_LoadDepth(FfxInt32x2 pixel_coordinate, FfxInt32 mip) +{ + return texelFetch(r_depth_hierarchy, pixel_coordinate, mip).x; +} +#endif // #if defined(SSSR_BIND_SRV_DEPTH_HIERARCHY) + +#if defined(SSSR_BIND_SRV_BLUE_NOISE_TEXTURE) +FfxFloat32x2 FFX_SSSR_SampleRandomVector2D(FfxUInt32x2 pixel) +{ + return texelFetch(r_blue_noise_texture, FfxInt32x2(pixel.xy % 128), 0).xy; +} +#endif // #if defined(SSSR_BIND_SRV_BLUE_NOISE_TEXTURE) + +#if defined(SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP) +FfxFloat32x3 FFX_SSSR_SampleEnvironmentMap(FfxFloat32x3 direction, FfxFloat32 preceptualRoughness) +{ + FfxInt32x2 cubeSize = textureSize(r_input_environment_map, 0); + FfxInt32 maxMipLevel = FfxInt32(log2(FfxFloat32(cubeSize.x > 0 ? cubeSize.x : 1))); + FfxFloat32 lod = clamp(preceptualRoughness * FfxFloat32(maxMipLevel), 0.0, FfxFloat32(maxMipLevel)); + return textureLod(samplerCube(r_input_environment_map, s_EnvironmentMapSampler), direction, lod).xyz * IBLFactor(); +} +#endif // #if defined(SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +void IncrementRayCounter(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value) +{ + original_value = atomicAdd(rw_ray_counter.data[0], value); +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +void IncrementDenoiserTileCounter(FFX_PARAMETER_OUT FfxUInt32 original_value) +{ + original_value = atomicAdd(rw_ray_counter.data[2], 1); +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +FfxUInt32 PackRayCoords(FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 ray_x_15bit = ray_coord.x & 32767; // 0b111111111111111 + FfxUInt32 ray_y_14bit = ray_coord.y & 16383; // 0b11111111111111; + FfxUInt32 copy_horizontal_1bit = copy_horizontal ? 1 : 0; + FfxUInt32 copy_vertical_1bit = copy_vertical ? 1 : 0; + FfxUInt32 copy_diagonal_1bit = copy_diagonal ? 1 : 0; + + FfxUInt32 packed = (copy_diagonal_1bit << 31) | (copy_vertical_1bit << 30) | (copy_horizontal_1bit << 29) | (ray_y_14bit << 15) | (ray_x_15bit << 0); + return packed; +} + +#if defined (SSSR_BIND_UAV_RAY_LIST) +void StoreRay(FfxInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace + rw_ray_list.data[index] = packedRayCoords; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_LIST) + +#if defined (SSSR_BIND_UAV_DENOISER_TILE_LIST) +void StoreDenoiserTile(FfxInt32 index, FfxUInt32x2 tile_coord) +{ + rw_denoiser_tile_list.data[index] = ((tile_coord.y & 0xffffu) << 16) | ((tile_coord.x & 0xffffu) << 0); // Store out pixel to trace +} +#endif // #if defined (SSSR_BIND_UAV_DENOISER_TILE_LIST) + +#if defined (SSSR_BIND_SRV_DEPTH_HIERARCHY) +FfxBoolean IsReflectiveSurface(FfxUInt32x2 pixel_coordinate, FfxFloat32 roughness) +{ +#if FFX_SSSR_OPTION_INVERTED_DEPTH + const FfxFloat32 far_plane = 0.0f; + return texelFetch(r_depth_hierarchy, FfxInt32x2(pixel_coordinate), 0).r > far_plane; +#else // FFX_SSSR_OPTION_INVERTED_DEPTH + const FfxFloat32 far_plane = 1.0f; + return texelFetch(r_depth_hierarchy, FfxInt32x2(pixel_coordinate), 0).r < far_plane; +#endif // FFX_SSSR_OPTION_INVERTED_DEPTH +} +#endif // #if defined (SSSR_BIND_SRV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_EXTRACTED_ROUGHNESS) +void StoreExtractedRoughness(FfxUInt32x2 coordinate, FfxFloat32 roughness) +{ + imageStore(rw_extracted_roughness, FfxInt32x2(coordinate), FfxFloat32x4(roughness)); +} +#endif // #if defined (SSSR_BIND_UAV_EXTRACTED_ROUGHNESS) + +#if defined (SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS) +FfxFloat32 LoadRoughnessFromMaterialParametersInput(FfxUInt32x3 coordinate) +{ + FfxFloat32 rawRoughness = texelFetch(r_input_material_parameters, FfxInt32x2(coordinate.xy), FfxInt32(coordinate.z))[RoughnessChannel()]; + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +FfxBoolean IsRayIndexValid(FfxUInt32 ray_index) +{ + return ray_index < rw_ray_counter.data[1]; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_UAV_RAY_LIST) +FfxUInt32 GetRaylist(FfxUInt32 ray_index) +{ + return rw_ray_list.data[ray_index]; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_LIST) + +#if defined (SSSR_BIND_UAV_BLUE_NOISE_TEXTURE) +void FFX_SSSR_StoreBlueNoiseSample(FfxUInt32x2 coordinate, FfxFloat32x2 blue_noise_sample) +{ + imageStore(rw_blue_noise_texture, FfxInt32x2(coordinate), FfxFloat32x4(blue_noise_sample, 0.0f, 0.0f)); +} +#endif // #if defined (SSSR_BIND_UAV_BLUE_NOISE_TEXTURE) + +#if defined (SSSR_BIND_SRV_VARIANCE) +FfxFloat32 FFX_SSSR_LoadVarianceHistory(FfxInt32x3 coordinate) +{ + return texelFetch(r_variance, coordinate.xy, coordinate.z).x; +} +#endif // #if defined (SSSR_BIND_SRV_VARIANCE) + +#if defined (SSSR_BIND_UAV_RADIANCE) +void FFX_SSSR_StoreRadiance(FfxUInt32x2 coordinate, FfxFloat32x4 radiance) +{ + imageStore(rw_radiance, FfxInt32x2(coordinate), radiance); +} +#endif // #if defined (SSSR_BIND_UAV_RADIANCE) + +#if defined (SSSR_BIND_SRV_SOBOL_BUFFER) +FfxUInt32 FFX_SSSR_GetSobolSample(FfxUInt32x3 coordinate) +{ + return FfxUInt32(texelFetch(r_sobol_buffer, FfxInt32x2(coordinate.xy), FfxInt32(coordinate.z)).r); +} +#endif // #if defined (SSSR_BIND_SRV_SOBOL_BUFFER) + +#if defined (SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER) +FfxUInt32 FFX_SSSR_GetScramblingTile(FfxUInt32x3 coordinate) +{ + return FfxUInt32(texelFetch(r_scrambling_tile_buffer, FfxInt32x2(coordinate.xy), FfxInt32(coordinate.z)).r); +} +#endif // #if defined (SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER) + +#if defined (SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS) +void FFX_SSSR_WriteIntersectIndirectArgs(FfxUInt32 index, FfxUInt32 data) +{ + rw_intersection_pass_indirect_args.data[index] = data; +} +#endif // #if defined (SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +void FFX_SSSR_WriteRayCounter(FfxUInt32 index, FfxUInt32 data) +{ + rw_ray_counter.data[index] = data; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +FfxUInt32 FFX_SSSR_GetRayCounter(FfxUInt32 index) +{ + return rw_ray_counter.data[index]; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_SRV_INPUT_DEPTH) +void FFX_SSSR_GetInputDepthDimensions(FFX_PARAMETER_OUT FfxFloat32x2 image_size) +{ + image_size = textureSize(r_input_depth, 0); +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_DEPTH) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void FFX_SSSR_GetDepthHierarchyMipDimensions(FfxUInt32 mip, FFX_PARAMETER_OUT FfxFloat32x2 image_size) +{ + image_size = imageSize(rw_depth_hierarchy[mip]); +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_SRV_INPUT_DEPTH) +FfxFloat32 FFX_SSSR_GetInputDepth(FfxUInt32x2 coordinate) +{ + return texelFetch(r_input_depth, FfxInt32x2(coordinate), 0).r; +} + +FfxFloat32x4 SpdLoadSourceImage(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return FFX_SSSR_GetInputDepth(coordinate).xxxx; +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_DEPTH) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void FFX_SSSR_WriteDepthHierarchy(FfxUInt32 index, FfxUInt32x2 coordinate, FfxFloat32 data) +{ + imageStore(rw_depth_hierarchy[index], FfxInt32x2(coordinate), FfxFloat32x4(data)); +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +FfxFloat32x4 SpdLoad(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return FfxFloat32x4(imageLoad(rw_depth_hierarchy[6], coordinate).x); // 5 -> 6 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 coordinate, FfxUInt32 slice) +{ + imageStore(rw_depth_hierarchy[coordinate + 1], pix, FfxFloat32x4(outValue.x)); // + 1 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) +void SpdResetAtomicCounter(FfxUInt32 slice) +{ + rw_spd_global_atomic.data[0] = 0; +} +#endif // #if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) + +#if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) +void FFX_SSSR_SPDIncreaseAtomicCounter(FFX_PARAMETER_INOUT FfxUInt32 spdCounter) +{ + spdCounter = atomicAdd(rw_spd_global_atomic.data[0], 1); +} +#endif // #if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) + +#if defined(SSSR_BIND_SRV_INPUT_COLOR) +FfxFloat32x3 FFX_SSSR_LoadInputColor(FfxInt32x3 coordinate) +{ + return texelFetch(r_input_color, coordinate.xy, coordinate.z).xyz; +} +#endif // #if defined(SSSR_BIND_SRV_INPUT_COLOR) + +#if defined(SSSR_BIND_SRV_EXTRACTED_ROUGHNESS) +FfxFloat32 FFX_SSSR_LoadExtractedRoughness(FfxInt32x3 coordinate) +{ + return texelFetch(r_extracted_roughness, coordinate.xy, coordinate.z).x; +} +#endif // #if defined(SSSR_BIND_SRV_EXTRACTED_ROUGHNESS) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_callbacks_hlsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_callbacks_hlsl.h new file mode 100644 index 00000000..322fda9e --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_callbacks_hlsl.h @@ -0,0 +1,602 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_sssr_resources.h" + +#if defined(FFX_GPU) +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic push +#pragma dxc diagnostic ignored "-Wambig-lit-shift" +#endif //__hlsl_dx_compiler +#include "ffx_core.h" +#ifdef __hlsl_dx_compiler +#pragma dxc diagnostic pop +#endif //__hlsl_dx_compiler + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#pragma warning(disable: 3205) // conversion from larger type to smaller + +#define DECLARE_SRV_REGISTER(regIndex) t##regIndex +#define DECLARE_UAV_REGISTER(regIndex) u##regIndex +#define DECLARE_CB_REGISTER(regIndex) b##regIndex +#define FFX_SSSR_DECLARE_SRV(regIndex) register(DECLARE_SRV_REGISTER(regIndex)) +#define FFX_SSSR_DECLARE_UAV(regIndex) register(DECLARE_UAV_REGISTER(regIndex)) +#define FFX_SSSR_DECLARE_CB(regIndex) register(DECLARE_CB_REGISTER(regIndex)) + +#if defined(SSSR_BIND_CB_SSSR) + cbuffer cbSSSR : FFX_SSSR_DECLARE_CB(SSSR_BIND_CB_SSSR) + { + FfxFloat32Mat4 invViewProjection; + FfxFloat32Mat4 projection; + FfxFloat32Mat4 invProjection; + FfxFloat32Mat4 viewMatrix; + FfxFloat32Mat4 invView; + FfxFloat32Mat4 prevViewProjection; + FfxUInt32x2 renderSize; + FfxFloat32x2 inverseRenderSize; + FfxFloat32 normalsUnpackMul; + FfxFloat32 normalsUnpackAdd; + FfxUInt32 roughnessChannel; + FfxBoolean isRoughnessPerceptual; + FfxFloat32 iblFactor; + FfxFloat32 temporalStabilityFactor; + FfxFloat32 depthBufferThickness; + FfxFloat32 roughnessThreshold; + FfxFloat32 varianceThreshold; + FfxUInt32 frameIndex; + FfxUInt32 maxTraversalIntersections; + FfxUInt32 minTraversalOccupancy; + FfxUInt32 mostDetailedMip; + FfxUInt32 samplesPerQuad; + FfxUInt32 temporalVarianceGuidedTracingEnabled; + + #define FFX_SSSR_CONSTANT_BUFFER_1_SIZE 110 // Number of 32-bit values. This must be kept in sync with the cbSSSR size. + }; +#else + #define invViewProjection 0 + #define projection 0 + #define invProjection 0 + #define viewMatrix 0 + #define invView 0 + #define prevViewProjection 0 + #define normalsUnpackMul 0 + #define normalsUnpackAdd 0 + #define roughnessChannel 0 + #define isRoughnessPerceptual 0 + #define renderSize 0 + #define inverseRenderSize 0 + #define iblFactor 0 + #define temporalStabilityFactor 0 + #define depthBufferThickness 0 + #define roughnessThreshold 0 + #define varianceThreshold 0 + #define frameIndex 0 + #define maxTraversalIntersections 0 + #define minTraversalOccupancy 0 + #define mostDetailedMip 0 + #define samplesPerQuad 0 + #define temporalVarianceGuidedTracingEnabled 0 + + #define FFX_SSSR_CONSTANT_BUFFER_1_SIZE 0 +#endif + +#if defined(FFX_GPU) +#define FFX_SSSR_ROOTSIG_STRINGIFY(p) FFX_SSSR_ROOTSIG_STR(p) +#define FFX_SSSR_ROOTSIG_STR(p) #p +#define FFX_SSSR_ROOTSIG [RootSignature( "DescriptorTable(UAV(u0, numDescriptors = " FFX_SSSR_ROOTSIG_STRINGIFY(FFX_SSSR_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "DescriptorTable(SRV(t0, numDescriptors = " FFX_SSSR_ROOTSIG_STRINGIFY(FFX_SSSR_RESOURCE_IDENTIFIER_COUNT) ")), " \ + "CBV(b0), " \ + "StaticSampler(s0, filter = FILTER_MIN_MAG_MIP_LINEAR, " \ + "addressU = TEXTURE_ADDRESS_CLAMP, " \ + "addressV = TEXTURE_ADDRESS_CLAMP, " \ + "addressW = TEXTURE_ADDRESS_WRAP, " \ + "comparisonFunc = COMPARISON_ALWAYS, " \ + "borderColor = STATIC_BORDER_COLOR_TRANSPARENT_BLACK, " \ + "maxAnisotropy = 1, " \ + "visibility = SHADER_VISIBILITY_ALL) " )] + +#if defined(FFX_SSSR_EMBED_ROOTSIG) +#define FFX_SSSR_EMBED_ROOTSIG_CONTENT FFX_SSSR_ROOTSIG +#else +#define FFX_SSSR_EMBED_ROOTSIG_CONTENT +#endif // #if FFX_SSSR_EMBED_ROOTSIG + +#endif // #if defined(FFX_GPU) + +SamplerState s_EnvironmentMapSampler : register(s0); + +FfxFloat32Mat4 InvViewProjection() +{ + return invViewProjection; +} + +FfxFloat32Mat4 Projection() +{ + return projection; +} + +FfxFloat32Mat4 InvProjection() +{ + return invProjection; +} + +FfxFloat32Mat4 ViewMatrix() +{ + return viewMatrix; +} + +FfxFloat32Mat4 InvView() +{ + return invView; +} + +FfxFloat32Mat4 PrevViewProjection() +{ + return prevViewProjection; +} + +FfxFloat32 NormalsUnpackMul() +{ + return normalsUnpackMul; +} + +FfxFloat32 NormalsUnpackAdd() +{ + return normalsUnpackAdd; +} + +FfxUInt32 RoughnessChannel() +{ + return roughnessChannel; +} + +FfxBoolean IsRoughnessPerceptual() +{ + return isRoughnessPerceptual; +} + +FfxUInt32x2 RenderSize() +{ + return renderSize; +} + +FfxFloat32x2 InverseRenderSize() +{ + return inverseRenderSize; +} + +FfxFloat32 IBLFactor() +{ + return iblFactor; +} + +FfxFloat32 TemporalStabilityFactor() +{ + return temporalStabilityFactor; +} + +FfxFloat32 DepthBufferThickness() +{ + return depthBufferThickness; +} + +FfxFloat32 RoughnessThreshold() +{ + return roughnessThreshold; +} + +FfxFloat32 VarianceThreshold() +{ + return varianceThreshold; +} + +FfxUInt32 FrameIndex() +{ + return frameIndex; +} + +FfxUInt32 MaxTraversalIntersections() +{ + return maxTraversalIntersections; +} + +FfxUInt32 MinTraversalOccupancy() +{ + return minTraversalOccupancy; +} + +FfxUInt32 MostDetailedMip() +{ + return mostDetailedMip; +} + +FfxUInt32 SamplesPerQuad() +{ + return samplesPerQuad; +} + +FfxBoolean TemporalVarianceGuidedTracingEnabled() +{ + return FfxBoolean(temporalVarianceGuidedTracingEnabled); +} + +// SRVs + #if defined SSSR_BIND_SRV_INPUT_COLOR + Texture2D r_input_color : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_INPUT_COLOR); + #endif + #if defined SSSR_BIND_SRV_INPUT_DEPTH + Texture2D r_input_depth : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_INPUT_DEPTH); + #endif + #if defined SSSR_BIND_SRV_DEPTH_HIERARCHY + Texture2D r_depth_hierarchy : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_DEPTH_HIERARCHY); + #endif + #if defined SSSR_BIND_SRV_INPUT_NORMAL + Texture2D r_input_normal : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_INPUT_NORMAL); + #endif + #if defined SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS + Texture2D r_input_material_parameters : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS); + #endif + #if defined SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP + TextureCube r_input_environment_map : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP); + #endif + #if defined SSSR_BIND_SRV_RADIANCE + Texture2D r_radiance : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_RADIANCE); + #endif + #if defined SSSR_BIND_SRV_RADIANCE_HISTORY + Texture2D r_radiance_history : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_RADIANCE_HISTORY); + #endif + #if defined SSSR_BIND_SRV_VARIANCE + Texture2D r_variance : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_VARIANCE); + #endif + #if defined SSSR_BIND_SRV_EXTRACTED_ROUGHNESS + Texture2D r_extracted_roughness : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_EXTRACTED_ROUGHNESS); + #endif + #if defined SSSR_BIND_SRV_SOBOL_BUFFER + Texture2D r_sobol_buffer : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_SOBOL_BUFFER); + #endif + #if defined SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER + Texture2D r_scrambling_tile_buffer : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER); + #endif + #if defined SSSR_BIND_SRV_BLUE_NOISE_TEXTURE + Texture2D r_blue_noise_texture : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_BLUE_NOISE_TEXTURE); + #endif + #if defined SSSR_BIND_SRV_INPUT_BRDF_TEXTURE + Texture2D r_input_brdf_texture : FFX_SSSR_DECLARE_SRV(SSSR_BIND_SRV_INPUT_BRDF_TEXTURE); + #endif + +// UAVs + #if defined SSSR_BIND_UAV_OUTPUT + RWTexture2D rw_output : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_OUTPUT); + #endif + #if defined SSSR_BIND_UAV_RADIANCE + RWTexture2D rw_radiance : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_RADIANCE); + #endif + #if defined SSSR_BIND_UAV_VARIANCE + RWTexture2D rw_variance : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_VARIANCE); + #endif + #if defined SSSR_BIND_UAV_RAY_LIST + RWStructuredBuffer rw_ray_list : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_RAY_LIST); + #endif + #if defined SSSR_BIND_UAV_DENOISER_TILE_LIST + RWStructuredBuffer rw_denoiser_tile_list : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_DENOISER_TILE_LIST); + #endif + #if defined SSSR_BIND_UAV_RAY_COUNTER + globallycoherent RWStructuredBuffer rw_ray_counter : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_RAY_COUNTER); + #endif + #if defined SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS + RWStructuredBuffer rw_intersection_pass_indirect_args : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS); + #endif + #if defined SSSR_BIND_UAV_EXTRACTED_ROUGHNESS + RWTexture2D rw_extracted_roughness : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_EXTRACTED_ROUGHNESS); + #endif + #if defined SSSR_BIND_UAV_BLUE_NOISE_TEXTURE + RWTexture2D rw_blue_noise_texture : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_BLUE_NOISE_TEXTURE); + #endif + #if defined SSSR_BIND_UAV_DEPTH_HIERARCHY + RWTexture2D rw_depth_hierarchy[13] : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_DEPTH_HIERARCHY); + #endif + + // SPD UAV + #if defined SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC + globallycoherent RWStructuredBuffer rw_spd_global_atomic : FFX_SSSR_DECLARE_UAV(SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC); + #endif + +#if FFX_HALF + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +FfxFloat16x4 SpdLoadH(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return (FfxFloat16x4)rw_depth_hierarchy[6][coordinate].xxxx; // 5 -> 6 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_SRV_INPUT_DEPTH) +FfxFloat16x4 SpdLoadSourceImageH(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return (FfxFloat16x4)r_input_depth[coordinate].xxxx; +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_DEPTH) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void SpdStoreH(FfxInt32x2 pix, FfxFloat16x4 outValue, FfxUInt32 coordinate, FfxUInt32 slice) +{ + rw_depth_hierarchy[coordinate + 1][pix] = outValue.x; // + 1 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#endif // #if defined(FFX_HALF) + +#if defined(SSSR_BIND_SRV_INPUT_NORMAL) +FfxFloat32x3 FFX_SSSR_LoadWorldSpaceNormal(FfxInt32x2 pixel_coordinate) +{ + return normalize(NormalsUnpackMul() * r_input_normal.Load(FfxInt32x3(pixel_coordinate, 0)).xyz + NormalsUnpackAdd()); +} +#endif // #if defined(SSSR_BIND_SRV_INPUT_NORMAL) + +#if defined(SSSR_BIND_SRV_DEPTH_HIERARCHY) +FfxFloat32 FFX_SSSR_LoadDepth(FfxInt32x2 pixel_coordinate, FfxInt32 mip) +{ + return r_depth_hierarchy.Load(FfxInt32x3(pixel_coordinate, mip)); +} +#endif // #if defined(SSSR_BIND_SRV_DEPTH_HIERARCHY) + +#if defined(SSSR_BIND_SRV_BLUE_NOISE_TEXTURE) +FfxFloat32x2 FFX_SSSR_SampleRandomVector2D(FfxUInt32x2 pixel) +{ + return r_blue_noise_texture.Load(FfxInt32x3(pixel.xy % 128, 0)); +} +#endif // #if defined(SSSR_BIND_SRV_BLUE_NOISE_TEXTURE) + +#if defined(SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP) +FfxFloat32x3 FFX_SSSR_SampleEnvironmentMap(FfxFloat32x3 direction, FfxFloat32 preceptualRoughness) +{ + FfxFloat32 Width; FfxFloat32 Height; + r_input_environment_map.GetDimensions(Width, Height); + FfxInt32 maxMipLevel = FfxInt32(log2(FfxFloat32(Width > 0 ? Width : 1))); + FfxFloat32 mip = clamp(preceptualRoughness * FfxFloat32(maxMipLevel), 0.0, FfxFloat32(maxMipLevel)); + return r_input_environment_map.SampleLevel(s_EnvironmentMapSampler, direction, mip).xyz * IBLFactor(); +} +#endif // #if defined(SSSR_BIND_SRV_INPUT_ENVIRONMENT_MAP) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +void IncrementRayCounter(FfxUInt32 value, FFX_PARAMETER_OUT FfxUInt32 original_value) +{ + InterlockedAdd(rw_ray_counter[0], value, original_value); +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +void IncrementDenoiserTileCounter(FFX_PARAMETER_OUT FfxUInt32 original_value) +{ + InterlockedAdd(rw_ray_counter[2], 1, original_value); +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +FfxUInt32 PackRayCoords(FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 ray_x_15bit = ray_coord.x & 0b111111111111111; + FfxUInt32 ray_y_14bit = ray_coord.y & 0b11111111111111; + FfxUInt32 copy_horizontal_1bit = copy_horizontal ? 1 : 0; + FfxUInt32 copy_vertical_1bit = copy_vertical ? 1 : 0; + FfxUInt32 copy_diagonal_1bit = copy_diagonal ? 1 : 0; + + FfxUInt32 packed = (copy_diagonal_1bit << 31) | (copy_vertical_1bit << 30) | (copy_horizontal_1bit << 29) | (ray_y_14bit << 15) | (ray_x_15bit << 0); + return packed; +} + +#if defined (SSSR_BIND_UAV_RAY_LIST) +void StoreRay(FfxInt32 index, FfxUInt32x2 ray_coord, FfxBoolean copy_horizontal, FfxBoolean copy_vertical, FfxBoolean copy_diagonal) +{ + FfxUInt32 packedRayCoords = PackRayCoords(ray_coord, copy_horizontal, copy_vertical, copy_diagonal); // Store out pixel to trace + rw_ray_list[index] = packedRayCoords; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_LIST) + +#if defined (SSSR_BIND_UAV_DENOISER_TILE_LIST) +void StoreDenoiserTile(FfxInt32 index, FfxUInt32x2 tile_coord) +{ + rw_denoiser_tile_list[index] = ((tile_coord.y & 0xffffu) << 16) | ((tile_coord.x & 0xffffu) << 0); // Store out pixel to trace +} +#endif // #if defined (SSSR_BIND_UAV_DENOISER_TILE_LIST) + +#if defined (SSSR_BIND_SRV_DEPTH_HIERARCHY) +FfxBoolean IsReflectiveSurface(FfxInt32x2 pixel_coordinate, FfxFloat32 roughness) +{ +#if FFX_SSSR_OPTION_INVERTED_DEPTH + const FfxFloat32 far_plane = 0.0f; + return r_depth_hierarchy[pixel_coordinate] > far_plane; +#else // FFX_SSSR_OPTION_INVERTED_DEPTH + const FfxFloat32 far_plane = 1.0f; + return r_depth_hierarchy[pixel_coordinate] < far_plane; +#endif // FFX_SSSR_OPTION_INVERTED_DEPTH +} +#endif // #if defined (SSSR_BIND_SRV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_EXTRACTED_ROUGHNESS) +void StoreExtractedRoughness(FfxUInt32x2 coordinate, FfxFloat32 roughness) +{ + rw_extracted_roughness[coordinate] = roughness; +} +#endif // #if defined (SSSR_BIND_UAV_EXTRACTED_ROUGHNESS) + +#if defined (SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS) +FfxFloat32 LoadRoughnessFromMaterialParametersInput(FfxUInt32x3 coordinate) +{ + FfxFloat32 rawRoughness = r_input_material_parameters.Load(coordinate)[RoughnessChannel()]; + if (IsRoughnessPerceptual()) + { + rawRoughness *= rawRoughness; + } + + return rawRoughness; +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_MATERIAL_PARAMETERS) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +FfxBoolean IsRayIndexValid(FfxUInt32 ray_index) +{ + return ray_index < rw_ray_counter[1]; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_UAV_RAY_LIST) +FfxUInt32 GetRaylist(FfxUInt32 ray_index) +{ + return rw_ray_list[ray_index]; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_LIST) + +#if defined (SSSR_BIND_UAV_BLUE_NOISE_TEXTURE) +void FFX_SSSR_StoreBlueNoiseSample(FfxUInt32x2 coordinate, FfxFloat32x2 blue_noise_sample) +{ + rw_blue_noise_texture[coordinate] = blue_noise_sample; +} +#endif // #if defined (SSSR_BIND_UAV_BLUE_NOISE_TEXTURE) + +#if defined (SSSR_BIND_SRV_VARIANCE) +FfxFloat32 FFX_SSSR_LoadVarianceHistory(FfxInt32x3 coordinate) +{ + return r_variance.Load(coordinate).x; +} +#endif // #if defined (SSSR_BIND_SRV_VARIANCE) + +#if defined (SSSR_BIND_UAV_RADIANCE) +void FFX_SSSR_StoreRadiance(FfxUInt32x2 coordinate, FfxFloat32x4 radiance) +{ + rw_radiance[coordinate] = radiance; +} +#endif // #if defined (SSSR_BIND_UAV_RADIANCE) + +#if defined (SSSR_BIND_SRV_SOBOL_BUFFER) +FfxUInt32 FFX_SSSR_GetSobolSample(FfxUInt32x3 coordinate) +{ + return r_sobol_buffer.Load(coordinate); +} +#endif // #if defined (SSSR_BIND_SRV_SOBOL_BUFFER) + +#if defined (SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER) +FfxUInt32 FFX_SSSR_GetScramblingTile(FfxUInt32x3 coordinate) +{ + return r_scrambling_tile_buffer.Load(coordinate); +} +#endif // #if defined (SSSR_BIND_SRV_SCRAMBLING_TILE_BUFFER) + +#if defined (SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS) +void FFX_SSSR_WriteIntersectIndirectArgs(FfxUInt32 index, FfxUInt32 data) +{ + rw_intersection_pass_indirect_args[index] = data; +} +#endif // #if defined (SSSR_BIND_UAV_INTERSECTION_PASS_INDIRECT_ARGS) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +void FFX_SSSR_WriteRayCounter(FfxUInt32 index, FfxUInt32 data) +{ + rw_ray_counter[index] = data; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_UAV_RAY_COUNTER) +FfxUInt32 FFX_SSSR_GetRayCounter(FfxUInt32 index) +{ + return rw_ray_counter[index]; +} +#endif // #if defined (SSSR_BIND_UAV_RAY_COUNTER) + +#if defined (SSSR_BIND_SRV_INPUT_DEPTH) +void FFX_SSSR_GetInputDepthDimensions(FFX_PARAMETER_OUT FfxFloat32x2 image_size) +{ + r_input_depth.GetDimensions(image_size.x, image_size.y); +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_DEPTH) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void FFX_SSSR_GetDepthHierarchyMipDimensions(FfxUInt32 mip, FFX_PARAMETER_OUT FfxFloat32x2 image_size) +{ + rw_depth_hierarchy[mip].GetDimensions(image_size.x, image_size.y); +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_SRV_INPUT_DEPTH) +FfxFloat32 FFX_SSSR_GetInputDepth(FfxUInt32x2 coordinate) +{ + return r_input_depth[coordinate]; +} + +FfxFloat32x4 SpdLoadSourceImage(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return FFX_SSSR_GetInputDepth(coordinate).xxxx; +} +#endif // #if defined (SSSR_BIND_SRV_INPUT_DEPTH) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void FFX_SSSR_WriteDepthHierarchy(FfxUInt32 index, FfxUInt32x2 coordinate, FfxFloat32 data) +{ + rw_depth_hierarchy[index][coordinate] = data; +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +FfxFloat32x4 SpdLoad(FfxInt32x2 coordinate, FfxUInt32 slice) +{ + return rw_depth_hierarchy[6][coordinate].xxxx; // 5 -> 6 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) +void SpdStore(FfxInt32x2 pix, FfxFloat32x4 outValue, FfxUInt32 coordinate, FfxUInt32 slice) +{ + rw_depth_hierarchy[coordinate + 1][pix] = outValue.x; // + 1 as we store a copy of the depth buffer at index 0 +} +#endif // #if defined (SSSR_BIND_UAV_DEPTH_HIERARCHY) + +#if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) +void SpdResetAtomicCounter(FfxUInt32 slice) +{ + rw_spd_global_atomic[0] = 0; +} +#endif // #if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) + +#if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) +void FFX_SSSR_SPDIncreaseAtomicCounter(FFX_PARAMETER_INOUT FfxUInt32 spdCounter) +{ + InterlockedAdd(rw_spd_global_atomic[0], 1, spdCounter); +} +#endif // #if defined (SSSR_BIND_UAV_SPD_GLOBAL_ATOMIC) + +#if defined(SSSR_BIND_SRV_INPUT_COLOR) +FfxFloat32x3 FFX_SSSR_LoadInputColor(FfxInt32x3 coordinate) +{ + return r_input_color.Load(coordinate).xyz; +} +#endif // #if defined(SSSR_BIND_SRV_INPUT_COLOR) + +#if defined(SSSR_BIND_SRV_EXTRACTED_ROUGHNESS) +FfxFloat32 FFX_SSSR_LoadExtractedRoughness(FfxInt32x3 coordinate) +{ + return r_extracted_roughness.Load(coordinate).x; +} +#endif // #if defined(SSSR_BIND_SRV_EXTRACTED_ROUGHNESS) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_classify_tiles.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_classify_tiles.h new file mode 100644 index 00000000..0c4b730b --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_classify_tiles.h @@ -0,0 +1,121 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_sssr_common.h" + +FfxBoolean IsBaseRay(FfxUInt32x2 dispatch_thread_id, FfxUInt32 samples_per_quad) { + switch (samples_per_quad) { + case 1: + return ((dispatch_thread_id.x & 1) | (dispatch_thread_id.y & 1)) == 0; // Deactivates 3 out of 4 rays + case 2: + return (dispatch_thread_id.x & 1) == (dispatch_thread_id.y & 1); // Deactivates 2 out of 4 rays. Keeps diagonal. + default: // case 4: + return true; + } +} + +FFX_GROUPSHARED FfxUInt32 g_TileCount; + +void ClassifyTiles(FfxUInt32x2 dispatch_thread_id, FfxUInt32x2 group_thread_id, FfxFloat32 roughness) +{ + g_TileCount = 0; + + FfxBoolean is_first_lane_of_wave = ffxWaveIsFirstLane(); + + // First we figure out on a per thread basis if we need to shoot a reflection ray. + // Disable offscreen pixels + FfxBoolean needs_ray = !(dispatch_thread_id.x >= RenderSize().x || dispatch_thread_id.y >= RenderSize().y); + + // Dont shoot a ray on very rough surfaces. + FfxBoolean is_reflective_surface = IsReflectiveSurface(dispatch_thread_id, roughness); + FfxBoolean is_glossy_reflection = IsGlossyReflection(roughness); + needs_ray = needs_ray && is_glossy_reflection && is_reflective_surface; + + // Also we dont need to run the denoiser on mirror reflections. + FfxBoolean needs_denoiser = needs_ray && !IsMirrorReflection(roughness); + + // Decide which ray to keep + FfxBoolean is_base_ray = IsBaseRay(dispatch_thread_id, SamplesPerQuad()); + needs_ray = needs_ray && (!needs_denoiser || is_base_ray); // Make sure to not deactivate mirror reflection rays. + + if (TemporalVarianceGuidedTracingEnabled() && needs_denoiser && !needs_ray) { + FfxBoolean has_temporal_variance = FFX_SSSR_LoadVarianceHistory(FfxInt32x3(dispatch_thread_id, 0)) > VarianceThreshold(); + needs_ray = needs_ray || has_temporal_variance; + } + + FFX_GROUP_MEMORY_BARRIER; // Wait until g_TileCount is cleared - allow some computations before and after + + // Now we know for each thread if it needs to shoot a ray and wether or not a denoiser pass has to run on this pixel. + + if (is_glossy_reflection && is_reflective_surface) + { + FFX_ATOMIC_ADD(g_TileCount, 1); + } + + // Next we have to figure out for which pixels that ray is creating the values for. Thus, if we have to copy its value horizontal, vertical or across. + FfxBoolean require_copy = !needs_ray && needs_denoiser; // Our pixel only requires a copy if we want to run a denoiser on it but don't want to shoot a ray for it. + FfxBoolean copy_horizontal = ffxWaveReadAtLaneIndexB1(require_copy, ffxWaveLaneIndex() ^ 1) && (SamplesPerQuad() != 4) && is_base_ray; // QuadReadAcrossX + FfxBoolean copy_vertical = ffxWaveReadAtLaneIndexB1(require_copy, ffxWaveLaneIndex() ^ 2) && (SamplesPerQuad() == 1) && is_base_ray; // QuadReadAcrossY + FfxBoolean copy_diagonal = ffxWaveReadAtLaneIndexB1(require_copy, ffxWaveLaneIndex() ^ 3) && (SamplesPerQuad() == 1) && is_base_ray; // QuadReadAcrossDiagonal + + // Thus, we need to compact the rays and append them all at once to the ray list. + FfxUInt32 local_ray_index_in_wave = ffxWavePrefixCountBits(needs_ray); + FfxUInt32 wave_ray_count = ffxWaveActiveCountBits(needs_ray); + FfxUInt32 base_ray_index; + if (is_first_lane_of_wave) { + IncrementRayCounter(wave_ray_count, base_ray_index); + } + base_ray_index = ffxWaveReadLaneFirstU1(base_ray_index); + if (needs_ray) { + FfxInt32 ray_index = FfxInt32(base_ray_index + local_ray_index_in_wave); + StoreRay(ray_index, dispatch_thread_id, copy_horizontal, copy_vertical, copy_diagonal); + } + + FfxFloat32x4 intersection_output = FfxFloat32x4(0.0f, 0.0f, 0.0f, 0.0f); + if (is_reflective_surface && !is_glossy_reflection) + { + // Fall back to environment map without preparing a ray + FfxFloat32x2 uv = (dispatch_thread_id + 0.5) * InverseRenderSize(); + FfxFloat32x3 world_space_normal = FFX_SSSR_LoadWorldSpaceNormal(FfxInt32x2(dispatch_thread_id)); + FfxFloat32 z = FFX_SSSR_LoadDepth(FfxInt32x2(dispatch_thread_id), 0); + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, z); + FfxFloat32x3 view_space_ray = ScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 view_space_ray_direction = normalize(view_space_ray); + FfxFloat32x3 view_space_surface_normal = FFX_MATRIX_MULTIPLY(ViewMatrix(), FfxFloat32x4(world_space_normal, 0)).xyz; + FfxFloat32x3 view_space_reflected_direction = reflect(view_space_ray_direction, view_space_surface_normal); + FfxFloat32x3 world_space_reflected_direction = FFX_MATRIX_MULTIPLY(InvView(), FfxFloat32x4(view_space_reflected_direction, 0)).xyz; + + intersection_output.xyz = FFX_SSSR_SampleEnvironmentMap(world_space_reflected_direction, sqrt(roughness)); + } + + FFX_SSSR_StoreRadiance(dispatch_thread_id, intersection_output); + + FFX_GROUP_MEMORY_BARRIER; // Wait until g_TileCount + + if ((group_thread_id.x == 0) && (group_thread_id.y == 0) && g_TileCount > 0) + { + FfxUInt32 tile_offset; + IncrementDenoiserTileCounter(tile_offset); + StoreDenoiserTile(FfxInt32(tile_offset), FfxInt32x2(dispatch_thread_id.xy)); + } + +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_common.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_common.h new file mode 100644 index 00000000..1bd5a1c9 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_common.h @@ -0,0 +1,68 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +//=== Common functions of the SssrSample === + +void UnpackRayCoords(FfxUInt32 packed, FFX_PARAMETER_OUT FfxUInt32x2 ray_coord, FFX_PARAMETER_OUT FfxBoolean copy_horizontal, FFX_PARAMETER_OUT FfxBoolean copy_vertical, FFX_PARAMETER_OUT FfxBoolean copy_diagonal) { + ray_coord.x = (packed >> 0) & 32767; // 0b111111111111111; + ray_coord.y = (packed >> 15) & 16383; // 0b11111111111111; + copy_horizontal = FfxBoolean((packed >> 29) & 1u); + copy_vertical = FfxBoolean((packed >> 30) & 1u); + copy_diagonal = FfxBoolean((packed >> 31) & 1u); +} + +// Transforms origin to uv space +// Mat must be able to transform origin from its current space into clip space. +FfxFloat32x3 ProjectPosition(FfxFloat32x3 origin, FfxFloat32Mat4 mat) { + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(origin, 1)); + projected.xyz /= projected.w; + projected.xy = 0.5 * projected.xy + 0.5; + projected.y = (1 - projected.y); + return projected.xyz; +} + +// Mat must be able to transform origin from texture space to a linear space. +FfxFloat32x3 InvProjectPosition(FfxFloat32x3 coord, FfxFloat32Mat4 mat) { + coord.y = (1 - coord.y); + coord.xy = 2 * coord.xy - 1; + FfxFloat32x4 projected = FFX_MATRIX_MULTIPLY(mat, FfxFloat32x4(coord, 1)); + projected.xyz /= projected.w; + return projected.xyz; +} + +// Origin and direction must be in the same space and mat must be able to transform from that space into clip space. +FfxFloat32x3 ProjectDirection(FfxFloat32x3 origin, FfxFloat32x3 direction, FfxFloat32x3 screen_space_origin, FfxFloat32Mat4 mat) { + FfxFloat32x3 offsetted = ProjectPosition(origin + direction, mat); + return offsetted - screen_space_origin; +} + +FfxBoolean IsGlossyReflection(FfxFloat32 roughness) { + return roughness < RoughnessThreshold(); +} + +FfxBoolean IsMirrorReflection(FfxFloat32 roughness) { + return roughness < 0.0001; +} + +FfxFloat32x3 ScreenSpaceToViewSpace(FfxFloat32x3 screen_uv_coord) { + return InvProjectPosition(screen_uv_coord, InvProjection()); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_depth_downsample.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_depth_downsample.h new file mode 100644 index 00000000..4bf8e2b4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_depth_downsample.h @@ -0,0 +1,115 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +FFX_GROUPSHARED FfxUInt32 spdCounter; +FFX_GROUPSHARED FfxFloat32 spdIntermediate[16][16]; + +// Define fetch and store functions +FfxUInt32 SpdGetAtomicCounter() { + return spdCounter; +} + +#if FFX_HALF + +FfxFloat16x4 SpdReduce4H(FfxFloat16x4 v0, FfxFloat16x4 v1, FfxFloat16x4 v2, FfxFloat16x4 v3) { +#if FFX_SSSR_OPTION_INVERTED_DEPTH + return max(max(v0, v1), max(v2, v3)); +#else + return min(min(v0, v1), min(v2, v3)); +#endif +} + +FfxFloat16x4 SpdLoadIntermediateH(FfxUInt32 x, FfxUInt32 y) { + FfxFloat16 f = FfxFloat16(spdIntermediate[x][y]); + return FfxFloat16x4(f.x, f.x, f.x, f.x); +} + +void SpdStoreIntermediateH(FfxUInt32 x, FfxUInt32 y, FfxFloat16x4 value) { + spdIntermediate[x][y] = value.x; +} + +#endif // FFX_HALF + +void SpdStoreIntermediate(FfxUInt32 x, FfxUInt32 y, FfxFloat32x4 value) { + spdIntermediate[x][y] = value.x; +} + +FfxFloat32x4 SpdLoadIntermediate(FfxUInt32 x, FfxUInt32 y) { + FfxFloat32 f = spdIntermediate[x][y]; + return FfxFloat32x4(f.x, f.x, f.x, f.x); +} + +FfxFloat32x4 SpdReduce4(FfxFloat32x4 v0, FfxFloat32x4 v1, FfxFloat32x4 v2, FfxFloat32x4 v3) { +#if FFX_SSSR_OPTION_INVERTED_DEPTH + return max(max(v0, v1), max(v2, v3)); +#else + return min(min(v0, v1), min(v2, v3)); +#endif +} + +void SpdIncreaseAtomicCounter(FfxUInt32 slice) +{ + FFX_SSSR_SPDIncreaseAtomicCounter(spdCounter); +} + +#include "../spd/ffx_spd.h" + +FfxUInt32 GetThreadgroupCount(FfxUInt32x2 image_size){ + // Each threadgroup works on 64x64 texels + return ((image_size.x + 63) / 64) * ((image_size.y + 63) / 64); +} + +// Returns mips count of a texture with specified size +FfxFloat32 GetMipsCount(FfxFloat32x2 texture_size){ + FfxFloat32 max_dim = max(texture_size.x, texture_size.y); + return 1.0 + floor(log2(max_dim)); +} + +void DepthDownsample(FfxUInt32 group_index, FfxUInt32x3 group_id, FfxUInt32x3 dispatch_thread_id){ + FfxFloat32x2 depth_image_size = FfxFloat32x2(0.0f, 0.0f); + FFX_SSSR_GetInputDepthDimensions(depth_image_size); + // Copy most detailed level into the hierarchy and transform it. + FfxUInt32x2 u_depth_image_size = FfxUInt32x2(depth_image_size); + for (FfxInt32 i = 0; i < 2; ++i) + { + for (FfxInt32 j = 0; j < 8; ++j) + { + FfxUInt32x2 idx = FfxUInt32x2(2 * dispatch_thread_id.x + i, 8 * dispatch_thread_id.y + j); + if (idx.x < u_depth_image_size.x && idx.y < u_depth_image_size.y) + { + FFX_SSSR_WriteDepthHierarchy(0, idx, FFX_SSSR_GetInputDepth(idx)); + } + } + } + + FfxFloat32x2 image_size = FfxFloat32x2(0.0f, 0.0f); + FFX_SSSR_GetDepthHierarchyMipDimensions(0, image_size); + FfxFloat32 mips_count = GetMipsCount(image_size); + FfxUInt32 threadgroup_count = GetThreadgroupCount(FfxInt32x2(image_size)); + + SpdDownsample( + FfxUInt32x2(group_id.xy), + FfxUInt32(group_index), + FfxUInt32(mips_count), + FfxUInt32(threadgroup_count), + 0); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_intersect.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_intersect.h new file mode 100644 index 00000000..8c6966e9 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_intersect.h @@ -0,0 +1,341 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_sssr_common.h" + +#define M_PI 3.14159265358979f +#define FFX_SSSR_FLOAT_MAX 3.402823466e+38 +#define FFX_SSSR_DEPTH_HIERARCHY_MAX_MIP 6 + +FfxFloat32x3 FFX_SSSR_ScreenSpaceToViewSpace(FfxFloat32x3 screen_space_position) { + return InvProjectPosition(screen_space_position, InvProjection()); +} + +FfxFloat32x3 ScreenSpaceToWorldSpace(FfxFloat32x3 screen_space_position) { + return InvProjectPosition(screen_space_position, InvViewProjection()); +} + +// http://jcgt.org/published/0007/04/01/paper.pdf by Eric Heitz +// Input Ve: view direction +// Input alpha_x, alpha_y: roughness parameters +// Input U1, U2: uniform random numbers +// Output Ne: normal sampled with PDF D_Ve(Ne) = G1(Ve) * max(0, dot(Ve, Ne)) * D(Ne) / Ve.z +FfxFloat32x3 SampleGGXVNDF(FfxFloat32x3 Ve, FfxFloat32 alpha_x, FfxFloat32 alpha_y, FfxFloat32 U1, FfxFloat32 U2) { + // Section 3.2: transforming the view direction to the hemisphere configuration + FfxFloat32x3 Vh = normalize(FfxFloat32x3(alpha_x * Ve.x, alpha_y * Ve.y, Ve.z)); + // Section 4.1: orthonormal basis (with special case if cross product is zero) + FfxFloat32 lensq = Vh.x * Vh.x + Vh.y * Vh.y; + FfxFloat32x3 T1 = lensq > 0 ? FfxFloat32x3(-Vh.y, Vh.x, 0) * ffxRsqrt(lensq) : FfxFloat32x3(1, 0, 0); + FfxFloat32x3 T2 = cross(Vh, T1); + // Section 4.2: parameterization of the projected area + FfxFloat32 r = sqrt(U1); + FfxFloat32 phi = 2.0 * M_PI * U2; + FfxFloat32 t1 = r * cos(phi); + FfxFloat32 t2 = r * sin(phi); + FfxFloat32 s = 0.5 * (1.0 + Vh.z); + t2 = (1.0 - s) * sqrt(1.0 - t1 * t1) + s * t2; + // Section 4.3: reprojection onto hemisphere + FfxFloat32x3 Nh = t1 * T1 + t2 * T2 + sqrt(max(0.0, 1.0 - t1 * t1 - t2 * t2)) * Vh; + // Section 3.4: transforming the normal back to the ellipsoid configuration + FfxFloat32x3 Ne = normalize(FfxFloat32x3(alpha_x * Nh.x, alpha_y * Nh.y, max(0.0, Nh.z))); + return Ne; +} + +FfxFloat32x3 Sample_GGX_VNDF_Ellipsoid(FfxFloat32x3 Ve, FfxFloat32 alpha_x, FfxFloat32 alpha_y, FfxFloat32 U1, FfxFloat32 U2) { + return SampleGGXVNDF(Ve, alpha_x, alpha_y, U1, U2); +} + +FfxFloat32x3 Sample_GGX_VNDF_Hemisphere(FfxFloat32x3 Ve, FfxFloat32 alpha, FfxFloat32 U1, FfxFloat32 U2) { + return Sample_GGX_VNDF_Ellipsoid(Ve, alpha, alpha, U1, U2); +} + +FfxFloat32x3 SampleReflectionVector(FfxFloat32x3 view_direction, FfxFloat32x3 normal, FfxFloat32 roughness, FfxInt32x2 dispatch_thread_id) { + FfxFloat32x3 U; + FfxFloat32x3 N = normal; + if (abs(N.z) > 0.0) { + FfxFloat32 k = sqrt(N.y * N.y + N.z * N.z); + U.x = 0.0; U.y = -N.z / k; U.z = N.y / k; + } + else { + FfxFloat32 k = sqrt(N.x * N.x + N.y * N.y); + U.x = N.y / k; U.y = -N.x / k; U.z = 0.0; + } + + // TBN 3x3 matrix + FfxFloat32x3 TBN_row0 = U; + FfxFloat32x3 TBN_row1 = cross(N, U); + FfxFloat32x3 TBN_row2 = N; + + // TBN * -view_direction + FfxFloat32x3 view_direction_tbn = FfxFloat32x3(dot(TBN_row0, -view_direction), dot(TBN_row1, -view_direction), dot(TBN_row2, -view_direction)); + + FfxFloat32x2 u = FFX_SSSR_SampleRandomVector2D(dispatch_thread_id); + + FfxFloat32x3 sampled_normal_tbn = Sample_GGX_VNDF_Hemisphere(view_direction_tbn, roughness, u.x, u.y); + #ifdef PERFECT_REFLECTIONS + sampled_normal_tbn = FfxFloat32x3(0, 0, 1); // Overwrite normal sample to produce perfect reflection. + #endif + + FfxFloat32x3 reflected_direction_tbn = reflect(-view_direction_tbn, sampled_normal_tbn); + + // Transpose of TBN + FfxFloat32x3 TBN_col0 = FfxFloat32x3(TBN_row0[0], TBN_row1[0], TBN_row2[0]); + FfxFloat32x3 TBN_col1 = FfxFloat32x3(TBN_row0[1], TBN_row1[1], TBN_row2[1]); + FfxFloat32x3 TBN_col2 = FfxFloat32x3(TBN_row0[2], TBN_row1[2], TBN_row2[2]); + + // transpose(TBN) * reflected_direction_tbn + return FfxFloat32x3(dot(TBN_col0, reflected_direction_tbn), dot(TBN_col1, reflected_direction_tbn), dot(TBN_col2, reflected_direction_tbn)); +} + +void FFX_SSSR_InitialAdvanceRay(FfxFloat32x3 origin, FfxFloat32x3 direction, FfxFloat32x3 inv_direction, FfxFloat32x2 current_mip_resolution, FfxFloat32x2 current_mip_resolution_inv, FfxFloat32x2 floor_offset, FfxFloat32x2 uv_offset, FFX_PARAMETER_OUT FfxFloat32x3 position, FFX_PARAMETER_OUT FfxFloat32 current_t) { + FfxFloat32x2 current_mip_position = current_mip_resolution * origin.xy; + + // Intersect ray with the half box that is pointing away from the ray origin. + FfxFloat32x2 xy_plane = floor(current_mip_position) + floor_offset; + xy_plane = xy_plane * current_mip_resolution_inv + uv_offset; + + // o + d * t = p' => t = (p' - o) / d + FfxFloat32x2 t = xy_plane * inv_direction.xy - origin.xy * inv_direction.xy; + current_t = min(t.x, t.y); + position = origin + current_t * direction; +} + +FfxBoolean FFX_SSSR_AdvanceRay(FfxFloat32x3 origin, FfxFloat32x3 direction, FfxFloat32x3 inv_direction, FfxFloat32x2 current_mip_position, FfxFloat32x2 current_mip_resolution_inv, FfxFloat32x2 floor_offset, FfxFloat32x2 uv_offset, FfxFloat32 surface_z, FFX_PARAMETER_INOUT FfxFloat32x3 position, FFX_PARAMETER_INOUT FfxFloat32 current_t) { + // Create boundary planes + FfxFloat32x2 xy_plane = floor(current_mip_position) + floor_offset; + xy_plane = xy_plane * current_mip_resolution_inv + uv_offset; + FfxFloat32x3 boundary_planes = FfxFloat32x3(xy_plane, surface_z); + + // Intersect ray with the half box that is pointing away from the ray origin. + // o + d * t = p' => t = (p' - o) / d + FfxFloat32x3 t = boundary_planes * inv_direction - origin * inv_direction; + + // Prevent using z plane when shooting out of the depth buffer. +#if FFX_SSSR_OPTION_INVERTED_DEPTH + t.z = direction.z < 0 ? t.z : FFX_SSSR_FLOAT_MAX; +#else + t.z = direction.z > 0 ? t.z : FFX_SSSR_FLOAT_MAX; +#endif + + // Choose nearest intersection with a boundary. + FfxFloat32 t_min = min(min(t.x, t.y), t.z); + +#if FFX_SSSR_OPTION_INVERTED_DEPTH + // Larger z means closer to the camera. + FfxBoolean above_surface = surface_z < position.z; +#else + // Smaller z means closer to the camera. + FfxBoolean above_surface = surface_z > position.z; +#endif + + // Decide whether we are able to advance the ray until we hit the xy boundaries or if we had to clamp it at the surface. + // We use the asuint comparison to avoid NaN / Inf logic, also we actually care about bitwise equality here to see if t_min is the t.z we fed into the min3 above. + FfxBoolean skipped_tile = ffxAsUInt32(t_min) != ffxAsUInt32(t.z) && above_surface; + + // Make sure to only advance the ray if we're still above the surface. + current_t = above_surface ? t_min : current_t; + + // Advance ray + position = origin + current_t * direction; + + return skipped_tile; +} + +FfxFloat32x2 FFX_SSSR_GetMipResolution(FfxFloat32x2 screen_dimensions, FfxInt32 mip_level) { + return screen_dimensions * pow(0.5, mip_level); +} + +// Requires origin and direction of the ray to be in screen space [0, 1] x [0, 1] +FfxFloat32x3 FFX_SSSR_HierarchicalRaymarch(FfxFloat32x3 origin, FfxFloat32x3 direction, FfxBoolean is_mirror, FfxFloat32x2 screen_size, FfxInt32 most_detailed_mip, FfxUInt32 min_traversal_occupancy, FfxUInt32 max_traversal_intersections, FFX_PARAMETER_OUT FfxBoolean valid_hit) +{ + const FfxFloat32x3 inv_direction = FFX_SELECT(direction != FfxFloat32x3(0.0f, 0.0f, 0.0f), FfxFloat32x3(1.0f, 1.0f, 1.0f) / direction, FfxFloat32x3(FFX_SSSR_FLOAT_MAX, FFX_SSSR_FLOAT_MAX, FFX_SSSR_FLOAT_MAX)); + + // Start on mip with highest detail. + FfxInt32 current_mip = most_detailed_mip; + + // Could recompute these every iteration, but it's faster to hoist them out and update them. + FfxFloat32x2 current_mip_resolution = FFX_SSSR_GetMipResolution(screen_size, current_mip); + FfxFloat32x2 current_mip_resolution_inv = ffxReciprocal(current_mip_resolution); + + // Offset to the bounding boxes uv space to intersect the ray with the center of the next pixel. + // This means we ever so slightly over shoot into the next region. + FfxFloat32x2 uv_offset = 0.005 * exp2(most_detailed_mip) / screen_size; + uv_offset.x = direction.x < 0.0f ? -uv_offset.x : uv_offset.x; + uv_offset.y = direction.y < 0.0f ? -uv_offset.y : uv_offset.y; + + // Offset applied depending on current mip resolution to move the boundary to the left/right upper/lower border depending on ray direction. + FfxFloat32x2 floor_offset; + floor_offset.x = direction.x < 0.0f ? 0.0f : 1.0f; + floor_offset.y = direction.y < 0.0f ? 0.0f : 1.0f; + + // Initially advance ray to avoid immediate self intersections. + FfxFloat32 current_t; + FfxFloat32x3 position; + FFX_SSSR_InitialAdvanceRay(origin, direction, inv_direction, current_mip_resolution, current_mip_resolution_inv, floor_offset, uv_offset, position, current_t); + + FfxBoolean exit_due_to_low_occupancy = false; + FfxInt32 i = 0; + while (i < max_traversal_intersections && current_mip >= most_detailed_mip && !exit_due_to_low_occupancy) { + FfxFloat32x2 current_mip_position = current_mip_resolution * position.xy; + FfxFloat32 surface_z = FFX_SSSR_LoadDepth(FfxInt32x2(current_mip_position), current_mip); + exit_due_to_low_occupancy = !is_mirror && ffxWaveActiveCountBits(true) <= min_traversal_occupancy; + FfxBoolean skipped_tile = FFX_SSSR_AdvanceRay(origin, direction, inv_direction, current_mip_position, current_mip_resolution_inv, floor_offset, uv_offset, surface_z, position, current_t); + + // Don't increase mip further than this because we did not generate it + FfxBoolean nextMipIsOutOfRange = skipped_tile && (current_mip >= FFX_SSSR_DEPTH_HIERARCHY_MAX_MIP); + if (!nextMipIsOutOfRange) + { + current_mip += skipped_tile ? 1 : -1; + current_mip_resolution *= skipped_tile ? 0.5 : 2; + current_mip_resolution_inv *= skipped_tile ? 2 : 0.5;; + } + + ++i; + } + + valid_hit = (i <= max_traversal_intersections); + + return position; +} + +FfxFloat32 FFX_SSSR_ValidateHit(FfxFloat32x3 hit, FfxFloat32x2 uv, FfxFloat32x3 world_space_ray_direction, FfxFloat32x2 screen_size, FfxFloat32 depth_buffer_thickness) { + // Reject hits outside the view frustum + if ((hit.x < 0.0f) || (hit.y < 0.0f) || (hit.x > 1.0f) || (hit.y > 1.0f)) { + return 0.0f; + } + + // Reject the hit if we didnt advance the ray significantly to avoid immediate self reflection + FfxFloat32x2 manhattan_dist = abs(hit.xy - uv); + if((manhattan_dist.x < (2.0f / screen_size.x)) && (manhattan_dist.y < (2.0f / screen_size.y)) ) { + return 0.0; + } + + // Don't lookup radiance from the background. + FfxInt32x2 texel_coords = FfxInt32x2(screen_size * hit.xy); + FfxFloat32 surface_z = FFX_SSSR_LoadDepth(texel_coords / 2, 1); +#if FFX_SSSR_OPTION_INVERTED_DEPTH + if (surface_z == 0.0) { +#else + if (surface_z == 1.0) { +#endif + return 0; + } + + // We check if we hit the surface from the back, these should be rejected. + FfxFloat32x3 hit_normal = FFX_SSSR_LoadWorldSpaceNormal(texel_coords); + if (dot(hit_normal, world_space_ray_direction) > 0) { + return 0; + } + + FfxFloat32x3 view_space_surface = FFX_SSSR_ScreenSpaceToViewSpace(FfxFloat32x3(hit.xy, surface_z)); + FfxFloat32x3 view_space_hit = FFX_SSSR_ScreenSpaceToViewSpace(hit); + FfxFloat32 distance = length(view_space_surface - view_space_hit); + + // Fade out hits near the screen borders + FfxFloat32x2 fov = 0.05 * FfxFloat32x2(screen_size.y / screen_size.x, 1); + FfxFloat32x2 border = smoothstep(FfxFloat32x2(0.0f, 0.0f), fov, hit.xy) * (1 - smoothstep(FfxFloat32x2(1.0f, 1.0f) - fov, FfxFloat32x2(1.0f, 1.0f), hit.xy)); + FfxFloat32 vignette = border.x * border.y; + + // We accept all hits that are within a reasonable minimum distance below the surface. + // Add constant in linear space to avoid growing of the reflections toward the reflected objects. + FfxFloat32 confidence = 1.0f - smoothstep(0.0f, depth_buffer_thickness, distance); + confidence *= confidence; + + return vignette * confidence; +} + +void Intersect(FfxUInt32 group_index, FfxUInt32 group_id) +{ + FfxUInt32 ray_index = group_id * 64 + group_index; + if(!IsRayIndexValid(ray_index)) + { + return; + } + + FfxUInt32 packed_coords = GetRaylist(ray_index); + + FfxUInt32x2 coords; + FfxBoolean copy_horizontal; + FfxBoolean copy_vertical; + FfxBoolean copy_diagonal; + UnpackRayCoords(packed_coords, coords, copy_horizontal, copy_vertical, copy_diagonal); + + const FfxUInt32x2 screen_size = RenderSize(); + + FfxFloat32x2 uv = (coords + 0.5) * InverseRenderSize(); + + FfxFloat32x3 world_space_normal = FFX_SSSR_LoadWorldSpaceNormal(FfxInt32x2(coords)); + FfxFloat32 roughness = FFX_SSSR_LoadExtractedRoughness(FfxInt32x3(coords, 0)); + FfxBoolean is_mirror = IsMirrorReflection(roughness); + + FfxInt32 most_detailed_mip = is_mirror ? 0 : FfxInt32(MostDetailedMip()); + FfxFloat32x2 mip_resolution = FFX_SSSR_GetMipResolution(screen_size, most_detailed_mip); + FfxFloat32 z = FFX_SSSR_LoadDepth(FfxInt32x2(uv * mip_resolution), most_detailed_mip); + + FfxFloat32x3 screen_uv_space_ray_origin = FfxFloat32x3(uv, z); + FfxFloat32x3 view_space_ray = ScreenSpaceToViewSpace(screen_uv_space_ray_origin); + FfxFloat32x3 view_space_ray_direction = normalize(view_space_ray); + + FfxFloat32x3 view_space_surface_normal = FFX_MATRIX_MULTIPLY(ViewMatrix(), FfxFloat32x4(world_space_normal, 0)).xyz; + FfxFloat32x3 view_space_reflected_direction = SampleReflectionVector(view_space_ray_direction, view_space_surface_normal, roughness, FfxInt32x2(coords)); + FfxFloat32x3 screen_space_ray_direction = ProjectDirection(view_space_ray, view_space_reflected_direction, screen_uv_space_ray_origin, Projection()); + + //====SSSR==== + FfxBoolean valid_hit = false; + FfxFloat32x3 hit = FFX_SSSR_HierarchicalRaymarch(screen_uv_space_ray_origin, screen_space_ray_direction, is_mirror, screen_size, most_detailed_mip, MinTraversalOccupancy(), MaxTraversalIntersections(), valid_hit); + + FfxFloat32x3 world_space_origin = ScreenSpaceToWorldSpace(screen_uv_space_ray_origin); + FfxFloat32x3 world_space_hit = ScreenSpaceToWorldSpace(hit); + FfxFloat32x3 world_space_ray = world_space_hit - world_space_origin.xyz; + + FfxFloat32 confidence = valid_hit ? FFX_SSSR_ValidateHit(hit, uv, world_space_ray, screen_size, DepthBufferThickness()) : 0; + FfxFloat32 world_ray_length = max(0, length(world_space_ray)); + + FfxFloat32x3 reflection_radiance = FfxFloat32x3(0.0f, 0.0f, 0.0f); + if (confidence > 0.0f) { + // Found an intersection with the depth buffer -> We can lookup the color from lit scene. + reflection_radiance = FFX_SSSR_LoadInputColor(FfxInt32x3(screen_size * hit.xy, 0)); + } + + // Sample environment map. + FfxFloat32x3 world_space_reflected_direction = FFX_MATRIX_MULTIPLY(InvView(), FfxFloat32x4(view_space_reflected_direction, 0)).xyz; + FfxFloat32x3 environment_lookup = FFX_SSSR_SampleEnvironmentMap(world_space_reflected_direction, 0.0f); + reflection_radiance = ffxLerp(environment_lookup, reflection_radiance, confidence); + + FfxFloat32x4 new_sample = FfxFloat32x4(reflection_radiance, world_ray_length); + + FFX_SSSR_StoreRadiance(coords, new_sample); + + FfxUInt32x2 copy_target = coords ^ 1; // Flip last bit to find the mirrored coords along the x and y axis within a quad. + if (copy_horizontal) { + FfxUInt32x2 copy_coords = FfxUInt32x2(copy_target.x, coords.y); + FFX_SSSR_StoreRadiance(copy_coords, new_sample); + } + if (copy_vertical) { + FfxUInt32x2 copy_coords = FfxUInt32x2(coords.x, copy_target.y); + FFX_SSSR_StoreRadiance(copy_coords, new_sample); + } + if (copy_diagonal) { + FfxUInt32x2 copy_coords = copy_target; + FFX_SSSR_StoreRadiance(copy_coords, new_sample); + } +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_prepare_blue_noise_texture.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_prepare_blue_noise_texture.h new file mode 100644 index 00000000..ddb4400a --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_prepare_blue_noise_texture.h @@ -0,0 +1,59 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_sssr_common.h" + +#define GOLDEN_RATIO 1.61803398875f + +// Blue Noise Sampler by Eric Heitz. Returns a value in the range [0, 1]. +FfxFloat32 SampleRandomNumber(FfxUInt32 pixel_i, FfxUInt32 pixel_j, FfxUInt32 sample_index, FfxUInt32 sample_dimension) { + // Wrap arguments + pixel_i = pixel_i & 127u; + pixel_j = pixel_j & 127u; + sample_index = sample_index & 255u; + sample_dimension = sample_dimension & 255u; + + // xor index based on optimized ranking + const FfxUInt32 ranked_sample_index = sample_index; + + // Fetch value in sequence + FfxUInt32 value = FFX_SSSR_GetSobolSample(FfxUInt32x3(sample_dimension, ranked_sample_index * 256u, 0)); + + + // If the dimension is optimized, xor sequence value based on optimized scrambling + FfxUInt32 originalIndex = (sample_dimension % 8u) + (pixel_i + pixel_j * 128u) * 8u; + value = value ^ FFX_SSSR_GetScramblingTile(FfxUInt32x3(originalIndex % 512u, originalIndex / 512u, 0)); + + // Convert to FfxFloat32 and return + return (value + 0.5f) / 256.0f; +} + +FfxFloat32x2 SampleRandomVector2D(FfxUInt32x2 pixel) { + FfxFloat32x2 u = FfxFloat32x2( + FFX_MODULO(SampleRandomNumber(pixel.x, pixel.y, 0, 0u) + (FrameIndex() & 0xFFu) * GOLDEN_RATIO, 1.0f), + FFX_MODULO(SampleRandomNumber(pixel.x, pixel.y, 0, 1u) + (FrameIndex() & 0xFFu) * GOLDEN_RATIO, 1.0f)); + return u; +} + +void PrepareBlueNoiseTexture(FfxUInt32x2 dispatch_thread_id) { + FFX_SSSR_StoreBlueNoiseSample(dispatch_thread_id, SampleRandomVector2D(dispatch_thread_id)); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_prepare_indirect_args.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_prepare_indirect_args.h new file mode 100644 index 00000000..22d52991 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_prepare_indirect_args.h @@ -0,0 +1,44 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +void PrepareIndirectArgs() { + { // Prepare intersection args + FfxUInt32 ray_count = FFX_SSSR_GetRayCounter(0); + + FFX_SSSR_WriteIntersectIndirectArgs(0, (ray_count + 63) / 64); + FFX_SSSR_WriteIntersectIndirectArgs(1, 1); + FFX_SSSR_WriteIntersectIndirectArgs(2, 1); + + FFX_SSSR_WriteRayCounter(0, 0); + FFX_SSSR_WriteRayCounter(1, ray_count); + } + { // Prepare denoiser args + FfxUInt32 tile_count = FFX_SSSR_GetRayCounter(2); + + FFX_SSSR_WriteIntersectIndirectArgs(3, tile_count); + FFX_SSSR_WriteIntersectIndirectArgs(4, 1); + FFX_SSSR_WriteIntersectIndirectArgs(5, 1); + + FFX_SSSR_WriteRayCounter(2, 0); + FFX_SSSR_WriteRayCounter(3, tile_count); + } +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_resources.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_resources.h new file mode 100644 index 00000000..bea837d4 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/sssr/ffx_sssr_resources.h @@ -0,0 +1,61 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#ifndef FFX_SSSR2_RESOURCES_H +#define FFX_SSSR2_RESOURCES_H + +#if defined(FFX_CPU) || defined(FFX_GPU) +#define FFX_SSSR_RESOURCE_IDENTIFIER_NULL 0 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INPUT_COLOR 1 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INPUT_DEPTH 2 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INPUT_MOTION_VECTORS 3 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INPUT_NORMAL 4 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INPUT_MATERIAL_PARAMETERS 5 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INPUT_ENVIRONMENT_MAP 6 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INPUT_BRDF_TEXTURE 7 +#define FFX_SSSR_RESOURCE_IDENTIFIER_OUTPUT 8 +#define FFX_SSSR_RESOURCE_IDENTIFIER_DEPTH_HIERARCHY 9 +#define FFX_SSSR_RESOURCE_IDENTIFIER_RADIANCE 10 +#define FFX_SSSR_RESOURCE_IDENTIFIER_RADIANCE_HISTORY 11 +#define FFX_SSSR_RESOURCE_IDENTIFIER_VARIANCE 12 +#define FFX_SSSR_RESOURCE_IDENTIFIER_RAY_LIST 13 +#define FFX_SSSR_RESOURCE_IDENTIFIER_DENOISER_TILE_LIST 14 +#define FFX_SSSR_RESOURCE_IDENTIFIER_RAY_COUNTER 15 +#define FFX_SSSR_RESOURCE_IDENTIFIER_INTERSECTION_PASS_INDIRECT_ARGS 16 +#define FFX_SSSR_RESOURCE_IDENTIFIER_EXTRACTED_ROUGHNESS 17 +#define FFX_SSSR_RESOURCE_IDENTIFIER_RADIANCE_0 18 +#define FFX_SSSR_RESOURCE_IDENTIFIER_RADIANCE_1 19 +#define FFX_SSSR_RESOURCE_IDENTIFIER_VARIANCE_0 20 +#define FFX_SSSR_RESOURCE_IDENTIFIER_VARIANCE_1 21 +#define FFX_SSSR_RESOURCE_IDENTIFIER_SOBOL_BUFFER 22 +#define FFX_SSSR_RESOURCE_IDENTIFIER_RANKING_TILE_BUFFER 23 +#define FFX_SSSR_RESOURCE_IDENTIFIER_SCRAMBLING_TILE_BUFFER 24 +#define FFX_SSSR_RESOURCE_IDENTIFIER_BLUE_NOISE_TEXTURE 25 +#define FFX_SSSR_RESOURCE_IDENTIFIER_SPD_GLOBAL_ATOMIC 26 +#define FFX_SSSR_RESOURCE_IDENTIFIER_COUNT 27 + +#define FFX_SSSR_CONSTANTBUFFER_IDENTIFIER_SSSR 0 +#define FFX_SSSR_CONSTANTBUFFER_IDENTIFIER_COUNT 1 + +#endif // #if defined(FFX_CPU) || defined(FFX_GPU) + +#endif //!defined( FFX_SSSR_RESOURCES_H ) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/vrs/CMakeCompileVRSShaders.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/vrs/CMakeCompileVRSShaders.txt new file mode 100644 index 00000000..825f43e6 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/vrs/CMakeCompileVRSShaders.txt @@ -0,0 +1,46 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(VRS_BASE_ARGS + -reflection -deps=gcc -DFFX_GPU=1) + +set(VRS_PERMUTATION_ARGS + -DFFX_VRS_OPTION_ADDITIONALSHADINGRATES={0,1} + -DFFX_VARIABLESHADING_TILESIZE={8,16,32}) + +set(VRS_INCLUDE_ARGS + "${FFX_GPU_PATH}" + "${FFX_GPU_PATH}/vrs") + +if (NOT VRS_SHADER_EXT) + set(VRS_SHADER_EXT *) +endif() + +file(GLOB VRS_SHADERS + "shaders/vrs/ffx_vrs_imagegen_pass.${VRS_SHADER_EXT}") + +compile_shaders_with_depfile( + "${FFX_SC_EXECUTABLE}" + "${VRS_BASE_ARGS}" "${VRS_API_BASE_ARGS}" "${VRS_PERMUTATION_ARGS}" "${VRS_INCLUDE_ARGS}" + "${VRS_SHADERS}" "${FFX_PASS_SHADER_OUTPUT_PATH}" VRS_PERMUTATION_OUTPUTS) + +add_shader_output("${VRS_PERMUTATION_OUTPUTS}") diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_glsl.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_glsl.h new file mode 100644 index 00000000..1df0e018 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/gpu/vrs/ffx_vrs_callbacks_glsl.h @@ -0,0 +1,143 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "ffx_vrs_resources.h" + +#if defined(FFX_GPU) +#include "ffx_core.h" + +#ifndef FFX_PREFER_WAVE64 +#define FFX_PREFER_WAVE64 +#endif // #ifndef FFX_PREFER_WAVE64 + +#if defined(VRS_BIND_CB_VRS) + layout(set = 0, binding = VRS_BIND_CB_VRS, std140) uniform cbVRS_t + { + FfxFloat32x2 motionVectorScale; + FfxFloat32 varianceCutoff; + FfxFloat32 motionFactor; + FfxInt32x2 resolution; + FfxUInt32 tileSize; + } cbVRS; + +#endif + +FfxInt32x2 Resolution() +{ +#if defined(VRS_BIND_CB_VRS) + return cbVRS.resolution; +#else + return FfxInt32x2(0, 0); +#endif +} + +FfxUInt32 TileSize() +{ +#if defined(VRS_BIND_CB_VRS) + return cbVRS.tileSize; +#else + return 0; +#endif +} + +FfxFloat32 VarianceCutoff() +{ +#if defined(VRS_BIND_CB_VRS) + return cbVRS.varianceCutoff; +#else + return 0.f; +#endif +} + +FfxFloat32 MotionFactor() +{ +#if defined(VRS_BIND_CB_VRS) + return cbVRS.motionFactor; +#else + return 0.f +#endif +} + +FfxFloat32x2 MotionVectorScale() +{ +#if defined(VRS_BIND_CB_VRS) + return cbVRS.motionVectorScale; +#else + return FfxFloat32x2(0.0f); +#endif +} + +// SRVs +#if defined VRS_BIND_SRV_INPUT_COLOR + layout (set = 0, binding = VRS_BIND_SRV_INPUT_COLOR) uniform texture2D r_input_color; +#endif +#if defined VRS_BIND_SRV_INPUT_MOTIONVECTORS + layout (set = 0, binding = VRS_BIND_SRV_INPUT_MOTIONVECTORS) uniform texture2D r_input_velocity; +#endif +#if defined VRS_BIND_SRV_OUTPUT_VRSIMAGE + layout (set = 0, binding = VRS_BIND_SRV_OUTPUT_VRSIMAGE) uniform texture2D r_vrsimage_output; +#endif + +// UAV declarations +#if defined VRS_BIND_UAV_INPUT_COLOR + layout (set = 0, binding = VRS_BIND_UAV_INPUT_COLOR, rgba32f) uniform image2D rw_input_color; +#endif +#if defined VRS_BIND_UAV_INPUT_MOTIONVECTORS + layout (set = 0, binding = VRS_BIND_UAV_INPUT_MOTIONVECTORS, rg16f) uniform image2D rw_input_velocity; +#endif +#if defined VRS_BIND_UAV_OUTPUT_VRSIMAGE + layout (set = 0, binding = VRS_BIND_UAV_OUTPUT_VRSIMAGE, r8ui) uniform uimage2D rw_vrsimage_output; +#endif + + +#if defined(VRS_BIND_SRV_INPUT_COLOR) +// read a value from previous frames color buffer and return luminance +FfxFloat32 ReadLuminance(FfxInt32x2 pos) +{ + FfxFloat32x3 color = texelFetch(r_input_color, pos, 0).xyz; + + // return color value converted to grayscale + return dot(color, FfxFloat32x3(0.30, 0.59, 0.11)); + // in some cases using different weights, linearizing the color values + // or multiplying luminance with a value based on specularity or depth + // may yield better results +} +#endif // #if defined(VRS_BIND_SRV_INPUT_COLOR) + +#if defined(VRS_BIND_SRV_INPUT_MOTIONVECTORS) +// read per pixel motion vectors and convert them to pixel-space +FfxFloat32x2 ReadMotionVec2D(FfxInt32x2 pos) +{ + FfxFloat32x2 velocity = texelFetch(r_input_velocity, pos, 0).xy * MotionVectorScale(); + // return 0 to not use motion vectors + return velocity * Resolution(); +} +#endif // #if defined(VRS_BIND_SRV_INPUT_MOTIONVECTORS) + +#if defined(VRS_BIND_UAV_OUTPUT_VRSIMAGE) +void WriteVrsImage(FfxInt32x2 pos, FfxUInt32 value) +{ + imageStore(rw_vrsimage_output, pos, FfxUInt32x4(value)); +} +#endif // #if defined(VRS_BIND_UAV_OUTPUT_VRSIMAGE) + +#endif // #if defined(FFX_GPU) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/dx12/license.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/dx12/license.txt new file mode 100644 index 00000000..fd1f95e8 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/dx12/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2024 Microsoft + +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/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/gdk/license.txt b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/gdk/license.txt new file mode 100644 index 00000000..55b20717 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/gdk/license.txt @@ -0,0 +1,23 @@ +License Text (MIT License) + +This file is part of the FidelityFX SDK. + +Copyright (C) 2024 Advanced Micro Devices, Inc. + +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/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/vk/ffx_vk.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/vk/ffx_vk.h new file mode 100644 index 00000000..b31d5892 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/backends/vk/ffx_vk.h @@ -0,0 +1,370 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup VKBackend Vulkan Backend +/// FidelityFX SDK native backend implementation for Vulkan. +/// +/// @ingroup Backends + +#pragma once + +#include +#include + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// FFX specific callback type when submitting a command buffer to a queue. +typedef VkResult (*PFN_vkQueueSubmitFFX)(uint32_t submitCount, const VkSubmitInfo* pSubmits, VkFence fence); + +typedef struct VkQueueInfoFFX +{ + VkQueue queue; + uint32_t familyIndex; + PFN_vkQueueSubmitFFX submitFunc; +} VkQueueInfoFFX; + + +typedef enum VkCompositonModeFFX +{ + VK_COMPOSITION_MODE_NOT_FORCED_FFX, + VK_COMPOSITION_MODE_GAME_QUEUE_FFX, + VK_COMPOSITION_MODE_PRESENT_QUEUE_FFX, +} VkCompositonModeFFX; + +/// Structure holding additional information to effectively replace the game swapchain by the frame interpolation one. +/// Some notes on the queues: +/// - please pass the queue, its family (for queue family ownership transfer purposes) and an optional function if you want to control concurrent submissions +/// - game queue: the queue where the replacement of vkQueuePresentKHR is called. This queue should have Graphics and Compute capabilities (Transfer is implied as per Vulkan specification). +/// It can be shared with the engine. No Submit function is necessary. +/// The code assumes that the UI texture is owned by that queue family when present is called. +/// - async compute queue: optional queue with Compute capability (Transfer is implied as per Vulkan specification). If used by the engine, prefer not to enable the async compute path of FSR3 Frame interpolation. +/// - present queue: queue with Graphics, Compute or Transfer capability, and Present support. This queue cannot be used by the engine. Otherwise, some deadlock can occur. +/// - image acquire queue: this one doesn't need any capability. Strongly prefer a queue not used by the engine. The main graphics queue can work too but it might delay the signaling of the semaphore/fence when acquiring a new image, negatively impacting the performance. +typedef struct VkFrameInterpolationInfoFFX +{ + VkPhysicalDevice physicalDevice; + VkDevice device; + VkQueueInfoFFX gameQueue; + VkQueueInfoFFX asyncComputeQueue; + VkQueueInfoFFX presentQueue; + VkQueueInfoFFX imageAcquireQueue; + VkCompositonModeFFX compositionMode; + const VkAllocationCallbacks* pAllocator; +} VkFrameInterpolationInfoFFX; + +/// Query how much memory is required for the Vulkan backend's scratch buffer. +/// +/// @param [in] physicalDevice A pointer to the VkPhysicalDevice device. +/// @param [in] maxContexts The maximum number of simultaneous effect contexts that will share the backend. +/// (Note that some effects contain internal contexts which count towards this maximum) +/// +/// @returns +/// The size (in bytes) of the required scratch memory buffer for the VK backend. +/// +/// @ingroup VKBackend +FFX_API size_t ffxGetScratchMemorySizeVK(VkPhysicalDevice physicalDevice, size_t maxContexts); + +/// Convenience structure to hold all VK-related device information +typedef struct VkDeviceContext { + VkDevice vkDevice; /// The Vulkan device + VkPhysicalDevice vkPhysicalDevice; /// The Vulkan physical device + PFN_vkGetDeviceProcAddr vkDeviceProcAddr; /// The device's function address table +} VkDeviceContext; + +/// Create a FfxDevice from a VkDevice. +/// +/// @param [in] vkDeviceContext A pointer to a VKDeviceContext that holds all needed information +/// +/// @returns +/// An abstract FidelityFX device. +/// +/// @ingroup VKBackend +FFX_API FfxDevice ffxGetDeviceVK(VkDeviceContext* vkDeviceContext); + +/// Populate an interface with pointers for the VK backend. +/// +/// @param [out] backendInterface A pointer to a FfxInterface structure to populate with pointers. +/// @param [in] device A pointer to the VkDevice device. +/// @param [in] scratchBuffer A pointer to a buffer of memory which can be used by the DirectX(R)12 backend. +/// @param [in] scratchBufferSize The size (in bytes) of the buffer pointed to by scratchBuffer. +/// @param [in] maxContexts The maximum number of simultaneous effect contexts that will share the backend. +/// (Note that some effects contain internal contexts which count towards this maximum) +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_INVALID_POINTER The interface pointer was NULL. +/// +/// @ingroup VKBackend +FFX_API FfxErrorCode ffxGetInterfaceVK( + FfxInterface* backendInterface, + FfxDevice device, + void* scratchBuffer, + size_t scratchBufferSize, + size_t maxContexts); + +/// Create a FfxCommandList from a VkCommandBuffer. +/// +/// @param [in] cmdBuf A pointer to the Vulkan command buffer. +/// +/// @returns +/// An abstract FidelityFX command list. +/// +/// @ingroup VKBackend +FFX_API FfxCommandList ffxGetCommandListVK(VkCommandBuffer cmdBuf); + +/// Create a FfxPipeline from a VkPipeline. +/// +/// @param [in] pipeline A pointer to the Vulkan pipeline. +/// +/// @returns +/// An abstract FidelityFX pipeline. +/// +/// @ingroup VKBackend +FFX_API FfxPipeline ffxGetPipelineVK(VkPipeline pipeline); + +/// Fetch a FfxResource from a GPUResource. +/// +/// @param [in] vkResource A pointer to the (agnostic) VK resource. +/// @param [in] ffxResDescription An FfxResourceDescription for the resource representation. +/// @param [in] ffxResName (optional) A name string to identify the resource in debug mode. +/// @param [in] state The state the resource is currently in. +/// +/// @returns +/// An abstract FidelityFX resources. +/// +/// @ingroup VKBackend +FFX_API FfxResource ffxGetResourceVK(void* vkResource, + FfxResourceDescription ffxResDescription, + const wchar_t* ffxResName, + FfxResourceStates state = FFX_RESOURCE_STATE_COMPUTE_READ); + +/// Fetch a FfxSurfaceFormat from a VkFormat. +/// +/// @param [in] format The VkFormat to convert to FfxSurfaceFormat. +/// +/// @returns +/// An FfxSurfaceFormat. +/// +/// @ingroup VKBackend +FFX_API FfxSurfaceFormat ffxGetSurfaceFormatVK(VkFormat format); + +/// Fetch a FfxResourceDescription from an existing VkBuffer. +/// +/// @param [in] buffer The VkBuffer resource to create a FfxResourceDescription for. +/// @param [in] createInfo The VkBufferCreateInfo of the buffer +/// @param [in] additionalUsages Optional FfxResourceUsage flags needed for select resource mapping. +/// +/// @returns +/// An FfxResourceDescription. +/// +/// @ingroup VKBackend +FFX_API FfxResourceDescription ffxGetBufferResourceDescriptionVK(const VkBuffer buffer, + const VkBufferCreateInfo createInfo, + FfxResourceUsage additionalUsages = FFX_RESOURCE_USAGE_READ_ONLY); + +/// Fetch a FfxResourceDescription from an existing VkImage. +/// +/// @param [in] image The VkImage resource to create a FfxResourceDescription for. +/// @param [in] createInfo The VkImageCreateInfo of the buffer +/// @param [in] additionalUsages Optional FfxResourceUsage flags needed for select resource mapping. +/// +/// @returns +/// An FfxResourceDescription. +/// +/// @ingroup VKBackend +FFX_API FfxResourceDescription ffxGetImageResourceDescriptionVK(const VkImage image, + const VkImageCreateInfo createInfo, + FfxResourceUsage additionalUsages = FFX_RESOURCE_USAGE_READ_ONLY); + +/// Fetch a FfxCommandQueue from an existing VkQueue. +/// +/// @param [in] commandQueue The VkQueue to create a FfxCommandQueue from. +/// +/// @returns +/// An FfxCommandQueue. +/// +/// @ingroup VKBackend +FFX_API FfxCommandQueue ffxGetCommandQueueVK(VkQueue commandQueue); + +/// Fetch a FfxSwapchain from an existing VkSwapchainKHR. +/// +/// @param [in] pSwapchain The VkSwapchainKHR to create a FfxSwapchain from. +/// +/// @returns +/// An FfxSwapchain. +/// +/// @ingroup VKBackend +FFX_API FfxSwapchain ffxGetSwapchainVK(VkSwapchainKHR swapchain); + +/// Fetch a VkSwapchainKHR from an existing FfxSwapchain. +/// +/// @param [in] ffxSwapchain The FfxSwapchain to fetch an VkSwapchainKHR from. +/// +/// @returns +/// An VkSwapchainKHR object. +/// +/// @ingroup VKBackend +FFX_API VkSwapchainKHR ffxGetVKSwapchain(FfxSwapchain ffxSwapchain); + +/// Replaces the current swapchain with the provided FfxSwapchain. +/// +/// @param [in] gameQueue The FfxCommandQueue presentation will occur on. +/// @param [in,out] gameSwapChain The current FfxSwapchain to replace, optional. If not NULL, the swapchain will be destroyed. On return, it will hold the FfxSwapchain to use for frame interpolation presentation. +/// @param [in] swapchainCreateInfo The VkSwapchainCreateInfoKHR of the current swapchain. Its oldSwapchain member should be VK_NULL_HANDLE or the same as gameSwapChain. +/// @param [in] frameInterpolationInfo The VkFrameInterpolationInfoFFX containing additional information for swapchain replacement. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT One of the parameters is invalid. If the returned gameSwapChain is NULL, the old swapchain has been destroyed. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR Internal generic error. If the returned gameSwapChain is NULL, the old swapchain has been destroyed. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxErrorCode ffxReplaceSwapchainForFrameinterpolationVK(FfxCommandQueue gameQueue, + FfxSwapchain& gameSwapChain, + const VkSwapchainCreateInfoKHR* swapchainCreateInfo, + const VkFrameInterpolationInfoFFX* frameInterpolationInfo); + +/// Waits for the FfxSwapchain to complete presentation. +/// +/// @param [in] gameSwapChain The FfxSwapchain to wait on. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT Could not query the interface for the frame interpolation swap chain. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxErrorCode ffxWaitForPresents(FfxSwapchain gameSwapChain); + +/// Registers a FfxResource to use for UI with the provided FfxSwapchain. +/// +/// @param [in] gameSwapChain The FfxSwapchain to to register the UI resource with. +/// @param [in] uiResource The FfxResource representing the UI resource. +/// @param [in] flags A set of FfxUiCompositionFlags. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT Could not query the interface for the frame interpolation swap chain. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxErrorCode ffxRegisterFrameinterpolationUiResourceVK(FfxSwapchain gameSwapChain, FfxResource uiResource, uint32_t flags); + +/// Fetches a FfxCommandList from the FfxSwapchain. +/// +/// @param [in] gameSwapChain The FfxSwapchain to get a FfxCommandList from. +/// @param [out] gameCommandlist The FfxCommandList from the provided FfxSwapchain. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT Could not query the interface for the frame interpolation swap chain. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxErrorCode ffxGetFrameinterpolationCommandlistVK(FfxSwapchain gameSwapChain, FfxCommandList& gameCommandlist); + +/// Fetches a FfxResource representing the backbuffer from the FfxSwapchain. +/// +/// @param [in] gameSwapChain The FfxSwapchain to get a FfxResource backbuffer from. +/// +/// @returns +/// An abstract FidelityFX resources for the swapchain backbuffer. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxResource ffxGetFrameinterpolationTextureVK(FfxSwapchain gameSwapChain); + +/// Sets a FfxFrameGenerationConfig to the internal FrameInterpolationSwapChain (in the backend). +/// +/// @param [in] config The FfxFrameGenerationConfig to set. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT Could not query the interface for the frame interpolation swap chain. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxErrorCode ffxSetFrameGenerationConfigToSwapchainVK(FfxFrameGenerationConfig const* config); + +//enum values should match enum FfxApiConfigureFrameGenerationSwapChainKeyVK +typedef enum FfxFrameInterpolationSwapchainConfigureKey +{ + FFX_FI_SWAPCHAIN_CONFIGURE_KEY_WAITCALLBACK = 0, + FFX_FI_SWAPCHAIN_CONFIGURE_KEY_FRAMEPACINGTUNING = 2, +} FfxFrameInterpolationSwapchainConfigureKey; + +/// Configures FfxSwapchain via KeyValue API post FfxSwapchain context creation +/// +/// @param [in] gameSwapChain The FfxSwapchain to configure via KeyValue API +/// @param [in] key The FfxFrameInterpolationSwapchainConfigureKey is key +/// @param [in] valuePtr The pointer to value. What this pointer deference to depends on key. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT Could not query the interface for the frame interpolation swap chain. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxErrorCode ffxConfigureFrameInterpolationSwapchainVK(FfxSwapchain gameSwapChain, FfxFrameInterpolationSwapchainConfigureKey key, void* valuePtr); + +/// Query how much GPU memory created by FfxSwapchain. This excludes GPU memory created by the VkSwapchain (ie. size of backbuffers). +/// +/// @param [in] gameSwapChain The FfxSwapchain to configure via KeyValue API +/// @param [in out] vramUsage The FfxEffectMemoryUsage is the GPU memory created by FrameInterpolationSwapchain +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT Could not query the interface for the frame interpolation swap chain. +/// +/// @ingroup VKFrameInterpolation +FFX_API FfxErrorCode ffxFrameInterpolationSwapchainGetGpuMemoryUsageVK(FfxSwapchain gameSwapChain, FfxEffectMemoryUsage* vramUsage); + +typedef VkResult (*PFN_vkCreateSwapchainFFX)(VkDevice device, const VkSwapchainCreateInfoKHR* pCreateInfo, const VkAllocationCallbacks* pAllocator, VkSwapchainKHR* pSwapchain, const VkFrameInterpolationInfoFFX* pFrameInterpolationInfo); + +/// Function to get he number of presents. This is useful when using frame interpolation +typedef uint64_t (*PFN_getLastPresentCountFFX)(VkSwapchainKHR); + +/// Structure holding the replacement function pointers for frame interpolation to work +/// Not all extensions are supported for now +/// Regarding specific functions: +/// - queuePresentKHR: when using this one, the presenting image should be in VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL state +/// - getLastPresentCount: this function isn't part of Vulkan but the engine can use it to get the real number of presented frames since the swapchain creation +struct FfxSwapchainReplacementFunctions +{ + PFN_vkCreateSwapchainFFX createSwapchainFFX; + PFN_vkDestroySwapchainKHR destroySwapchainKHR; + PFN_vkGetSwapchainImagesKHR getSwapchainImagesKHR; + PFN_vkAcquireNextImageKHR acquireNextImageKHR; + PFN_vkQueuePresentKHR queuePresentKHR; + PFN_vkSetHdrMetadataEXT setHdrMetadataEXT; + PFN_getLastPresentCountFFX getLastPresentCountFFX; +}; +FFX_API FfxErrorCode ffxGetSwapchainReplacementFunctionsVK(FfxDevice device, FfxSwapchainReplacementFunctions* functions); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_blur.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_blur.h new file mode 100644 index 00000000..8012070d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_blur.h @@ -0,0 +1,200 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup ffxBlur FidelityFX Blur +/// FidelityFX Blur runtime library +/// +/// @ingroup SDKComponents + +//------------------------------------------------------------------------------------------------------------------------------ +// +// ABOUT +// ===== +// AMD FidelityFX Blur is a collection of blurring effects implemented on compute shaders, hand-optimized for maximum performance. +// FFX-Blur includes +// - Gaussian Blur w/ large kernel support (up to 21x21) +// +//============================================================================================================================== + +#pragma once + +#include + +/// FidelityFX Blur major version. +/// +/// @ingroup ffxBlur +#define FFX_BLUR_VERSION_MAJOR (1) + +/// FidelityFX Blur minor version. +/// +/// @ingroup ffxBlur +#define FFX_BLUR_VERSION_MINOR (1) + +/// FidelityFX Blur patch version. +/// +/// @ingroup ffxBlur +#define FFX_BLUR_VERSION_PATCH (0) + +/// FidelityFX Blur context count +/// +/// Defines the number of internal effect contexts required by Blur +/// +/// @ingroup ffxBlur +#define FFX_BLUR_CONTEXT_COUNT 1 + +/// The size of the context specified in uint32_t units. +/// +/// @ingroup ffxBlur +#define FFX_BLUR_CONTEXT_SIZE (1024) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// Enum to specify which blur pass (currently only one). +/// +/// @ingroup ffxBlur +typedef enum FfxBlurPass +{ + FFX_BLUR_PASS_BLUR = 0, ///< A pass which which blurs the input + FFX_BLUR_PASS_COUNT ///< The number of passes in the Blur effect +} FfxBlurPass; + +/// Use this macro for FfxBlurContextDescription::kernelSizes to enable all kernel sizes. +/// +/// @ingroup ffxBlur +#define FFX_BLUR_KERNEL_SIZE_ALL ((1 << FFX_BLUR_KERNEL_SIZE_COUNT) - 1) + +typedef enum FfxBlurKernelPermutation +{ + FFX_BLUR_KERNEL_PERMUTATION_0 = (1 << 0), ///< Sigma value of 1.6 used for generation of Gaussian kernel. + FFX_BLUR_KERNEL_PERMUTATION_1 = (1 << 1), ///< Sigma value of 2.8 used for generation of Gaussian kernel. + FFX_BLUR_KERNEL_PERMUTATION_2 = (1 << 2), ///< Sigma value of 4.0 used for generation of Gaussian kernel. +} FfxBlurKernelPermutation; +#define FFX_BLUR_KERNEL_PERMUTATION_COUNT 3 + +/// Use this macro for FfxBlurContextDescription::sigmaPermutations to enable all sigma permutations. +/// +/// @ingroup ffxBlur +#define FFX_BLUR_KERNEL_PERMUTATIONS_ALL ((1 << FFX_BLUR_KERNEL_PERMUTATION_COUNT) - 1) + +/// Enum to specify the size of the blur kernel. Use logical OR to enable multiple kernels +/// when setting the FfxBlurContextDescription::kernelSizes parameter prior to calling +/// ffxBlurContextCreate. +/// +/// @ingroup ffxBlur +typedef enum FfxBlurKernelSize +{ + FFX_BLUR_KERNEL_SIZE_3x3 = (1 << 0), + FFX_BLUR_KERNEL_SIZE_5x5 = (1 << 1), + FFX_BLUR_KERNEL_SIZE_7x7 = (1 << 2), + FFX_BLUR_KERNEL_SIZE_9x9 = (1 << 3), + FFX_BLUR_KERNEL_SIZE_11x11 = (1 << 4), + FFX_BLUR_KERNEL_SIZE_13x13 = (1 << 5), + FFX_BLUR_KERNEL_SIZE_15x15 = (1 << 6), + FFX_BLUR_KERNEL_SIZE_17x17 = (1 << 7), + FFX_BLUR_KERNEL_SIZE_19x19 = (1 << 8), + FFX_BLUR_KERNEL_SIZE_21x21 = (1 << 9) +} FfxBlurKernelSize; +#define FFX_BLUR_KERNEL_SIZE_COUNT 10 + +/// Enum to specify whether to initialize the FP32 or FP16 bit permutation of the blur shader(s). +/// Use this when setting the FfxBlurContextDescription::floatPrecision parameter prior to calling +/// ffxBlurContextCreate. +/// +/// @ingroup ffxBlur +typedef enum FfxBlurFloatPrecision +{ + FFX_BLUR_FLOAT_PRECISION_32BIT = 0, + FFX_BLUR_FLOAT_PRECISION_16BIT = 1, + FFX_BLUR_FLOAT_PRECISION_COUNT = 2 +} FfxBlurFloatPrecision; + +typedef uint32_t FfxBlurKernelPermutations; +typedef uint32_t FfxBlurKernelSizes; + +/// FfxBlurContextDescription struct is used to create/initialize an FfxBlurContext. +/// +/// @ingroup ffxBlur +typedef struct FfxBlurContextDescription +{ + FfxBlurKernelPermutations kernelPermutations; ///< A bit mask of FfxBlurKernelPermutation values to indicate which kernels to enable for use. + FfxBlurKernelSizes kernelSizes; ///< A bit mask of FfxBlurKernelSize values to indicated which kernel sizes to enable for use. + FfxBlurFloatPrecision floatPrecision; ///< A flag indicating the desired floating point precision for use in ffxBlurContextDispatch + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX. +} FfxBlurContextDescription; + +/// FfxBlurContext must be created via ffxBlurContextCreate to use the FFX Blur effect. +/// +/// @ingroup ffxBlur +typedef struct FfxBlurContext +{ + uint32_t data[FFX_BLUR_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxBlurContext; + +/// Create and initialize the FfxBlurContext. +/// +/// @param [out] pContext The FfxBlurContext to create and initialize. +/// @param [in] pContextDescription The initialization configuration parameters. +/// +/// @ingroup ffxBlur +FFX_API FfxErrorCode ffxBlurContextCreate(FfxBlurContext* pContext, const FfxBlurContextDescription* pContextDescription); + +/// Destroy and free resources associated with the FfxBlurContext. +/// +/// @param [inout] pContext The FfxBlurContext to destroy. +/// +/// @ingroup ffxBlur +FFX_API FfxErrorCode ffxBlurContextDestroy(FfxBlurContext* pContext); + +/// FfxBlurDispatchDescription struct defines configuration of a blur dispatch (see ffxBlurContextDispatch). +/// +/// @ingroup ffxBlur +typedef struct FfxBlurDispatchDescription +{ + FfxCommandList commandList; ///< The FfxCommandList to record rendering commands into. + FfxBlurKernelPermutation kernelPermutation; ///< The permutation of the kernel (must be the one specified in FfxBlurContextDescription::kernelPermutations). + FfxBlurKernelSize kernelSize; ///< The kernel size to use for blurring (must be one specified in FfxBlurContextDescription::kernelSizes). + FfxDimensions2D inputAndOutputSize; ///< The width and height in pixels of the input and output resources. + FfxResource input; ///< The FfxResource to blur. + FfxResource output; ///< The FfxResource containing the output buffer for the blurred output. +} FfxBlurDispatchDescription; + +/// Create and initialize the FfxBlurContext. +/// +/// @param [in] pContext The FfxBlurContext to use for the dispatch. +/// @param [in] pDispatchDescription The dispatch configuration parameters (see FfxBlurDispatchDescription). +/// +/// @ingroup ffxBlur +FFX_API FfxErrorCode ffxBlurContextDispatch(FfxBlurContext* pContext, const FfxBlurDispatchDescription* pDispatchDescription); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup ffxBlur +FFX_API FfxVersionNumber ffxBlurGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_breadcrumbs.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_breadcrumbs.h new file mode 100644 index 00000000..64a4bd5b --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_breadcrumbs.h @@ -0,0 +1,487 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +/// @defgroup ffxBreadcrumbs FidelityFX Breadcrumbs +/// FidelityFX Breadcrumbs runtime library +/// +/// @ingroup SDKComponents + + +#pragma once + +// Include the interface for the backend of the Breadcrumbs API. +#include + +/// FidelityFX Breadcrumbs major version. +/// +/// @ingroup ffxBreadcrumbs +#define FFX_BREADCRUMBS_VERSION_MAJOR (1) + +/// FidelityFX Breadcrumbs minor version. +/// +/// @ingroup ffxBreadcrumbs +#define FFX_BREADCRUMBS_VERSION_MINOR (0) + +/// FidelityFX Breadcrumbs patch version. +/// +/// @ingroup ffxBreadcrumbs +#define FFX_BREADCRUMBS_VERSION_PATCH (1) + +/// FidelityFX Breadcrumbs context count +/// +/// Defines the number of internal effect contexts required by Breadcrumbs +/// +/// @ingroup ffxBreadcrumbs +#define FFX_BREADCRUMBS_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup ffxBreadcrumbs +#define FFX_BREADCRUMBS_CONTEXT_SIZE (128) + +/// Maximal number of markers that can be written into single memory block. +/// +/// @ingroup ffxBreadcrumbs +#define FFX_BREADCRUMBS_MAX_MARKERS_PER_BLOCK ((1U << 31) - 1U) + +/// List of marker types to be used in X() macro. +/// +/// @ingroup ffxBreadcrumbs +#define FFX_BREADCRUMBS_MARKER_LIST \ + X(BEGIN_EVENT) \ + X(BEGIN_QUERY) \ + X(CLEAR_DEPTH_STENCIL) \ + X(CLEAR_RENDER_TARGET) \ + X(CLEAR_STATE) \ + X(CLEAR_UNORDERED_ACCESS_FLOAT) \ + X(CLEAR_UNORDERED_ACCESS_UINT) \ + X(CLOSE) \ + X(COPY_BUFFER_REGION) \ + X(COPY_RESOURCE) \ + X(COPY_TEXTURE_REGION) \ + X(COPY_TILES) \ + X(DISCARD_RESOURCE) \ + X(DISPATCH) \ + X(DRAW_INDEXED_INSTANCED) \ + X(DRAW_INSTANCED) \ + X(END_EVENT) \ + X(END_QUERY) \ + X(EXECUTE_BUNDLE) \ + X(EXECUTE_INDIRECT) \ + X(RESET) \ + X(RESOLVE_QUERY_DATA) \ + X(RESOLVE_SUBRESOURCE) \ + X(RESOURCE_BARRIER) \ + X(SET_COMPUTE_ROOT_SIGNATURE) \ + X(SET_DESCRIPTORS_HEAP) \ + X(SET_GRAPHICS_ROOT_SIGNATURE) \ + X(SET_PIPELINE_STATE) \ + X(SET_PREDICATION) \ + X(ATOMIC_COPY_BUFFER_UINT) \ + X(ATOMIC_COPY_BUFFER_UINT64) \ + X(RESOLVE_SUBRESOURCE_REGION) \ + X(SET_SAMPLE_POSITION) \ + X(SET_VIEW_INSTANCE_MASK) \ + X(WRITE_BUFFER_IMMEDIATE) \ + X(SET_PROTECTED_RESOURCE_SESSION) \ + X(BEGIN_RENDER_PASS) \ + X(BUILD_RAY_TRACING_ACCELERATION_STRUCTURE) \ + X(COPY_RAY_TRACING_ACCELERATION_STRUCTURE) \ + X(DISPATCH_RAYS) \ + X(EMIT_RAY_TRACING_ACCELERATION_STRUCTURE_POSTBUILD_INFO) \ + X(END_RENDER_PASS) \ + X(EXECUTE_META_COMMANDS) \ + X(INITIALIZE_META_COMMANDS) \ + X(SET_RAY_TRACING_STATE) \ + X(SET_SHADING_RATE) \ + X(SET_SHADING_RATE_IMAGE) \ + X(BEGIN_CONDITIONAL_RENDERING_EXT) \ + X(BEGIN_DEBUG_UTILS_LABEL_EXT) \ + X(BEGIN_QUERY_INDEXED_EXT) \ + X(BEGIN_RENDER_PASS_2) \ + X(BEGIN_TRANSFORM_FEEDBACK_EXT) \ + X(BIND_DESCRIPTOR_SETS) \ + X(BIND_PIPELINES) \ + X(BIND_SHADING_RATE_IMAGE_NV) \ + X(BLIT_IMAGE) \ + X(BUILD_ACCELERATION_STRUCTURE_NV) \ + X(CLEAR_ATTACHMENTS) \ + X(CLEAR_COLOR_IMAGE) \ + X(CLEAR_DEPTH_STENCIL_IMAGE) \ + X(COPY_ACCELERATION_STRUCTURE_NV) \ + X(COPY_BUFFER) \ + X(COPY_BUFFER_TO_IMAGE) \ + X(COPY_IMAGE) \ + X(COPY_IMAGE_TO_BUFFER) \ + X(DEBUG_MARKER_BEGIN_EXT) \ + X(DEBUG_MARKER_END_EXT) \ + X(DEBUG_MARKER_INSERT_EXT) \ + X(DISPATCH_BASE) \ + X(DISPATCH_INDIRECT) \ + X(DRAW) \ + X(DRAW_INDEXED) \ + X(DRAW_INDEXED_INDIRECT) \ + X(DRAW_INDEXED_INDIRECT_COUNT) \ + X(DRAW_INDIRECT) \ + X(DRAW_INDIRECT_BYTE_COUNT_EXT) \ + X(DRAW_INDIRECT_COUNT) \ + X(DRAW_MESH_TASKS_INDIRECT_COUNT_NV) \ + X(DRAW_MESH_TASKS_INDIRECT_NV) \ + X(DRAW_MESH_TASKS_NV) \ + X(END_CONDITIONAL_RENDERING_EXT) \ + X(END_DEBUG_UTILS_LABEL_EXT) \ + X(END_QUERY_INDEXED_EXT) \ + X(END_RENDER_PASS_2) \ + X(END_TRANSFORM_FEEDBACK_EXT) \ + X(EXECUTE_COMMANDS) \ + X(FILL_BUFFER) \ + X(INSERT_DEBUG_UTILS_LABEL_EXT) \ + X(NEXT_SUBPASS) \ + X(NEXT_SUBPASS_2) \ + X(PIPELINE_BARRIER) \ + X(PROCESS_COMMANDS_NVX) \ + X(RESERVE_SPACE_FOR_COMMANDS_NVX) \ + X(RESET_EVENT) \ + X(RESET_QUERY_POOL) \ + X(RESOLVE_IMAGE) \ + X(SET_CHECKPOINT_NV) \ + X(SET_EVENT) \ + X(SET_PERFORMANCE_MARKER_INTEL) \ + X(SET_PERFORMANCE_OVERRIDE_INTEL) \ + X(SET_PERFORMANCE_STREAM_MARKER_INTEL) \ + X(SET_SAMPLE_LOCATIONS_EXT) \ + X(SET_VIEWPORT_SHADING_RATE_PALETTE_NV) \ + X(TRACE_RAYS_NV) \ + X(UPDATE_BUFFER) \ + X(WAIT_EVENTS) \ + X(WRITE_ACCELERATION_STRUCTURES_PROPERTIES_NV) \ + X(WRITE_BUFFER_MARKER_AMD) \ + X(WRITE_BUFFER_MARKER_2_AMD) \ + X(WRITE_TIMESTAMP) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of bit flags used when creating a +/// FfxBreadcrumbsContext. See FfxBreadcrumbsContextDescription. +/// +/// @ingroup ffxBreadcrumbs +typedef enum FfxBreadcrumbsInitializationFlagBits { + + FFX_BREADCRUMBS_PRINT_FINISHED_LISTS = (1<<0), ///< A bit indicating that fully finished command lists will be expanded during status printing (otherwise their entries will be collapsed). + FFX_BREADCRUMBS_PRINT_NOT_STARTED_LISTS = (1<<1), ///< A bit indicating that command lists that haven't started execution on GPU yet will be expanded during status printing (otherwise their entries will be collapsed). + FFX_BREADCRUMBS_PRINT_FINISHED_NODES = (1<<3), ///< A bit indicating that nested markers which already have finished execution will be expanded during status printing (otherwise they will merged into top level marker). + FFX_BREADCRUMBS_PRINT_NOT_STARTED_NODES = (1<<4), ///< A bit indicating that nested markers which haven't started execution yet will be expanded during status printing (otherwise they will merged into top level marker). + FFX_BREADCRUMBS_PRINT_EXTENDED_DEVICE_INFO = (1<<5), ///< A bit indicating that additional info about active GPU will be printed into output status. + FFX_BREADCRUMBS_PRINT_SKIP_DEVICE_INFO = (1<<6), ///< A bit indicating that no info about active GPU will be printed into outpus status. + FFX_BREADCRUMBS_PRINT_SKIP_PIPELINE_INFO = (1<<7), ///< A bit indicating no info about pipelines used for commands recorded between markers will be printed into output status. + FFX_BREADCRUMBS_ENABLE_THREAD_SYNCHRONIZATION = (1<<8), ///< A bit indicating if internal synchronization should be applied (when using Breadcrumbs concurrently from multiple threads). +} FfxBreadcrumbsInitializationFlagBits; + +/// Type of currently recorded marker, purely informational. +/// +/// based on available methods of `ID3D12GraphicsCommandListX`, values of `D3D12_AUTO_BREADCRUMB_OP` and Vulkan `vkCmd*()` functions. +/// When using FFX_BREADCRUMBS_MARKER_PASS it is required to supply custom name for recording this type of marker. Otherwise it can +/// be left out as NULL and the Breadcrumbs will use default tag for this marker. It can be useful when recording multiple similar +/// commands in a row. Breadcrumbs will automatically add numbering to them so it's not needed to create your own numbered dynamic string. +/// +/// @ingroup ffxBreadcrumbs +typedef enum FfxBreadcrumbsMarkerType { + + FFX_BREADCRUMBS_MARKER_PASS, ///< Marker for grouping sets of commands. It is required to supply custom name for this type. +#define X(marker) FFX_BREADCRUMBS_MARKER_##marker, + FFX_BREADCRUMBS_MARKER_LIST +#undef X +} FfxBreadcrumbsMarkerType; + +/// A structure encapsulating the parameters required to initialize FidelityFX Breadcrumbs. +/// +/// @ingroup ffxBreadcrumbs +typedef struct FfxBreadcrumbsContextDescription { + + uint32_t flags; ///< A collection of FfxBreadcrumbsInitializationFlagBits. + uint32_t frameHistoryLength; ///< Number of frames to records markers for. Have to be larger than 0. + uint32_t maxMarkersPerMemoryBlock; ///< Controls the number of markers saved in single memory block. Have to be in range of [1..FFX_BREADCRUMBS_MAX_MARKERS_PER_BLOCK]. + uint32_t usedGpuQueuesCount; ///< Number of entries in pUsedGpuQueues. Have to be larger than 0. + uint32_t* pUsedGpuQueues; ///< Pointer to an array of unique indices representing GPU queues used for command lists used with AMD FidelityFX Breadcrumbs Library. + FfxAllocationCallbacks allocCallbacks; ///< Callbacks for managing memory in the library. + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX SDK. +} FfxBreadcrumbsContextDescription; + + +/// Wrapper for custom Breadcrumbs name tags with indicator whether to perform copy on them. +/// +/// When custom name is supplied isNameExternallyOwned field controls whether to perform copy on the string. +/// If string memory is managed by the application (ex. static string) the copy can be omitted to save memory. +/// +/// @ingroup ffxBreadcrumbs +typedef struct FfxBreadcrumbsNameTag +{ + const char* pName; ///< Custom name for the object. By default optional, can be left to NULL. + bool isNameExternallyOwned; ///< Controls if AMD FidelityFX Breadcrumbs Library should copy a custom name with backed-up memory. +} FfxBreadcrumbsNameTag; + +/// Description for new command list to be enabled for writing AMD FidelityFX Breadcrumbs Library markers. +/// +/// @ingroup ffxBreadcrumbs +typedef struct FfxBreadcrumbsCommandListDescription { + + FfxCommandList commandList; ///< Handle to the command list that will be used with breadcrumbs operations. + uint32_t queueType; ///< Type of queue that list is used on. + FfxBreadcrumbsNameTag name; ///< Custom name for the command list. + FfxPipeline pipeline; ///< Optional pipeline state to associate with newly registered command list (can be set later). + uint16_t submissionIndex; ///< Information about submit number that command list is sent to GPU. Purely informational to help in analysing output later. +} FfxBreadcrumbsCommandListDescription; + +/// Description for pipeline state that will be used to tag breadcrumbs markers. +/// +/// @ingroup ffxBreadcrumbs +typedef struct FfxBreadcrumbsPipelineStateDescription +{ + FfxPipeline pipeline; ///< Pipeline state that will be associated with set of Breadcrumbs markers. + FfxBreadcrumbsNameTag name; ///< Custom name for the pipeline state. + FfxBreadcrumbsNameTag vertexShader; ///< Name of used Vertex Shader. Part of classic geometry processing pipeline, cannot be set together with compute, ray tracing or new mesh processing pipeline. + FfxBreadcrumbsNameTag hullShader; ///< Name of used Hull Shader. Part of classic geometry processing pipeline, cannot be set together with compute, ray tracing or new mesh processing pipeline. + FfxBreadcrumbsNameTag domainShader; ///< Name of used Domain Shader. Part of classic geometry processing pipeline, cannot be set together with compute, ray tracing or new mesh processing pipeline. + FfxBreadcrumbsNameTag geometryShader; ///< Name of used Geometry Shader. Part of classic geometry processing pipeline, cannot be set together with compute, ray tracing or new mesh processing pipeline. + FfxBreadcrumbsNameTag meshShader; ///< Name of used Mesh Shader. Part of new mesh processing pipeline, cannot be set together with compute, ray tracing or classic geometry processing pipeline. + FfxBreadcrumbsNameTag amplificationShader; ///< Name of used Amplification Shader. Part of new mesh processing pipeline, cannot be set together with compute, ray tracing or classic geometry processing pipeline. + FfxBreadcrumbsNameTag pixelShader; ///< Name of used Pixel Shader. Cannot be set together with computeShader or rayTracingShader. + FfxBreadcrumbsNameTag computeShader; ///< Name of used Compute Shader. Have to be set exclusively to other shader names (indicates compute pipeline). + FfxBreadcrumbsNameTag rayTracingShader; ///< Name of used Ray Tracing Shader. Have to be set exclusively to other shader names (indicates ray tracing pipeline). +} FfxBreadcrumbsPipelineStateDescription; + +/// Output with current AMD FidelityFX Breadcrumbs Library markers log for post-mortem analysis. +/// +/// @ingroup ffxBreadcrumbs +typedef struct FfxBreadcrumbsMarkersStatus +{ + size_t bufferSize; ///< Size of the status buffer. + char* pBuffer; ///< UTF-8 encoded buffer with log about markers execution. Have to be released with FFX_FREE. +} FfxBreadcrumbsMarkersStatus; + +/// A structure encapsulating the FidelityFX Breadcrumbs context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by AMD FidelityFX Breadcrumbs Library. +/// +/// The FfxBreadcrumbsContext object should have a lifetime matching +/// your use of Breadcrumbs. Before destroying the Breadcrumbs context care should be taken +/// to ensure the GPU is not accessing the resources created or used by Breadcrumbs. +/// It is therefore recommended that the GPU is idle before destroying the +/// Breadcrumbs context. +/// +/// @ingroup ffxBreadcrumbs +typedef struct FfxBreadcrumbsContext +{ + uint32_t data[FFX_BREADCRUMBS_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxBreadcrumbsContext; + +/// Create a FidelityFX Breadcrumbs context from the parameters +/// programmed to the FfxBreadcrumbsContextDescription structure. +/// +/// The context structure is the main object used to interact with the Breadcrumbs +/// API, and is responsible for the management of the internal buffers used +/// by the Breadcrumbs algorithm. For each provided queue there will be created +/// a buffer that will hold contents of the saved markers, awaiting for retrieval +/// per call to ffxBreadcrumbsPrintStatus() +/// +/// When choosing the number of frames to save markers for, +/// specified in the frameHistoryLength field of +/// FfxBreadcrumbsContextDescription, typically can be set to the number of +/// frames in flight in the application, but for longer history it can be increased. +/// +/// Buffers for markers are allocated at fixed size, allowing for certain +/// number of markers to be saved in them. The size of this buffers are +/// determined by maxMarkersPerMemoryBlock field of +/// FfxBreadcrumbsContextDescription. When needed new ones are created but to avoid +/// multiple allocations you can estimate how many markers will be used in single frame. +/// +/// The FfxBreadcrumbsContext should be destroyed when use of it is +/// completed, typically when an application is unloaded. To destroy the Breadcrumbs context +/// you should call ffxBreadcrumbsContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxBreadcrumbsContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxBreadcrumbsContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxBreadcrumbsContextDescription.backendInterface was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsContextCreate(FfxBreadcrumbsContext* pContext, const FfxBreadcrumbsContextDescription* pContextDescription); + +/// Destroy the FidelityFX Breadcrumbs context. +/// +/// Should always be called from a single thread for same context. +/// +/// @param [out] pContext A pointer to a FfxBreadcrumbsContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext was NULL. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsContextDestroy(FfxBreadcrumbsContext* pContext); + +/// Begins new frame of execution for FidelityFX Breadcrumbs. +/// +/// Should always be called from a single thread for same context. +/// +/// @param [in] pContext A pointer to a FfxBreadcrumbsContext structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext was NULL. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsStartFrame(FfxBreadcrumbsContext* pContext); + +/// Register new command list for current frame FidelityFX Breadcrumbs operations. +/// +/// After call to ffxBreadcrumbsStartFrame() every previously used list has to be registered again. +/// +/// @param [in] pContext A pointer to a FfxBreadcrumbsContext structure. +/// @param [in] pCommandListDescription A pointer to a FfxBreadcrumbsCommandListDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext or pCommandListDescription was NULL. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT The operation failed because given command list has been already registered. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsRegisterCommandList(FfxBreadcrumbsContext* pContext, const FfxBreadcrumbsCommandListDescription* pCommandListDescription); + +/// Register new pipeline state to associate later with FidelityFX Breadcrumbs operations. +/// +/// Information about pipeline is preserved across frames so only single call after creation of pipeline is needed. +/// +/// @param [in] pContext A pointer to a FfxBreadcrumbsContext structure. +/// @param [in] pPipelineDescription A pointer to a FfxBreadcrumbsPipelineStateDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext or pPipelineDescription was NULL. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT The operation failed because given pipeline has been already registered or pPipelineDescription contains incorrect data. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsRegisterPipeline(FfxBreadcrumbsContext* pContext, const FfxBreadcrumbsPipelineStateDescription* pPipelineDescription); + +/// Associate specific pipeline state with following FidelityFX Breadcrumbs markers. +/// +/// When recorded commands use specific pipelines you can save this information, associating said pipelines +/// with recorded markers, so later on additional information can be displayed when using ffxBreadcrumbsPrintStatus(). +/// To reset currently used pipeline just pass NULL as pipeline param. +/// +/// @param [in] pContext A pointer to a FfxBreadcrumbsContext structure. +/// @param [in] commandList Previously registered command list. +/// @param [in] pipeline Previously registered pipeline. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either context or commandList was NULL. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT The operation failed because given pipeline or command list has not been registered yet. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsSetPipeline(FfxBreadcrumbsContext* pContext, FfxCommandList commandList, FfxPipeline pipeline); + +/// Begin new FidelityFX Breadcrumbs marker section. +/// +/// New section has to be ended with ffxBreadcrumbsEndMarker() +/// but multiple ffxBreadcrumbsBeginMarker() nesting calls are possible. +/// +/// @param [in] pContext A pointer to a FfxBreadcrumbsContext structure. +/// @param [in] commandList Previously registered command list. +/// @param [in] type Type of the marker section. +/// @param [in] pName Custom name for the marker section. Have to contain correct string if type is FFX_BREADCRUMBS_MARKER_PASS(). +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext or pName was NULL. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT The operation failed because given command list has not been registered yet or pName doesn't contain correct string. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsBeginMarker(FfxBreadcrumbsContext* pContext, FfxCommandList commandList, FfxBreadcrumbsMarkerType type, const FfxBreadcrumbsNameTag* pName); + +/// End FidelityFX Breadcrumbs marker section. +/// +/// Has to be preceeded by ffxBreadcrumbsBeginMarker(). +/// +/// @param [in] pContext A pointer to a FfxBreadcrumbsContext structure. +/// @param [in] commandList Previously registered command list. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because pContext was NULL. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT The operation failed because given command list has not been registered yet. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsEndMarker(FfxBreadcrumbsContext* pContext, FfxCommandList commandList); + +/// Gather information about current FidelityFX Breadcrumbs markers status. +/// +/// After receiving device lost error on GPU you can use this method to print post-mortem log of markers execution +/// to determine which commands in which frame were in flight during the crash. +/// Should always be called from a single thread. +/// +/// @param [in] pContext A pointer to a FfxBreadcrumbsContext structure. +/// @param [out] pMarkersStatus Buffer with post-mortem log of Breadcrumbs markers. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext or pMarkersStatus was NULL. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxErrorCode ffxBreadcrumbsPrintStatus(FfxBreadcrumbsContext* pContext, FfxBreadcrumbsMarkersStatus* pMarkersStatus); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup ffxBreadcrumbs +FFX_API FfxVersionNumber ffxBreadcrumbsGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizer.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizer.h new file mode 100644 index 00000000..9860b4cd --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizer.h @@ -0,0 +1,339 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +#include + +/// The size of the context specified in 32bit values. +/// +/// @ingroup ffxBrixelizer +#define FFX_BRIXELIZER_CONTEXT_SIZE (5938838) + +/// The size of the update description specified in 32bit values. +/// +/// @ingroup ffxBrixelizer +#define FFX_BRIXELIZER_UPDATE_DESCRIPTION_SIZE 2099376 + +#ifdef __cplusplus +extern "C" { +#endif + +/// A structure encapsulating the FidelityFX Brixelizer context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by Brixelizer. +/// +/// The FfxBrixelizerContext object should have a lifetime matching +/// your use of Brixelizer. Before destroying the Brixelizer context care +/// should be taken to ensure the GPU is not accessing the resources created +/// or used by Brixelizer. It is therefore recommended that the GPU is idle +/// before destroying the Brixelizer context. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerContext { + uint32_t data[FFX_BRIXELIZER_CONTEXT_SIZE]; +} FfxBrixelizerContext; + +/// A structure representing an axis aligned bounding box for use with Brixelizer. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerAABB { + float min[3]; ///< The minimum bounds of the AABB. + float max[3]; ///< The maximum bounds of the AABB. +} FfxBrixelizerAABB; + +/// Flags used for cascade creation. A cascade may be specified +/// as having static geometry, dynamic geometry, or both by combining these flags. +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerCascadeFlag { + FFX_BRIXELIZER_CASCADE_STATIC = (1 << 0), + FFX_BRIXELIZER_CASCADE_DYNAMIC = (1 << 1), +} FfxBrixelizerCascadeFlag; + +/// A structure encapsulating the parameters for cascade creation. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerCascadeDescription { + FfxBrixelizerCascadeFlag flags; ///< Flags for cascade creation. See FfxBrixelizerCascadeFlag. + float voxelSize; ///< The edge size of voxels in world space for the cascade. +} FfxBrixelizerCascadeDescription; + +/// A structure encapsulating the parameters for creating a Brixelizer context. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerContextDescription { + float sdfCenter[3]; ///< The point in world space around which to center the cascades. + uint32_t numCascades; ///< The number of cascades managed by the Brixelizer context. + FfxBrixelizerContextFlags flags; ///< A combination of FfxBrixelizerContextFlags specifying options for the context. + FfxBrixelizerCascadeDescription cascadeDescs[FFX_BRIXELIZER_MAX_CASCADES]; ///< Parameters describing each of the cascades, see FfxBrixelizerCascadeDescription. + FfxInterface backendInterface; ///< An implementation of the FidelityFX backend for use with Brixelizer. +} FfxBrixelizerContextDescription; + +/// Flags used for setting which AABBs to draw in a debug visualization of Brixelizer +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerPopulateDebugAABBsFlags { + FFX_BRIXELIZER_POPULATE_AABBS_NONE = 0, ///< Draw no AABBs. + FFX_BRIXELIZER_POPULATE_AABBS_STATIC_INSTANCES = 1 << 0, ///< Draw AABBs for all static instances. + FFX_BRIXELIZER_POPULATE_AABBS_DYNAMIC_INSTANCES = 1 << 1, ///< Draw AABBs for all dynamic instances. + FFX_BRIXELIZER_POPULATE_AABBS_INSTANCES = FFX_BRIXELIZER_POPULATE_AABBS_STATIC_INSTANCES | FFX_BRIXELIZER_POPULATE_AABBS_DYNAMIC_INSTANCES, ///< Draw AABBs for all instances. + FFX_BRIXELIZER_POPULATE_AABBS_CASCADE_AABBS = 1 << 2, ///< Draw AABBs for all cascades. +} FfxBrixelizerPopulateDebugAABBsFlags; + +/// A structure containing the statistics for a Brixelizer context readable after an update of the Brixelizer API. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerContextStats { + uint32_t brickAllocationsAttempted; ///< Total number of brick allocations attempted this frame. + uint32_t brickAllocationsSucceeded; ///< Total number of brick allocations succeeded this frame. + uint32_t bricksCleared; ///< Total number of bricks cleared in SDF atlas at the beginning of this frame. + uint32_t bricksMerged; ///< Total number of bricks merged this frame. + uint32_t freeBricks; ///< The number of free bricks in the Brixelizer context. +} FfxBrixelizerContextStats; + +/// A structure containing the statistics for a Brixelizer cascade readable after an update of the Brixelizer API. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerCascadeStats { + uint32_t trianglesAllocated; ///< The number of triangle allocations that were attempted to the cascade in a given frame. + uint32_t referencesAllocated; ///< The number of reference allocations that were attempted to the cascade in a given frame. + uint32_t bricksAllocated; ///< The number of brick allocations that were attempted to the cascade in a given frame. +} FfxBrixelizerCascadeStats; + +/// A structure containing the statistics readable after an update of the Brixelizer API. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerStats { + uint32_t cascadeIndex; ///< The index of the cascade that the statisticss have been collected for. + FfxBrixelizerCascadeStats staticCascadeStats; ///< The statistics for the static cascade. + FfxBrixelizerCascadeStats dynamicCascadeStats; ///< The statistics for the dynamic cascade. + FfxBrixelizerContextStats contextStats; ///< The statistics for the Brixelizer context. +} FfxBrixelizerStats; + +/// A structure encapsulating the parameters used for computing an update by the +/// Brixelizer context. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerUpdateDescription { + FfxBrixelizerResources resources; ///< Structure containing all resources to be used by the Brixelizer context. + uint32_t frameIndex; ///< The index of the current frame. + float sdfCenter[3]; ///< The center of the cascades. + FfxBrixelizerPopulateDebugAABBsFlags populateDebugAABBsFlags; ///< Flags determining which AABBs to draw in a debug visualization. See FfxBrixelizerPopulateDebugAABBsFlag. + FfxBrixelizerDebugVisualizationDescription *debugVisualizationDesc; ///< An optional debug visualization description. If this parameter is set to NULL no debug visualization is drawn. + uint32_t maxReferences; ///< The maximum number of triangle voxel references to be stored in the update. + uint32_t triangleSwapSize; ///< The size of the swap space available to be used for storing triangles in the update. + uint32_t maxBricksPerBake; ///< The maximum number of bricks to be updated. + size_t *outScratchBufferSize; ///< An optional pointer to a size_t to receive the size of the GPU scratch buffer needed to process the update. + FfxBrixelizerStats *outStats; ///< An optional pointer to an FfxBrixelizerStats struct to receive statistics for the update. Note, stats read back after a call to update do not correspond to the same frame that the stats were requested, as reading of stats requires readback from GPU buffers which is performed with a delay. +} FfxBrixelizerUpdateDescription; + +/// A structure generated by Brixelizer from an FfxBrixelizerUpdateDescription structure +/// used for storing parameters necessary for an update with the underlying raw Brixelizer API. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerBakedUpdateDescription { + uint32_t data[FFX_BRIXELIZER_UPDATE_DESCRIPTION_SIZE]; +} FfxBrixelizerBakedUpdateDescription; + +/// Flags used for specifying instance properties. +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerInstanceFlags { + FFX_BRIXELIZER_INSTANCE_FLAG_NONE = 0, ///< No instance flags set. + FFX_BRIXELIZER_INSTANCE_FLAG_DYNAMIC = 1 << 0, ///< This flag is set for any instance which should be added to the dynamic cascade. Indicates that this instance will be resubmitted every frame. +} FfxBrixelizerInstanceFlags; + +/// A structure encapsulating the parameters necessary to create an instance with Brixelizer. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerInstanceDescription { + uint32_t maxCascade; ///< The index of the highest cascade this instance will be submitted to. This helps avoid submitting many small objects to least detailed cascades. + FfxBrixelizerAABB aabb; ///< An AABB surrounding the instance. + FfxFloat32x3x4 transform; ///< A transform of the instance into world space. The transform is in row major order. + + FfxIndexFormat indexFormat; ///< The format of the index buffer. Accepted formats are FFX_INDEX_UINT16 or FFX_INDEX_UINT32. + uint32_t indexBuffer; ///< The index of the index buffer set with ffxBrixelizerContextSetBuffer. + uint32_t indexBufferOffset; ///< An offset into the index buffer. + uint32_t triangleCount; ///< The count of triangles in the index buffer. + + uint32_t vertexBuffer; ///< The index of the vertex buffer set with ffxBrixelizerContextSetBuffer. + uint32_t vertexStride; ///< The stride of the vertex buffer in bytes. + uint32_t vertexBufferOffset; ///< An offset into the vertex buffer. + uint32_t vertexCount; ///< The count of vertices in the vertex buffer. + FfxSurfaceFormat vertexFormat; ///< The format of vertices in the vertex buffer. Accepted values are FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT and FFX_SURFACE_FORMAT_R32G32B32_FLOAT. + + FfxBrixelizerInstanceFlags flags; ///< Flags specifying properties of the instance. See FfxBrixelizerInstanceFlags. + + FfxBrixelizerInstanceID *outInstanceID; ///< A pointer to an FfxBrixelizerInstanceID storing the ID of the created instance. +} FfxBrixelizerInstanceDescription; + +/// Get the size in bytes needed for an FfxBrixelizerContext struct. +/// Note that this function is provided for consistency, and the size of the +/// FfxBrixelizerContext is a known compile time value which can be +/// obtained using sizeof(FfxBrixelizerContext). +/// +/// @return The size in bytes of an FfxBrixelizerContext struct. +/// +/// @ingroup ffxBrixelizer +inline size_t ffxBrixelizerGetContextSize() +{ + return sizeof(FfxBrixelizerContext); +} + +/// Create a FidelityFX Brixelizer context from the parameters +/// specified to the FfxBrixelizerContextDesc struct. +/// +/// The context structure is the main object used to interact with the Brixelizer +/// API, and is responsible for the management of the internal resources used by the +/// Brixelizer algorithm. When this API is called, multiple calls will be made via +/// the pointers contained in the backendInterface structure. This +/// backend will attempt to retrieve the device capabilities, and create the internal +/// resources, and pipelines required by Brixelizer. +/// +/// Depending on the parameters passed in via the contextDescription a +/// different set of resources and pipelines may be requested by the callback functions. +/// +/// The FfxBrixelizerContext should be destroyed when use of it is completed. +/// To destroy the context you should call ffxBrixelizerContextDestroy. +/// +/// @param [in] desc An FfxBrixelizerContextDescription structure with the parameters for context creation. +/// @param [out] outContext An FfxBrixelizerContext structure for receiving the initialized Brixelizer context. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerContextCreate(const FfxBrixelizerContextDescription* desc, FfxBrixelizerContext* outContext); + +/// Delete the Brixelizer context associated with the FfxBrixelizerContext struct. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerContextDestroy(FfxBrixelizerContext* context); + +/// Fill in an FfxBrixelizerContextInfo struct for necessary for updating a constant buffer for use +/// by Brixelizer when ray marching. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [out] contextInfo An FfxBrixelizerContextInfo struct to be filled. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerGetContextInfo(FfxBrixelizerContext* context, FfxBrixelizerContextInfo* contextInfo); + +/// Build an FfxBrixelizerBakedUpdateDescription struct from an FfxBrixelizerUpdateDescription struct +/// for use in doing a Brixelizer update. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [in] desc An FfxBrixelizerUpdateDescription struct containing the parameters for the update. +/// @param [out] outDesc An FfxBrixelizerBakedUpdateDescription struct to be filled in. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerBakeUpdate(FfxBrixelizerContext* context, const FfxBrixelizerUpdateDescription* desc, FfxBrixelizerBakedUpdateDescription* outDesc); + +/// Perform an update of Brixelizer, recording GPU commands to a command list. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [in] desc An FfxBrixelizerBakedUpdateDescription describing the update to compute. +/// @param [out] scratchBuffer An FfxResource to be used as scratch space by the update. +/// @param [out] commandList An FfxCommandList to write GPU commands to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerUpdate(FfxBrixelizerContext* context, FfxBrixelizerBakedUpdateDescription* desc, FfxResource scratchBuffer, FfxCommandList commandList); + +/// Register a vertex or index buffer to use with Brixelizer. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [in] buffer An FfxResource of the vertex or index buffer. +/// @param [out] index The index of the registered buffer. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRegisterBuffers(FfxBrixelizerContext* context, const FfxBrixelizerBufferDescription* bufferDescs, uint32_t numBufferDescs); + +/// Unregister a previously registered vertex or index buffer. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [in] index The index of the buffer to unregister. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerUnregisterBuffers(FfxBrixelizerContext* context, const uint32_t* indices, uint32_t numIndices); + +/// Create a static instance for a Brixelizer context. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [in] descs An array of FfxBrixelizerInstanceDescription structs with the parameters for instance creation. +/// @param [in] numDescs The number of entries in the array passed in by descs. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerCreateInstances(FfxBrixelizerContext* context, const FfxBrixelizerInstanceDescription* descs, uint32_t numDescs); + +/// Delete a static instance from a Brixelizer context. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [in] instanceIDs An array of FfxBrixelizerInstanceIDs corresponding to instances to be destroyed. +/// @param [in] numInstnaceIDs The number of elements in the array passed in by instanceIDs. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerDeleteInstances(FfxBrixelizerContext* context, const FfxBrixelizerInstanceID* instanceIDs, uint32_t numInstanceIDs); + +/// Get a pointer to the underlying Brixelizer raw context from a Brixelizer context. +/// +/// @param [inout] context An FfxBrixelizerContext containing the Brixelizer context. +/// @param [out] outContext A FfxBrixelizerRawContext representing the underlying Brixelizer raw context. +/// +/// @return +/// FFX_ERROR_INVALID_POINTER The pointer given was invalid. +/// @return +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerGetRawContext(FfxBrixelizerContext* context, FfxBrixelizerRawContext** outContext); + +#ifdef __cplusplus +} +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizer_raw.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizer_raw.h new file mode 100644 index 00000000..a6bc500f --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizer_raw.h @@ -0,0 +1,681 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +/// @defgroup ffxBrixelizer FidelityFX Brixelizer +/// FidelityFX Brixelizer runtime library +/// +/// @ingroup SDKComponents + + +// Include the interface for the backend of the Brixelizer API. +#include +#include + +/// FidelityFX Brixelizer major version. +/// +/// @ingroup ffxBrixelizer +#define FFX_BRIXELIZER_VERSION_MAJOR (1) + +/// FidelityFX Brixelizer minor version. +/// +/// @ingroup ffxBrixelizer +#define FFX_BRIXELIZER_VERSION_MINOR (0) + +/// FidelityFX Brixelizer patch version. +/// +/// @ingroup ffxBrixelizer +#define FFX_BRIXELIZER_VERSION_PATCH (0) + +/// FidelityFX Brixelizer context count +/// +/// Defines the number of internal effect contexts required by Brixelizer +/// +/// @ingroup ffxBrixelizer +#define FFX_BRIXELIZER_CONTEXT_COUNT 1 + +/// The size of the raw context specified in 32bit values. +/// +/// @ingroup ffxBrixelizer +#define FFX_BRIXELIZER_RAW_CONTEXT_SIZE (2924058) + +#ifdef __cplusplus +extern "C" { +#endif + +/// An enumeration of all the passes which constitute the Brixelizer algorithm. +/// +/// Brixelizer is implemented as a composite of several compute passes each +/// computing a key part of the final result. Each call to the +/// FfxBrixelizerScheduleGpuJobFunc callback function will +/// correspond to a single pass included in FfxBrixelizerPass. For a +/// more comprehensive description of each pass, please refer to the Brixelizer +/// reference documentation. +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerPass +{ + + FFX_BRIXELIZER_PASS_CONTEXT_CLEAR_COUNTERS, + FFX_BRIXELIZER_PASS_CONTEXT_COLLECT_CLEAR_BRICKS, + FFX_BRIXELIZER_PASS_CONTEXT_PREPARE_CLEAR_BRICKS, + FFX_BRIXELIZER_PASS_CONTEXT_CLEAR_BRICK, + FFX_BRIXELIZER_PASS_CONTEXT_COLLECT_DIRTY_BRICKS, + FFX_BRIXELIZER_PASS_CONTEXT_PREPARE_EIKONAL_ARGS, + FFX_BRIXELIZER_PASS_CONTEXT_EIKONAL, + FFX_BRIXELIZER_PASS_CONTEXT_MERGE_CASCADES, + FFX_BRIXELIZER_PASS_CONTEXT_PREPARE_MERGE_BRICKS_ARGS, + FFX_BRIXELIZER_PASS_CONTEXT_MERGE_BRICKS, + FFX_BRIXELIZER_PASS_CASCADE_CLEAR_BUILD_COUNTERS, + FFX_BRIXELIZER_PASS_CASCADE_RESET_CASCADE, + FFX_BRIXELIZER_PASS_CASCADE_SCROLL_CASCADE, + FFX_BRIXELIZER_PASS_CASCADE_CLEAR_REF_COUNTERS, + FFX_BRIXELIZER_PASS_CASCADE_CLEAR_JOB_COUNTER, + FFX_BRIXELIZER_PASS_CASCADE_INVALIDATE_JOB_AREAS, + FFX_BRIXELIZER_PASS_CASCADE_COARSE_CULLING, + FFX_BRIXELIZER_PASS_CASCADE_SCAN_JOBS, + FFX_BRIXELIZER_PASS_CASCADE_VOXELIZE, + FFX_BRIXELIZER_PASS_CASCADE_SCAN_REFERENCES, + FFX_BRIXELIZER_PASS_CASCADE_COMPACT_REFERENCES, + FFX_BRIXELIZER_PASS_CASCADE_CLEAR_BRICK_STORAGE, + FFX_BRIXELIZER_PASS_CASCADE_EMIT_SDF, + FFX_BRIXELIZER_PASS_CASCADE_COMPRESS_BRICK, + FFX_BRIXELIZER_PASS_CASCADE_INITIALIZE_CASCADE, + FFX_BRIXELIZER_PASS_CASCADE_MARK_UNINITIALIZED, + FFX_BRIXELIZER_PASS_CASCADE_BUILD_TREE_AABB, + FFX_BRIXELIZER_PASS_CASCADE_FREE_CASCADE, + FFX_BRIXELIZER_PASS_DEBUG_VISUALIZATION, + FFX_BRIXELIZER_PASS_DEBUG_INSTANCE_AABBS, + FFX_BRIXELIZER_PASS_DEBUG_AABB_TREE, + + FFX_BRIXELIZER_PASS_COUNT ///< The number of passes performed by Brixelizer. +} FfxBrixelizerPass; + +/// An ID value for an instance created with Brixelizer. +/// +/// @ingroup ffxBrixelizer +typedef uint32_t FfxBrixelizerInstanceID; + +/// A structure representing the external resources needed for a Brixelizer cascade. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerCascadeResources +{ + FfxResource aabbTree; ///< An FfxResource for storing the AABB tree of the cascade. This should be a structured buffer of size FFX_BRIXELIZER_CASCADE_AABB_TREE_SIZE and stride FFX_BRIXELIZER_CASCADE_AABB_TREE_STRIDE. + FfxResource brickMap; ///< An FfxResource for storing the brick map of the cascade. This should be a structured buffer of size FFX_BRIXELIZER_CASCADE_BRICK_MAP_SIZE and stride FFX_BRIXELIZER_CASCADE_BRICK_MAP_STRIDE. +} FfxBrixelizerCascadeResources; + +/// A structure representing all external resources for use with Brixelizer. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerResources +{ + FfxResource sdfAtlas; ///< An FfxResource for storing the SDF atlas. This should be a 512x512x512 3D texture of 8-bit unorm values. + FfxResource brickAABBs; ///< An FfxResource for storing the brick AABBs. This should be a structured buffer containing 64*64*64 32-bit values. + FfxBrixelizerCascadeResources cascadeResources[FFX_BRIXELIZER_MAX_CASCADES]; ///< Cascade resources. +} FfxBrixelizerResources; + +/// A structure encapsulating the parameters necessary to register a buffer with +/// the Brixelizer API. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerBufferDescription { + FfxResource buffer; ///< An FfxResource of the buffer. + uint32_t *outIndex; ///< A pointer to a uint32_t to receive the index assigned to the buffer. +} FfxBrixelizerBufferDescription; + +/// Flags used for specifying debug drawing of AABBs. +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerCascadeDebugAABB { + FFX_BRIXELIZER_CASCADE_DEBUG_AABB_NONE, + FFX_BRIXELIZER_CASCADE_DEBUG_AABB_BOUNDING_BOX, + FFX_BRIXELIZER_CASCADE_DEBUG_AABB_AABB_TREE, +} FfxBrixelizerCascadeDebugAABB; + +/// A structure encapsulating the parameters for drawing a debug visualization. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerDebugVisualizationDescription +{ + float inverseViewMatrix[16]; ///< Inverse view matrix for the scene in row major order. + float inverseProjectionMatrix[16]; ///< Inverse projection matrix for the scene in row major order. + FfxBrixelizerTraceDebugModes debugState; ///< An FfxBrixelizerTraceDebugModes determining what kind of debug output to draw. + uint32_t startCascadeIndex; ///< The index of the most detailed cascade in the cascade chain. + uint32_t endCascadeIndex; ///< The index of the least detailed cascade in the cascade chain. + float sdfSolveEps; ///< The epsilon value used in SDF ray marching. + float tMin; ///< The tMin value for minimum ray intersection. + float tMax; ///< The tMax value for maximum ray intersection. + uint32_t renderWidth; ///< The width of the output resource. + uint32_t renderHeight; ///< The height of the output resource. + FfxResource output; ///< An FfxResource to draw the debug visualization to. + + FfxCommandList commandList; ///< An FfxCommandList to write the draw commands to. + uint32_t numDebugAABBInstanceIDs; ///< The number of FfxBrixelizerInstanceIDs in the debugAABBInstanceIDs array. + const FfxBrixelizerInstanceID *debugAABBInstanceIDs; ///< An array of FfxBrixelizerInstanceIDs for instances to draw the bounding boxes of. + FfxBrixelizerCascadeDebugAABB cascadeDebugAABB[FFX_BRIXELIZER_MAX_CASCADES]; ///< An array of flags showing what AABB debug output to draw for each cascade. +} FfxBrixelizerDebugVisualizationDescription; + +/// Flags for options for Brixelizer context creation. +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerContextFlags +{ + FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_CONTEXT_READBACK_BUFFERS = (1 << 0), ///< Create a context with context readback buffers enabled. Needed to use ffxBrixelizerContextGetDebugCounters. + FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_CASCADE_READBACK_BUFFERS = (1 << 1), ///< Create a context with cascade readback buffers enabled. Needed to use ffxBrixelizerContextGetCascadeCounters. + FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_AABBS = (1 << 2), ///< Create a context with debug AABBs enabled. + FFX_BRIXELIZER_CONTEXT_FLAG_ALL_DEBUG = FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_CONTEXT_READBACK_BUFFERS | FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_CASCADE_READBACK_BUFFERS | FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_AABBS, ///< Create a context with all debugging features enabled. +} FfxBrixelizerContextFlags; + +/// Flags used for creating Brixelizer jobs. Determines whether a job is a submission of geometry or invalidating +/// an area described by an AABB. +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerRawJobFlags { + FFX_BRIXELIZER_RAW_JOB_FLAG_NONE = 0u, + FFX_BRIXELIZER_RAW_JOB_FLAG_INVALIDATE = 1u << 2u, +} FfxBrixelizerRawJobFlags; + +/// Flags used for creating Brixelizer instances. +/// +/// @ingroup ffxBrixelizer +typedef enum FfxBrixelizerRawInstanceFlags { + FFX_BRIXELIZER_RAW_INSTANCE_FLAG_NONE = 0u, + FFX_BRIXELIZER_RAW_INSTANCE_FLAG_USE_INDEXLESS_QUAD_LIST = 1u << 1u, +} FfxBrixelizerRawInstanceFlags; + +/// A structure encapsulating the FidelityFX Brixelizer context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by Brixelizer. +/// +/// The FfxBrixelizerRawContext object should have a lifetime matching +/// your use of Brixelizer. Before destroying the Brixelizer context care +/// should be taken to ensure the GPU is not accessing the resources created +/// or used by Brixelizer. It is therefore recommended that the GPU is idle +/// before destroying the Brixelizer context. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerRawContext +{ + uint32_t data[FFX_BRIXELIZER_RAW_CONTEXT_SIZE]; +} FfxBrixelizerRawContext; + +/// A structure encapsulating the parameters for creating a Brixelizer context. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerRawContextDescription +{ + size_t maxDebugAABBs; ///< The maximum number of AABBs that can be drawn in debug mode. Note to use debug AABBs the flag FFX_BRIXELIZER_CONTEXT_FLAG must be passed at context creation. + FfxBrixelizerContextFlags flags; ///< A combination of FfxBrixelizerContextFlags specifying options for the context. + FfxInterface backendInterface; ///< An FfxInterface representing the FidelityFX backend interface. + +} FfxBrixelizerRawContextDescription; + +/// A structure encapsulating the parameters for creating a Brixelizer cascade. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerRawCascadeDescription +{ + float brickSize; ///< The edge size of a brick in world units. + float cascadeMin[3]; ///< Corner of the first brick. + uint32_t index; ///< Index of the cascade. +} FfxBrixelizerRawCascadeDescription; + +/// A structure describing a Brixelizer job. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerRawJobDescription +{ + float aabbMin[3]; ///< The mimimum corner of the AABB of the job. + float aabbMax[3]; ///< The maximum corner of the AABB of the job. + uint32_t flags; ///< Flags for the job (to be set from FfxBrixelizerRawJobFlags). + uint32_t instanceIdx; ///< The ID for an instance for the job. +} FfxBrixelizerRawJobDescription; + +/// A structure encapsulating the parameters for updating a Brixelizer cascade. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerRawCascadeUpdateDescription +{ + uint32_t maxReferences; ///< storage for triangle->voxel references + uint32_t triangleSwapSize; ///< scratch storage for triangles + uint32_t maxBricksPerBake; ///< max SDF brick baked per update + int32_t cascadeIndex; ///< Target Cascade + const FfxBrixelizerRawJobDescription *jobs; ///< A pointer to an array of jobs. + size_t numJobs; ///< The number of jobs in the array pointed to by jobs. + float cascadeMin[3]; ///< Lower corner of the first brick in world space. + int32_t clipmapOffset[3]; ///< Changing that invalidates portion of the cascade. it's an offset in the voxel->brick table. + uint32_t flags; ///< See FfxBrixelizerCascadeUpdateFlags. +} FfxBrixelizerRawCascadeUpdateDescription; + +/// A structure encapsulating the parameters for an instance to be added to a +/// Brixelizer context. +/// +/// @ingroup ffxBrixelizer +typedef struct FfxBrixelizerRawInstanceDescription +{ + float aabbMin[3]; ///< The minimum coordinates of an AABB surrounding the instance. + float aabbMax[3]; ///< The maximum coordinates of an AABB surrounding the instance. + FfxFloat32x3x4 transform; ///< A tranform of the instance into world space. The transform is in row major order. + + FfxIndexFormat indexFormat; ///< The format of the index buffer. Accepted formats are FFX_INDEX_UINT16 or FFX_INDEX_UINT32. + uint32_t indexBuffer; ///< The index of the index buffer set with ffxBrixelizerContextSetBuffer. + uint32_t indexBufferOffset; ///< An offset into the index buffer. + uint32_t triangleCount; ///< The count of triangles in the index buffer. + + uint32_t vertexBuffer; ///< The index of the vertex buffer set with ffxBrixelizerContextSetBuffer. + uint32_t vertexStride; ///< The stride of the vertex buffer in bytes. + uint32_t vertexBufferOffset; ///< An offset into the vertex buffer. + uint32_t vertexCount; ///< The count of vertices in the vertex buffer. + FfxSurfaceFormat vertexFormat; ///< The format of vertices in the vertex buffer. Accepted values are FFX_SURFACE_FORMAT_R16G16B16A16_FLOAT and FFX_SURFACE_FORMAT_R32G32B32A32_FLOAT. + + uint32_t flags; ///< Flags for the instance. See FfxBrixelizerRawInstanceFlags. + FfxBrixelizerInstanceID *outInstanceID; ///< A pointer to an FfxBrixelizerInstanceID to be filled with the instance ID assigned for the instance. +} FfxBrixelizerRawInstanceDescription; + + +/// Get the size in bytes needed for an FfxBrixelizerRawContext struct. +/// Note that this function is provided for consistency, and the size of the +/// FfxBrixelizerRawContext is a known compile time value which can be +/// obtained using sizeof(FfxBrixelizerRawContext). +/// +/// @return The size in bytes of an FfxBrixelizerRawContext struct. +/// +/// @ingroup ffxBrixelizer +inline size_t ffxBrixelizerRawGetContextSize() +{ + return sizeof(FfxBrixelizerRawContext); +} + +/// Create a FidelityFX Brixelizer context from the parameters +/// specified to the FfxBrixelizerRawContextDescription struct. +/// +/// The context structure is the main object used to interact with the Brixelizer API, +/// and is responsible for the management of the internal resources used by the +/// Brixelizer algorithm. When this API is called, multiple calls will be made via +/// the pointers contained in the backendInterface structure. This +/// backend will attempt to retrieve the device capabilities, and create the internal +/// resources, and pipelines required by Brixelizer. +/// +/// Depending on the parameters passed in via the contextDescription a +/// different set of resources and pipelines may be requested by the callback functions. +/// +/// The FfxBrixelizerRawContext should be destroyed when use of it is completed. +/// To destroy the context you should call ffxBrixelizerContextDestroy. +/// +/// @param [out] context A pointer to a FfxBrixelizerRawContext to populate. +/// @param [in] contextDescription A pointer to a FfxBrixelizerRawContextDescription specifying the parameters for context creation. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because contextDescription->backendInterface was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error from the backend. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextCreate(FfxBrixelizerRawContext* context, const FfxBrixelizerRawContextDescription* contextDescription); + +/// Destroy the FidelityFX Brixelizer context. +/// +/// @param [out] context A pointer to a FfxBrixelizerRawContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The context pointer provided was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextDestroy(FfxBrixelizerRawContext* context); + +/// Get an FfxBrixelizerContextInfo structure with the details for context. +/// This call is intended to be used to fill in a constant buffer necessary for making ray +/// queries. +/// +/// @param [out] context The FfxBrixelizerRawContext to receive the FfxBrixelizerContextInfo of. +/// @param [out] contextInfo A FfxBrixelizerContextInfo struct to be filled in. +/// +/// @retval +/// FFX_OK The operation was successful. +/// @retval +/// FFX_ERROR_INVALID_POINTER The context pointer provided was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextGetInfo(FfxBrixelizerRawContext* context, FfxBrixelizerContextInfo* contextInfo); + +/// Create a cascade for use with Brixelizer. +/// +/// @param [out] context The FfxBrixelizerRawContext to create a cascade for. +/// @param [in] cascadeDescription A FfxBrixelizerRawCascadeDescription struct specifying the parameters for cascade creation. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because one of context, cascadeDescription, c>cascadeDescription->aabbTree or c>cascadeDescription->brickMap was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation encountered an error in the backend. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextCreateCascade(FfxBrixelizerRawContext* context, const FfxBrixelizerRawCascadeDescription* cascadeDescription); + +/// Destroy a cascade previously created with ffxBrixelizerContextCreateCascade. +/// +/// @param [out] context The FfxBrixelizerRawContext to delete a cascade for. +/// @param [in] cascadeIndex The index of the cascade to delete. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextDestroyCascade(FfxBrixelizerRawContext* context, uint32_t cascadeIndex); + +/// Reset a cascade previously created with ffxBrixelizerContextCreateCascade. +/// +/// @param [out] context The FfxBrixelizerRawContext to reset a cascade for. +/// @param [in] cascadeIndex The index of the cascade to reset. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// @retval +/// FFX_ERROR_INVALID_ARGUMENT No cascade with index cascadeIndex exists. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextResetCascade(FfxBrixelizerRawContext* context, uint32_t cascadeIndex); + +/// Begin constructing GPU commands for updating SDF acceleration structures with Brixelizer. +/// Must be called between calls to ffxBrixelizerContextBegin and ffxBrixelizerContextEnd. +/// +/// @param [out] context The FfxBrixelizerRawContext to begin a frame for. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextBegin(FfxBrixelizerRawContext* context, FfxBrixelizerResources resources); + +/// End construcring GPU commands for updating the SDF acceleration structures with Brixelizer. +/// +/// @param [out] context The FfxBrixelizerRawContext to end a frame for. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextEnd(FfxBrixelizerRawContext* context); + +/// Record GPU commands to a FfxCommandList for updating acceleration structures with Brixelizer. +/// +/// @param [out] context The FfxBrixelizerRawContext to record GPU commands from. +/// @param [out] cmdList The FfxCommandList to record commands to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextSubmit(FfxBrixelizerRawContext* context, FfxCommandList cmdList); + +/// Get the size in bytes needed from a FfxResource to be used as a scratch buffer in a cascade update. +/// +/// @param [out] context The FfxBrixelizerRawContext to calculate the required scratch buffer size for. +/// @param [in] cascadeUpdateDescription A FfxBrixelizerRawCascadeUpdateDescription struct with the parameters for the cascade update. +/// @param [out] size A size_t to store the required scratch buffer size to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context or cascadeUpdateDescription was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextGetScratchMemorySize(FfxBrixelizerRawContext* context, const FfxBrixelizerRawCascadeUpdateDescription* cascadeUpdateDescription, size_t* size); + +/// Update a cascade in a Brixelizer context. +/// +/// @param [out] context The FfxBrixelizerRawContext to perform the cascade update on. +/// @param [in] cascadeUpdateDescription A FfxBrixelizerRawCascadeUpdateDescription struct with the parameters for the cascade update. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context or cascadeUpdateDescription was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextUpdateCascade(FfxBrixelizerRawContext* context, const FfxBrixelizerRawCascadeUpdateDescription* cascadeUpdateDescription); + +/// Merge two cascades in a Brixelizer context. +/// Must be called between calls to ffxBrixelizerRawContextBegin and ffxBrixelizerRawContextEnd. +/// +/// @param [out] context The FfxBrixelizerRawContext to merge cascades for. +/// @param [in] srcCascadeAIdx The index of the first source cascade. +/// @param [in] srcCascadeBIdx A FfxResource to store the required scratch buffer size to. +/// @param [in] dstCascadeIdx A FfxResource to store the required scratch buffer size to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextMergeCascades(FfxBrixelizerRawContext* context, uint32_t src_cascade_A_idx, uint32_t src_cascade_B_idx, uint32_t dst_cascade_idx); + +/// Build an AABB tree for a cascade in a Brixelizer context. +/// Must be called between calls to ffxBrixelizerRawContextBegin and ffxBrixelizerRawContextEnd. +/// +/// @param [out] context The FfxBrixelizerRawContext to build an AABB tree for. +/// @param [in] cascadeIndex The index of the cascade to build the AABB tree of. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextBuildAABBTree(FfxBrixelizerRawContext* context, uint32_t cascadeIndex); + +/// Create a debug visualization output of a Brixelizer context. +/// Must be called between calls to ffxBrixelizerRawContextBegin and ffxBrixelizerRawContextEnd. +/// +/// @param [out] context The FfxBrixelizerRawContext to create a debug visualization for. +/// @param [in] debugVisualizationDescription A FfxBrixelizerDebugVisualizationDescription providing the parameters for the debug visualization. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context or debugVisualizationDescription was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the FfxDevice provided to the context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextDebugVisualization(FfxBrixelizerRawContext* context, const FfxBrixelizerDebugVisualizationDescription* debugVisualizationDescription); + +/// Get the debug counters from a Brixelizer context. +/// Note to use this function the flag FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_CONTEXT_READBACK_BUFFERS must +/// be passed at context creation. +/// +/// @param [out] context The FfxBrixelizerRawContext to read the debug counters of. +/// @param [out] debugCounters A FfxBrixelizerDebugCounters struct to read the debug counters to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context or debugCounters was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextGetDebugCounters(FfxBrixelizerRawContext* context, FfxBrixelizerDebugCounters* debugCounters); + +/// Get the cascade counters from a Brixelizer context. +/// Note to use this function the flag FFX_BRIXELIZER_CONTEXT_FLAG_DEBUG_CASCADE_READBACK_BUFFERS must +/// be passed at context creation. +/// +/// @param [out] context The FfxBrixelizerRawContext to read the cascade counters of. +/// @param [in] cascadeIndex The index of the cascade to read the cascade counters of. +/// @param [out] counters A FfxBrixelizerScratchCounters struct to read the cascade counters to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context or counters was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextGetCascadeCounters(FfxBrixelizerRawContext* context, uint32_t cascadeIndex, FfxBrixelizerScratchCounters* counters); + +/// Create an instance in a Brixelizer context. +/// +/// @param [out] context The FfxBrixelizerRawContext to create an instance for. +/// @param [in] instanceDescription A FfxBrixelizerRawInstanceDescription struct with the parameters for the instance to create. +/// @param [out] numInstanceDescriptions A FfxBrixelizerInstanceID to read the instance ID to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context or instanceDescription was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextCreateInstances(FfxBrixelizerRawContext* context, const FfxBrixelizerRawInstanceDescription* instanceDescriptions, uint32_t numInstanceDescriptions); + +/// Destroy an instance in a Brixelizer context. +/// +/// @param [out] context The FfxBrixelizerRawContext to delete an instance for. +/// @param [in] instanceId The FfxBrixelizerInstanceID of the instance to delete. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextDestroyInstances(FfxBrixelizerRawContext* context, const FfxBrixelizerInstanceID* instanceIDs, uint32_t numInstanceIDs); + +/// Flush all instances added to the Brixelizer context with ffxBrixelizerRawContextCreateInstance to the GPU. +/// +/// @param [out] context The FfxBrixelizerRawContext to flush the instances for. +/// @param [in] cmdList An FfxCommandList to record GPU commands to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextFlushInstances(FfxBrixelizerRawContext* context, FfxCommandList cmdList); + +/// Register a vertex or index buffer for use with Brixelizer. +/// +/// @param [out] context The FfxBrixelizerRawContext to register a buffer for. +/// @param [in] buffer An FfxResource with the buffer to be set. +/// @param [out] index The index of the registered buffer. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextRegisterBuffers(FfxBrixelizerRawContext* context, const FfxBrixelizerBufferDescription* bufferDescs, uint32_t numBufferDescs); + +/// Unregister a previously registered vertex or index buffer. +/// +/// @param [out] context The FfxBrixelizerRawContext to unregister the buffer from +/// @param [in] index The index of the buffer to unregister. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextUnregisterBuffers(FfxBrixelizerRawContext* context, const uint32_t* indices, uint32_t numIndices); + +/// Get the index of the recommended cascade to update given the total number of cascades and current frame. +/// Follows the pattern 0 1 0 2 0 1 0 3 0 etc. If 0 is the most detailed cascade and maxCascades - 1 +/// is the least detailed cascade this ordering updates more detailed cascades more often. +/// +/// @param [out] context The FfxBrixelizerRawContext to set a buffer for. +/// @param [in] scratchBuffer A FfxResource for use as a scratch buffer. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxErrorCode ffxBrixelizerRawContextRegisterScratchBuffer(FfxBrixelizerRawContext* context, FfxResource scratchBuffer); + +/// Get the index of the recommended cascade to update given the total number of cascades and current frame. +/// Follows the pattern 0 1 0 2 0 1 0 3 0 etc. If 0 is the most detailed cascade and maxCascades - 1 +/// is the least detailed cascade this ordering updates more detailed cascades more often. +/// +/// @param [in] frameIndex The current frame index. +/// @param [in] maxCascades The total number of cascades. +/// +/// @retval The index of the cascade to update. +/// +/// @ingroup ffxBrixelizer +FFX_API uint32_t ffxBrixelizerRawGetCascadeToUpdate(uint32_t frameIndex, uint32_t maxCascades); + +/// Check whether an FfxResource is NULL. +/// +/// @param [in] resource An FfxResource to check for nullness. +/// +/// @retval true if resource is NULL else false. +/// +/// @ingroup ffxBrixelizer +FFX_API bool ffxBrixelizerRawResourceIsNull(FfxResource resource); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup ffxBrixelizer +FFX_API FfxVersionNumber ffxBrixelizerGetEffectVersion(); + +#ifdef __cplusplus +} +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizergi.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizergi.h new file mode 100644 index 00000000..75e63e60 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_brixelizergi.h @@ -0,0 +1,329 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +// Include the interface for the backend of the Brixelizer GI API. +#include +#include + +/// @defgroup ffxBrixgi FidelityFX Brixelizer GI +/// FidelityFX Brixelizer GI runtime library +/// +/// @ingroup SDKComponents + + +/// FidelityFX Brixelizer GI major version. +/// +/// @ingroup ffxBrixgi +#define FFX_BRIXELIZER_GI_VERSION_MAJOR (1) + +/// FidelityFX Brixelizer GI minor version. +/// +/// @ingroup ffxBrixgi +#define FFX_BRIXELIZER_GI_VERSION_MINOR (0) + +/// FidelityFX Brixelizer GI patch version. +/// +/// @ingroup ffxBrixgi +#define FFX_BRIXELIZER_GI_VERSION_PATCH (1) + +/// The size of the context specified in 32bit values. +/// +/// @ingroup ffxBrixgi +#define FFX_BRIXELIZER_GI_CONTEXT_SIZE (210000) + +/// FidelityFX Brixelizer GI context count +/// +/// Defines the number of internal effect contexts required by Brixelizer +/// +/// @ingroup ffxBrixgi +#define FFX_BRIXELIZER_GI_CONTEXT_COUNT 1 + +#ifdef __cplusplus +extern "C" { +#endif + +/// A structure encapsulating the FidelityFX Brixelizer GI context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by Brixelizer GI. +/// +/// The FfxBrixelizerGIContext object should have a lifetime matching +/// your use of Brixelizer GI. Before destroying the Brixelizer GI context care +/// should be taken to ensure the GPU is not accessing the resources created +/// or used by Brixelizer GI. It is therefore recommended that the GPU is idle +/// before destroying the Brixelizer GI context. +/// +/// @ingroup ffxBrixgi +typedef struct FfxBrixelizerGIContext +{ + uint32_t data[FFX_BRIXELIZER_GI_CONTEXT_SIZE]; +} FfxBrixelizerGIContext; + +/// An enumeration of flag bits used when creating an FfxBrixelizerGIContext. +/// See FfxBrixelizerGIContextDescription. +/// +/// @ingroup ffxBrixgi +typedef enum FfxBrixelizerGIFlags +{ + FFX_BRIXELIZER_GI_FLAG_DEPTH_INVERTED = (1 << 0), ///< Indicates input resources were generated with inverted depth. + FFX_BRIXELIZER_GI_FLAG_DISABLE_SPECULAR = (1 << 1), ///< Disable specular GI. + FFX_BRIXELIZER_GI_FLAG_DISABLE_DENOISER = (1 << 2), ///< Disable denoising. Only allowed at native resolution. +} FfxBrixelizerGIFlags; + +/// An enumeration of the quality modes supported by FidelityFX Brixelizer GI. +/// +/// @ingroup ffxBrixgi +typedef enum FfxBrixelizerGIInternalResolution +{ + FFX_BRIXELIZER_GI_INTERNAL_RESOLUTION_NATIVE, ///< Output GI at native resolution. + FFX_BRIXELIZER_GI_INTERNAL_RESOLUTION_75_PERCENT, ///< Output GI at 75% of native resolution. + FFX_BRIXELIZER_GI_INTERNAL_RESOLUTION_50_PERCENT, ///< Output GI at 50% of native resolution. + FFX_BRIXELIZER_GI_INTERNAL_RESOLUTION_25_PERCENT, ///< Output GI at 25% of native resolution. +} FfxBrixelizerGIInternalResolution; + +/// A structure encapsulating the parameters used for creating an +/// FfxBrixelizerGIContext. +/// +/// @ingroup ffxBrixgi +typedef struct FfxBrixelizerGIContextDescription +{ + FfxBrixelizerGIFlags flags; ///< A bit field representings various options. + FfxBrixelizerGIInternalResolution internalResolution; ///< The scale at which Brixelizer GI will output GI at internally. The output will be internally upscaled to the specified displaySize. + FfxDimensions2D displaySize; ///< The size of the presentation resolution targeted by the upscaling process. + FfxInterface backendInterface; ///< An implementation of the FidelityFX backend for use with Brixelizer. +} FfxBrixelizerGIContextDescription; + +/// A structure encapsulating the parameters used for computing a dispatch by the +/// Brixelizer GI context. +/// +/// @ingroup ffxBrixgi +typedef struct FfxBrixelizerGIDispatchDescription +{ + FfxFloat32x4x4 view; ///< The view matrix for the scene in row major order. + FfxFloat32x4x4 projection; ///< The projection matrix for the scene in row major order. + FfxFloat32x4x4 prevView; ///< The view matrix for the previous frame of the scene in row major order. + FfxFloat32x4x4 prevProjection; ///< The projection matrix for the scene in row major order. + + FfxFloat32x3 cameraPosition; ///< A 3-dimensional vector representing the position of the camera. + FfxUInt32 startCascade; ///< The index of the start cascade for use with ray marching with Brixelizer. + FfxUInt32 endCascade; ///< The index of the end cascade for use with ray marching with Brixelizer. + FfxFloat32 rayPushoff; ///< The distance from a surface along the normal vector to offset the diffuse ray origin. + FfxFloat32 sdfSolveEps; ///< The epsilon value for ray marching to be used with Brixelizer for diffuse rays. + FfxFloat32 specularRayPushoff; ///< The distance from a surface along the normal vector to offset the specular ray origin. + FfxFloat32 specularSDFSolveEps; ///< The epsilon value for ray marching to be used with Brixelizer for specular rays. + FfxFloat32 tMin; ///< The TMin value for use with Brixelizer. + FfxFloat32 tMax; ///< The TMax value for use with Brixelizer. + + FfxResource environmentMap; ///< The environment map. + FfxResource prevLitOutput; ///< The lit output from the previous frame. + FfxResource depth; ///< The input depth buffer. + FfxResource historyDepth; ///< The previous frame input depth buffer. + FfxResource normal; ///< The input normal buffer. + FfxResource historyNormal; ///< The previous frame input normal buffer. + FfxResource roughness; ///< The resource containing roughness information. + FfxResource motionVectors; ///< The input motion vectors texture. + FfxResource noiseTexture; ///< The input blue noise texture. + + FfxFloat32 normalsUnpackMul; ///< A multiply factor to transform the normal to the space expected by Brixelizer GI. + FfxFloat32 normalsUnpackAdd; ///< An offset to transform the normal to the space expected by Brixelizer GI. + FfxBoolean isRoughnessPerceptual; ///< A boolean to describe the space used to store roughness in the materialParameters texture. If false, we assume roughness squared was stored in the Gbuffer. + FfxUInt32 roughnessChannel; ///< The channel to read the roughness from the roughness texture + FfxFloat32 roughnessThreshold; ///< Regions with a roughness value greater than this threshold won't spawn specular rays. + FfxFloat32 environmentMapIntensity;///< The value to scale the contribution from the environment map. + FfxFloatCoords2D motionVectorScale; ///< The scale factor to apply to motion vectors. + + FfxResource sdfAtlas; ///< The SDF Atlas resource used by Brixelizer. + FfxResource bricksAABBs; ///< The brick AABBs resource used by Brixelizer. + FfxResource cascadeAABBTrees[24]; ///< The cascade AABB tree resources used by Brixelizer. + FfxResource cascadeBrickMaps[24]; ///< The cascade brick map resources used by Brixelizer. + + FfxResource outputDiffuseGI; ///< A texture to write the output diffuse GI calculated by Brixelizer GI. + FfxResource outputSpecularGI; ///< A texture to write the output specular GI calculated by Brixelizer GI. + + FfxBrixelizerRawContext *brixelizerContext; ///< A pointer to the Brixelizer context for use with Brixelizer GI. +} FfxBrixelizerGIDispatchDescription; + +/// An enumeration of which output mode to be used by Brixelizer GI debug visualization. +/// See FfxBrixelizerGIDebugDescription. +/// +/// @ingroup ffxBrixgi +typedef enum FfxBrixelizerGIDebugMode +{ + FFX_BRIXELIZER_GI_DEBUG_MODE_RADIANCE_CACHE, ///< Draw the radiance cache. + FFX_BRIXELIZER_GI_DEBUG_MODE_IRRADIANCE_CACHE, ///< Draw the irradiance cache. +} FfxBrixelizerGIDebugMode; + +/// A structure encapsulating the parameters for drawing a debug visualization. +/// +/// @ingroup ffxBrixgi +typedef struct FfxBrixelizerGIDebugDescription +{ + FfxFloat32x4x4 view; ///< The view matrix for the scene in row major order. + FfxFloat32x4x4 projection; ///< The projection matrix for the scene in row major order. + FfxUInt32 startCascade; ///< The index of the start cascade for use with ray marching with Brixelizer. + FfxUInt32 endCascade; ///< The index of the end cascade for use with ray marching with Brixelizer. + FfxUInt32 outputSize[2]; ///< The dimensions of the output texture. + FfxBrixelizerGIDebugMode debugMode; ///< The mode for the debug visualization. See FfxBrixelizerGIDebugMode. + FfxFloat32 normalsUnpackMul; ///< A multiply factor to transform the normal to the space expected by Brixelizer GI. + FfxFloat32 normalsUnpackAdd; ///< An offset to transform the normal to the space expected by Brixelizer GI. + + FfxResource depth; ///< The input depth buffer. + FfxResource normal; ///< The input normal buffer. + + FfxResource sdfAtlas; ///< The SDF Atlas resource used by Brixelizer. + FfxResource bricksAABBs; ///< The brick AABBs resource used by Brixelizer. + FfxResource cascadeAABBTrees[24]; ///< The cascade AABB tree resources used by Brixelizer. + FfxResource cascadeBrickMaps[24]; ///< The cascade brick map resources used by Brixelizer. + + FfxResource outputDebug; ///< The output texture for the debug visualization. + + FfxBrixelizerRawContext* brixelizerContext; ///< A pointer to the Brixelizer context for use with Brixelizer GI. +} FfxBrixelizerGIDebugDescription; + +/// An enumeration of all the passes which constitute the Brixelizer algorithm. +/// +/// Brixelizer GI is implemented as a composite of several compute passes each +/// computing a key part of the final result. Each call to the +/// FfxBrixelizerScheduleGpuJobFunc callback function will +/// correspond to a single pass included in FfxBrixelizerPass. For a +/// more comprehensive description of each pass, please refer to the Brixelizer +/// reference documentation. +/// +/// @ingroup ffxBrixgi +typedef enum FfxBrixelizerGIPass +{ + FFX_BRIXELIZER_GI_PASS_BLUR_X, + FFX_BRIXELIZER_GI_PASS_BLUR_Y, + FFX_BRIXELIZER_GI_PASS_CLEAR_CACHE, + FFX_BRIXELIZER_GI_PASS_EMIT_IRRADIANCE_CACHE, + FFX_BRIXELIZER_GI_PASS_EMIT_PRIMARY_RAY_RADIANCE, + FFX_BRIXELIZER_GI_PASS_FILL_SCREEN_PROBES, + FFX_BRIXELIZER_GI_PASS_INTERPOLATE_SCREEN_PROBES, + FFX_BRIXELIZER_GI_PASS_PREPARE_CLEAR_CACHE, + FFX_BRIXELIZER_GI_PASS_PROJECT_SCREEN_PROBES, + FFX_BRIXELIZER_GI_PASS_PROPAGATE_SH, + FFX_BRIXELIZER_GI_PASS_REPROJECT_GI, + FFX_BRIXELIZER_GI_PASS_REPROJECT_SCREEN_PROBES, + FFX_BRIXELIZER_GI_PASS_SPAWN_SCREEN_PROBES, + FFX_BRIXELIZER_GI_PASS_SPECULAR_PRE_TRACE, + FFX_BRIXELIZER_GI_PASS_SPECULAR_TRACE, + FFX_BRIXELIZER_GI_PASS_DEBUG_VISUALIZATION, + FFX_BRIXELIZER_GI_PASS_GENERATE_DISOCCLUSION_MASK, + FFX_BRIXELIZER_GI_PASS_DOWNSAMPLE, + FFX_BRIXELIZER_GI_PASS_UPSAMPLE, + + FFX_BRIXELIZER_GI_PASS_COUNT ///< The number of passes performed by Brixelizer GI. +} FfxBrixelizerGIPass; + +/// Get the size in bytes needed for an FfxBrixelizerGIContext struct. +/// Note that this function is provided for consistency, and the size of the +/// FfxBrixelizerGIContext is a known compile time value which can be +/// obtained using sizeof(FfxBrixelizerGIContext). +/// +/// @return The size in bytes of an FfxBrixelizerGIContext struct. +/// +/// @ingroup ffxBrixgi +inline size_t ffxBrixelizerGIGetContextSize() +{ + return sizeof(FfxBrixelizerGIContext); +} + +/// Create a FidelityFX Brixelizer GI context from the parameters +/// specified to the FfxBrixelizerGIContextDescription struct. +/// +/// The context structure is the main object used to interact with the Brixelizer GI API, +/// and is responsible for the management of the internal resources used by the +/// Brixelizer GI algorithm. When this API is called, multiple calls will be made via +/// the pointers contained in the backendInterface structure. This +/// backend will attempt to retrieve the device capabilities, and create the internal +/// resources, and pipelines required by Brixelizer GI. +/// +/// Depending on the parameters passed in via the pContextDescription a +/// different set of resources and pipelines may be requested by the callback functions. +/// +/// The FfxBrixelizerGIContext should be destroyed when use of it is completed. +/// To destroy the context you should call ffxBrixelizerGIContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxBrixelizerGIContext to populate. +/// @param [in] pContextDescription A pointer to a FfxBrixelizerGIContextDescription specifying the parameters for context creation. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The operation failed because either pContext or pContextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because pContextDescription->backendInterface was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error from the backend. +/// +/// @ingroup ffxBrixgi +FFX_API FfxErrorCode ffxBrixelizerGIContextCreate(FfxBrixelizerGIContext* pContext, const FfxBrixelizerGIContextDescription* pContextDescription); + +/// Destroy the FidelityFX Brixelizer GI context. +/// +/// @param [out] pContext A pointer to a FfxBrixelizerGIContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_INVALID_POINTER The pContext pointer provided was NULL. +/// +/// @ingroup ffxBrixgi +FFX_API FfxErrorCode ffxBrixelizerGIContextDestroy(FfxBrixelizerGIContext* pContext); + +/// Perform an update of Brixelizer GI, recording GPU commands to a command list. +/// +/// @param [inout] context An FfxBrixelizerGIContext containing the Brixelizer GI context. +/// @param [in] pDispatchDescription A pointer to a FfxBrixelizerGIDispatchDescription describing the dispatch to compute. +/// @param [inout] pCommandList An FfxCommandList to write GPU commands to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixgi +FFX_API FfxErrorCode ffxBrixelizerGIContextDispatch(FfxBrixelizerGIContext* pContext, const FfxBrixelizerGIDispatchDescription* pDispatchDescription, FfxCommandList pCommandList); + +/// Make a debug visualization from the FfxBrixelizerGIContext. +/// +/// @param [inout] context An FfxBrixelizerGIContext containing the Brixelizer GI context. +/// @param [in] pDebugDescription A pointer to a FfxBrixelizerGIDebugDescription describing the debug visualization to draw. +/// @param [inout] pCommandList An FfxCommandList to write GPU commands to. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup ffxBrixgi +FFX_API FfxErrorCode ffxBrixelizerGIContextDebugVisualization(FfxBrixelizerGIContext* pContext, const FfxBrixelizerGIDebugDescription* pDebugDescription, FfxCommandList pCommandList); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup ffxBrixgi +FFX_API FfxVersionNumber ffxBrixelizerGIGetEffectVersion(); + +#ifdef __cplusplus +} +#endif diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_classifier.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_classifier.h new file mode 100644 index 00000000..267154d6 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_classifier.h @@ -0,0 +1,288 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +// @defgroup Classifier + +#pragma once +#define FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT 4 + +// Include the interface for the backend of the FSR2 API. +#include + +/// @defgroup ffxClassifier FidelityFX Classifier +/// FidelityFX Classifier runtime library +/// +/// @ingroup SDKComponents + + +/// FidelityFX Classifier major version. +/// +/// @ingroup ffxClassifier +#define FFX_CLASSIFIER_VERSION_MAJOR (1) + +/// FidelityFX Classifier minor version. +/// +/// @ingroup ffxClassifier +#define FFX_CLASSIFIER_VERSION_MINOR (3) + +/// FidelityFX Classifier patch version. +/// +/// @ingroup ffxClassifier +#define FFX_CLASSIFIER_VERSION_PATCH (0) + +/// FidelityFX Classifier context count +/// +/// Defines the number of internal effect contexts required by Classifier +/// +/// @ingroup ffxClassifier +#define FFX_CLASSIFIER_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup ffxClassifier +#define FFX_CLASSIFIER_CONTEXT_SIZE (18500) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// Enum to specify which blur pass (currently only one). +/// +/// @ffxClassifier +typedef enum FfxClassifierPass +{ + FFX_CLASSIFIER_SHADOW_PASS_CLASSIFIER = 0, ///< The Tile Classification Pass + FFX_CLASSIFIER_REFLECTION_PASS_TILE_CLASSIFIER = 1, ///< Reflections tile classification pass + FFX_CLASSIFIER_PASS_COUNT ///< The number of passes in the Classifier effect +} FfxClassifierPass; + +/// An enumeration of bit flags used when creating a +/// FfxClassifierContext. See FfxClassifierContextDescription. +/// Currently, no flags exist. +/// +/// @ingroup ffxClassifier +typedef enum FfxClassifierInitializationFlagBits { + FFX_CLASSIFIER_SHADOW = (1 << 0), ///< A bit indicating the intent is to classify shadows + FFX_CLASSIFIER_CLASSIFY_BY_NORMALS = (1 << 1), ///< A bit indicating the intent is to classify by normals + FFX_CLASSIFIER_CLASSIFY_BY_CASCADES = (1 << 2), ///< A bit indicating the intent is to classify by cascades + FFX_CLASSIFIER_ENABLE_DEPTH_INVERTED = (1 << 3), ///< A bit indicating that the input depth buffer data provided is inverted [1..0]. + FFX_CLASSIFIER_REFLECTION = (1 << 4), ///< A bit indicating the intent is to classify reflections +} FfxClassifierInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX +/// Classifier. +/// +/// @ingroup ffxClassifier +typedef struct FfxClassifierContextDescription { + uint32_t flags; ///< A collection of @ref FfxClassifierInitializationFlagBits + FfxDimensions2D resolution; ///< Resolution of the shadow dispatch call + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX Classifier +} FfxClassifierContextDescription; + +/// A structure encapsulating the parameters for dispatching +/// of FidelityFX Classifier for shadows +/// +/// @ingroup ffxClassifier +typedef struct FfxClassifierShadowDispatchDescription { + FfxCommandList commandList; ///< The FfxCommandList to record Classifier rendering commands into. + FfxResource depth; ///< The FfxResource (SRV Texture 0)containing depth information + FfxResource normals; ///< The FfxResource (SRV Texture 1)containing normals information + FfxResource shadowMaps[FFX_CLASSIFIER_MAX_SHADOW_MAP_TEXTURES_COUNT]; ///< The FfxResource (SRV Texture 2)containing shadowMap(s) information + FfxResource workQueue; ///< The FfxResource (UAV Buffer 0)Work Queue: rwsb_tiles. + FfxResource workQueueCount; ///< The FfxResource (UAV Buffer 1)Work Queue Counter: rwb_tileCount + FfxResource rayHitTexture; ///< The FfxResource (UAV Texture 0)Ray Hit Texture + + FfxFloat32 normalsUnPackMul; ///< A multiply factor to transform the normal to the space expected by the Classifier + FfxFloat32 normalsUnPackAdd; ///< An offset to transform the normal to the space expected by the Classifier + + // Constant Data + FfxFloat32x3 lightDir; ///< The light direction + FfxFloat32 sunSizeLightSpace; ///< The sun size + FfxUInt32 tileCutOff; ///< The tile cutoff + + FfxBoolean bRejectLitPixels; ///< UI Setting, selects wheter to reject lit pixels in the shadows maps + FfxUInt32 cascadeCount; ///< The number of cascades + FfxFloat32 blockerOffset; ///< UI Setting, the blocker offsett + + FfxBoolean bUseCascadesForRayT; ///< UI Setting, selects whether to use the classifier to save ray intervals + FfxFloat32 cascadeSize; ///< The cascade size + + FfxFloat32x4 cascadeScale[4]; ///< A multiply factor for each cascade + FfxFloat32x4 cascadeOffset[4]; ///< An offeset factor for each cascade + + // Matrices + FfxFloat32 viewToWorld[16]; + FfxFloat32 lightView[16]; + FfxFloat32 inverseLightView[16]; + +} FfxClassifierShadowDispatchDescription; + +/// A structure encapsulating the parameters for dispatching +/// of FidelityFX Classifier for reflections +/// +/// @ingroup ffxClassifier +typedef struct FfxClassifierReflectionDispatchDescription { + FfxCommandList commandList; ///< The FfxCommandList to record Hybrid Reflections rendering commands into. + FfxResource depth; ///< A FfxResource containing the depth buffer for the current frame (at render resolution). + FfxResource motionVectors; ///< A FfxResource containing the motion vectors buffer for the current frame (at render resolution). + FfxResource normal; ///< A FfxResource containing the normal buffer for the current frame (at render resolution). + FfxResource materialParameters; ///< A FfxResource containing the aoRoughnessMetallic buffer for the current frame (at render resolution). + FfxResource environmentMap; ///< A FfxResource containing the environment map to fallback to when screenspace data is not sufficient + FfxResource radiance; + FfxResource varianceHistory; + FfxResource hitCounter; + FfxResource hitCounterHistory; + FfxResource rayList; + FfxResource rayListHW; + FfxResource extractedRoughness; + FfxResource rayCounter; + FfxResource denoiserTileList; + FfxDimensions2D renderSize; ///< The resolution that was used for rendering the input resources. + float invViewProjection[16]; ///< An array containing the inverse of the view projection matrix in column major layout. + float projection[16]; ///< An array containing the projection matrix in column major layout. + float invProjection[16]; ///< An array containing the inverse of the projection matrix in column major layout. + float view[16]; ///< An array containing the view matrix in column major layout. + float invView[16]; ///< An array containing the inverse of the view matrix in column major layout. + float prevViewProjection[16]; ///< An array containing the previous frame's view projection matrix in column major layout. + float iblFactor; ///< A factor to control the intensity of the image based lighting. Set to 1 for an HDR probe. + uint32_t frameIndex; + uint32_t samplesPerQuad; + uint32_t temporalVarianceGuidedTracingEnabled; + float globalRoughnessThreshold; + float rtRoughnessThreshold; + uint32_t mask; + uint32_t reflectionWidth; + uint32_t reflectionHeight; + float hybridMissWeight; + float hybridSpawnRate; + float vrtVarianceThreshold; + float reflectionsBackfacingThreshold; + uint32_t randomSamplesPerPixel; + float motionVectorScale[2]; + float normalsUnpackMul; + float normalsUnpackAdd; + uint32_t roughnessChannel; + bool isRoughnessPerceptual; +} FfxClassifierReflectionDispatchDescription; + +/// A structure encapsulating the FidelityFX Classifier context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by the Classifier. +/// +/// The FfxClassifierContext object should have a lifetime matching +/// your use of the Classifier. Before destroying the Classifier context care should be taken +/// to ensure the GPU is not accessing the resources created or used by the Classifier. +/// It is therefore recommended that the GPU is idle before destroying the +/// Classifier context. +/// +/// @ingroup ffxClassifier +typedef struct FfxClassifierContext { + uint32_t data[FFX_CLASSIFIER_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxClassifierContext; + +/// Create a FidelityFX Classifier context from the parameters +/// programmed to the FfxClassifierContextDescription structure. +/// +/// The context structure is the main object used to interact with the Classifier +/// API, and is responsible for the management of the internal resources +/// used by the Classifier. When this API is called, multiple calls +/// will be made via the pointers contained in the backendInterface +/// structure. This backend will attempt to retrieve the device capabilities, +/// and create the internal resources, and pipelines required by the Classifier to function. +/// Depending on the precise configuration used when +/// creating the FfxClassifierContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The FfxClassifierContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or the Classifier +/// is disabled by a user. To destroy the Classifier context you +/// should call FfxClassifierContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxClassifierContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxClassifierContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxClassifierContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxClassifier +FFX_API FfxErrorCode ffxClassifierContextCreate(FfxClassifierContext* pContext, const FfxClassifierContextDescription* pContextDescription); + +/// Dispatches work to the FidelityFX Classifier context for shadows +/// +/// @param [in] pContext A pointer to a FfxClassifierContext structure. +/// @param [in] pDispatchDescription A pointer to a FfxClassifierShadowDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxClassifier +FFX_API FfxErrorCode ffxClassifierContextShadowDispatch(FfxClassifierContext* pContext, const FfxClassifierShadowDispatchDescription* pDispatchDescription); + +/// Dispatches work to the FidelityFX Classifier context for reflections +/// +/// @param [in] pContext A pointer to a FfxClassifierContext structure. +/// @param [in] pDispatchDescription A pointer to a FfxClassifierReflectionDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxClassifier +FFX_API FfxErrorCode ffxClassifierContextReflectionDispatch(FfxClassifierContext* pContext, const FfxClassifierReflectionDispatchDescription* pDispatchDescription); + +/// Destroy the FidelityFX Classifier context. +/// +/// @param [out] pContext A pointer to a FfxClassifierContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxClassifier +FFX_API FfxErrorCode ffxClassifierContextDestroy(FfxClassifierContext* pContext); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup ffxClassifier +FFX_API FfxVersionNumber ffxClassifierGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_denoiser.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_denoiser.h new file mode 100644 index 00000000..5f9d23d7 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_denoiser.h @@ -0,0 +1,266 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +// Include the interface for the backend of the Denoiser API. +#include + +/// @defgroup FfxDenoiser FidelityFX Denoiser +/// FidelityFX Denoiser runtime library +/// +/// @ingroup SDKComponents + +/// FidelityFX Denoiser major version. +/// +/// @ingroup FfxDenoiser +#define FFX_DENOISER_VERSION_MAJOR (1) + +/// FidelityFX Denoiser minor version. +/// +/// @ingroup FfxDenoiser +#define FFX_DENOISER_VERSION_MINOR (3) + +/// FidelityFX Denoiser patch version. +/// +/// @ingroup FfxDenoiser +#define FFX_DENOISER_VERSION_PATCH (0) + +/// FidelityFX denoiser context count +/// +/// Defines the number of internal effect contexts required by the denoiser +/// +/// @ingroup FfxDenoiser +#define FFX_DENOISER_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup Denoiser +#define FFX_DENOISER_CONTEXT_SIZE (73098) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of the pass which constitutes the Denoiser algorithm. +/// +/// @ingroup Denoiser +typedef enum FfxDenoiserPass +{ + FFX_DENOISER_PASS_PREPARE_SHADOW_MASK = 0, + FFX_DENOISER_PASS_SHADOWS_TILE_CLASSIFICATION = 1, + FFX_DENOISER_PASS_FILTER_SOFT_SHADOWS_0 = 2, + FFX_DENOISER_PASS_FILTER_SOFT_SHADOWS_1 = 3, + FFX_DENOISER_PASS_FILTER_SOFT_SHADOWS_2 = 4, + FFX_DENOISER_PASS_REPROJECT_REFLECTIONS = 5, ///< A pass which reprojects and estimates the variance. + FFX_DENOISER_PASS_PREFILTER_REFLECTIONS = 6, ///< A pass which spatially filters the reflections. + FFX_DENOISER_PASS_RESOLVE_TEMPORAL_REFLECTIONS = 7, ///< A pass which temporally filters the reflections. + + FFX_DENOISER_PASS_COUNT ///< The number of passes in Denoiser +} FfxDenoiserPass; + +/// An enumeration of bit flags used when creating a +/// FfxDenoiserContext. See FfxDenoiserContextDescription. +/// +/// @ingroup FfxDenoiser +typedef enum FfxDenoiserInitializationFlagBits { + + FFX_DENOISER_SHADOWS = (1 << 0), ///< A bit indicating that the denoiser is used for denoising shadows + FFX_DENOISER_REFLECTIONS = (1 << 1), ///< A bit indicating that the denoiser is used for denoising reflections + FFX_DENOISER_ENABLE_DEPTH_INVERTED = (1 << 2), ///< A bit indicating that the input depth buffer data provided is inverted [1..0]. +} FfxDenoiserInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX Denoiser +/// +/// @ingroup FfxDenoiser +typedef struct FfxDenoiserContextDescription { + + uint32_t flags; ///< A collection of FfxDenoiserInitializationFlagBits + FfxDimensions2D windowSize; ///< The resolution that was used for rendering the input resource. + FfxSurfaceFormat normalsHistoryBufferFormat; ///< The format used by the reflections denoiser to store the normals buffer history + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX. +} FfxDenoiserContextDescription; + +/// A structure encapsulating the parameters for dispatching +/// of FidelityFX Denoiser +/// +/// @ingroup FfxDenoiser +typedef struct FfxDenoiserShadowsDispatchDescription { + + FfxCommandList commandList; ///< The FfxCommandList to record Denoiser rendering commands into. + FfxResource hitMaskResults; ///< A FfxResource containing the raytracing results where every pixel represents a 8x4 tile. + FfxResource depth; ///< A FfxResource containing 32bit depth values for the current frame. + FfxResource velocity; ///< A FfxResource containing 2-dimensional motion vectors. + FfxResource normal; ///< A FfxResource containing the normals. + FfxResource shadowMaskOutput; ///< A FfxResource which is used to store the fullscreen raytracing output. + + FfxFloat32x2 motionVectorScale; ///< A multiply factor to transform the motion vectors to the space expected by the shadow denoiser. + FfxFloat32 normalsUnpackMul; ///< A multiply factor to transform the normal to the space expected by the shadow denoiser. + FfxFloat32 normalsUnpackAdd; ///< An offset to transform the normal to the space expected by the shadow denoiser. + + FfxFloat32x3 eye; ///< The camera position + uint32_t frameIndex; ///< The current frame index + FfxFloat32 projectionInverse[16]; ///< The inverse of the camera projection matrix + FfxFloat32 reprojectionMatrix[16]; ///< The result of multiplying the projection matrix of the current frame by the result of the multiplication between the camera previous's frame view matrix by the inverse of the view-projection matrix + FfxFloat32 viewProjectionInverse[16]; ///< The inverse of the camera view-projection matrix + + FfxFloat32 depthSimilaritySigma; ///< A constant factor used in the denoising filters, defaults to 1.0f + +} FfxDenoiserShadowsDispatchDescription; + +/// A structure encapsulating the parameters for dispatching +/// of FidelityFX Denoiser +/// +/// @ingroup FfxDenoiser +typedef struct FfxDenoiserReflectionsDispatchDescription { + + FfxCommandList commandList; ///< The FfxCommandList to record Denoiser rendering commands into. + FfxResource depthHierarchy; ///< A FfxResource containing the depth buffer with full mip maps for the current frame. + FfxResource motionVectors; ///< A FfxResource containing the motion vectors buffer for the current frame. + FfxResource normal; ///< A FfxResource containing the normal buffer for the current frame. + FfxResource radianceA; ///< A FfxResource containing the ping-pong radiance buffers to filter. + FfxResource radianceB; ///< A FfxResource containing the ping-pong radiance buffers to filter. + FfxResource varianceA; ///< A FfxResource containing the ping-pong variance buffers used to filter and guide reflections. + FfxResource varianceB; ///< A FfxResource containing the ping-pong variance buffers used to filter and guide reflections. + FfxResource extractedRoughness; ///< A FfxResource containing the roughness of the current frame. + FfxResource denoiserTileList; ///< A FfxResource containing the tiles to be denoised. + FfxResource indirectArgumentsBuffer; ///< A FfxResource containing the indirect arguments used by the indirect dispatch calls tha compose the denoiser. + FfxResource output; ///< A FfxResource to store the denoised reflections. + FfxDimensions2D renderSize; ///< The resolution that was used for rendering the input resources. + FfxFloatCoords2D motionVectorScale; ///< The scale factor to apply to motion vectors. + float invProjection[16]; ///< An array containing the inverse of the projection matrix in column major layout. + float invView[16]; ///< An array containing the inverse of the view matrix in column major layout. + float prevViewProjection[16]; ///< An array containing the view projection matrix of the previous frame in column major layout. + float normalsUnpackMul; ///< A multiply factor to transform the normal to the space expected by SSSR. + float normalsUnpackAdd; ///< An offset to transform the normal to the space expected by SSSR. + bool isRoughnessPerceptual; ///< A boolean to describe the space used to store roughness in the materialParameters texture. If false, we assume roughness squared was stored in the Gbuffer. + uint32_t roughnessChannel; ///< The channel to read the roughness from the materialParameters texture + float temporalStabilityFactor; ///< A boolean to describe the space used to store roughness in the materialParameters texture. If false, we assume roughness squared was stored in the Gbuffer. + float roughnessThreshold; ///< Regions with a roughness value greater than this threshold won't spawn rays. + uint32_t frameIndex; ///< The index of the current frame. + bool reset; +} FfxDenoiserReflectionsDispatchDescription; + + +/// A structure encapsulating the FidelityFX denoiser context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by Denoiser. +/// +/// The FfxDenoiserContext object should have a lifetime matching +/// your use of Denoiser. Before destroying the Denoiser context care should be taken +/// to ensure the GPU is not accessing the resources created or used by Denoiser. +/// It is therefore recommended that the GPU is idle before destroying the +/// Denoiser context. +/// +/// @ingroup FfxDenoiser +typedef struct FfxDenoiserContext { + + uint32_t data[FFX_DENOISER_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxDenoiserContext; + +/// Create a FidelityFX Denoiser context from the parameters +/// programmed to the FfxDenoiserContextDescription structure. +/// +/// The context structure is the main object used to interact with the +/// Denoiser API, and is responsible for the management of the internal resources +/// used by the Denoiser algorithm. When this API is called, multiple calls +/// will be made via the pointers contained in the backendInterface +/// structure. This backend will attempt to retrieve the device capabilities, +/// and create the internal resources, and pipelines required by Denoiser to function. +/// Depending on the precise configuration used when +/// creating the FfxDenoiserContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The FfxDenoiserContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or shadow +/// denoising is disabled by a user. To destroy the Denoiser context you +/// should call ffxDenoiserContextDestroy. +/// +/// @param [out] context A pointer to a FfxDenoiserContext structure to populate. +/// @param [in] contextDescription A pointer to a FfxDenoiserContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxDenoiserContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxDenoiser +FFX_API FfxErrorCode ffxDenoiserContextCreate(FfxDenoiserContext* pContext, const FfxDenoiserContextDescription* pContextDescription); + +/// Dispatches work to the FidelityFX Denoiser context +/// +/// @param [out] context A pointer to a FfxDenoiserContext structure to populate. +/// @param [in] dispatchDescription A pointer to a FfxDenoiserShadowsDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxDenoiser +FFX_API FfxErrorCode ffxDenoiserContextDispatchShadows(FfxDenoiserContext* context, const FfxDenoiserShadowsDispatchDescription* dispatchDescription); + +/// Dispatches work to the FidelityFX Denoiser context +/// +/// @param [out] context A pointer to a FfxDenoiserContext structure to populate. +/// @param [in] dispatchDescription A pointer to a FfxDenoiserReflectionsDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxDenoiser +FFX_API FfxErrorCode ffxDenoiserContextDispatchReflections(FfxDenoiserContext* context, const FfxDenoiserReflectionsDispatchDescription* dispatchDescription); + +/// Destroy the FidelityFX Denoiser context. +/// +/// @param [out] context A pointer to a FfxDenoiserContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context was NULL. +/// +/// @ingroup FfxDenoiser +FFX_API FfxErrorCode ffxDenoiserContextDestroy(FfxDenoiserContext* context); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup FfxDenoiser +FFX_API FfxVersionNumber ffxDenoiserGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_dof.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_dof.h new file mode 100644 index 00000000..58ac2f4c --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_dof.h @@ -0,0 +1,263 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +// @defgroup DOF + +#pragma once + +// Include the interface for the backend of the FSR2 API. +#include + +/// @defgroup ffxDof FidelityFX DoF +/// FidelityFX Depth of Field runtime library +/// +/// @ingroup SDKComponents + + +/// FidelityFX DOF major version. +/// +/// @ingroup ffxDof +#define FFX_DOF_VERSION_MAJOR (1) + +/// FidelityFX DOF minor version. +/// +/// @ingroup ffxDof +#define FFX_DOF_VERSION_MINOR (1) + +/// FidelityFX DOF patch version. +/// +/// @ingroup ffxDof +#define FFX_DOF_VERSION_PATCH (0) + +/// FidelityFX DOF context count +/// +/// Defines the number of internal effect contexts required by DOF +/// +/// @ingroup ffxDof +#define FFX_DOF_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup ffxDof +#define FFX_DOF_CONTEXT_SIZE (45674) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of the passes which constitute the DoF algorithm. +/// +/// DOF is implemented as a composite of several compute passes each +/// computing a key part of the final result. Each call to the +/// FfxDofScheduleGpuJobFunc callback function will +/// correspond to a single pass included in FfxDofPass. For a +/// more comprehensive description of each pass, please refer to the DoF +/// reference documentation. +/// +/// @ingroup ffxDof +typedef enum FfxDofPass { + FFX_DOF_PASS_DOWNSAMPLE_DEPTH = 0, ///< A pass which downsamples the depth buffer + FFX_DOF_PASS_DOWNSAMPLE_COLOR = 1, ///< A pass which downsamples the color buffer + FFX_DOF_PASS_DILATE = 2, ///< A pass which dilates the depth tile buffer + FFX_DOF_PASS_BLUR = 3, ///< A pass which performs the depth of field blur + FFX_DOF_PASS_COMPOSITE = 4, ///< A pass which combines the blurred images with the sharp input + FFX_DOF_PASS_COUNT ///< The number of passes in DOF +} FfxDofPass; + +/// An enumeration of bit flags used when creating a +/// FfxDofContext. See FfxDofContextDescription. +/// Curently, no flags exist. +/// +/// @ingroup ffxDof +typedef enum FfxDofInitializationFlagBits { + FFX_DOF_REVERSE_DEPTH = (1 << 0), ///< A bit indicating whether input depth is reversed (1 is closest) + FFX_DOF_OUTPUT_PRE_INIT = (1 << 1), ///< A bit indicating whether the output is pre-initialized with the input color (e.g. it is the same texture) + FFX_DOF_DISABLE_RING_MERGE = (1 << 2), ///< A bit indicating whether to disable merging kernel rings +} FfxDofInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX +/// Depth of Field. +/// +/// @ingroup ffxDof +typedef struct FfxDofContextDescription { + uint32_t flags; ///< A collection of @ref FfxDofInitializationFlagBits + uint32_t quality; ///< The number of rings to be used in the DoF blur kernel + FfxDimensions2D resolution; ///< Resolution of the input and output textures + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX + float cocLimitFactor; ///< The limit to apply to circle of confusion size as a factor for resolution height +} FfxDofContextDescription; + +/// A structure encapsulating the parameters for dispatching +/// of FidelityFX Depth of Field +/// +/// @ingroup ffxDof +typedef struct FfxDofDispatchDescription { + FfxCommandList commandList; ///< The FfxCommandList to record DoF rendering commands into. + FfxResource color; ///< The FfxResource containing color information + FfxResource depth; ///< The FfxResource containing depth information + FfxResource output; ///< The FfxResource to output into. Can be the same as the color input. + float cocScale; ///< The factor converting depth to circle of confusion size. Can be calculated using ffxDofCalculateCocScale. + float cocBias; ///< The bias to apply to circle of confusion size. Can be calculated using ffxDofCalculateCocBias. +} FfxDofDispatchDescription; + +/// A structure encapsulating the FidelityFX Depth of Field context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by DoF. +/// +/// The FfxDofContext object should have a lifetime matching +/// your use of DoF. Before destroying the DoF context care should be taken +/// to ensure the GPU is not accessing the resources created or used by DoF. +/// It is therefore recommended that the GPU is idle before destroying the +/// DoF context. +/// +/// @ingroup ffxDof +typedef struct FfxDofContext { + uint32_t data[FFX_DOF_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxDofContext; + +/// Create a FidelityFX Depth of Field context from the parameters +/// programmed to the FfxDofContextDescription structure. +/// +/// The context structure is the main object used to interact with the Depth of +/// Field API, and is responsible for the management of the internal resources +/// used by the DoF algorithm. When this API is called, multiple calls +/// will be made via the pointers contained in the backendInterface +/// structure. This backend will attempt to retrieve the device capabilities, +/// and create the internal resources, and pipelines required by DoF to function. +/// Depending on the precise configuration used when +/// creating the FfxDofContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The FfxDofContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or DoF +/// is disabled by a user. To destroy the DoF context you +/// should call ffxDofContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxDofContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxDofContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxDofContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxDof +FFX_API FfxErrorCode ffxDofContextCreate(FfxDofContext* pContext, const FfxDofContextDescription* pContextDescription); + +/// Dispatches work to the FidelityFX DoF context +/// +/// @param [in] pContext A pointer to a FfxDofContext structure. +/// @param [in] pDispatchDescription A pointer to a FfxDofDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxDof +FFX_API FfxErrorCode ffxDofContextDispatch(FfxDofContext* pContext, const FfxDofDispatchDescription* pDispatchDescription); + +/// Destroy the FidelityFX DoF context. +/// +/// @param [out] pContext A pointer to a FfxDofContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because context was NULL. +/// +/// @ingroup ffxDof +FFX_API FfxErrorCode ffxDofContextDestroy(FfxDofContext* pContext); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup ffxDof +FFX_API FfxVersionNumber ffxDofGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) + + +/// Calculates the scale parameter in the thin lens model according to lens and projection parameters. +/// @param aperture Aperture radius in view space units +/// @param focus Distance to focus plane in view space units +/// @param focalLength Lens focal length in view space units +/// @param conversion Conversion factor for view units to pixels (i.e. image width in pixels / sensor size) +/// @param proj33 Element (3,3) of the projection matrix (z range scale) +/// @param proj34 Element (3,4) of the projection matrix (z range offset) +/// @param proj43 Element (4,3) of the projection matrix (typically 1 or -1) +/// +/// @ingroup ffxDof +static inline float ffxDofCalculateCocScale(float aperture, float focus, float focalLength, float conversion, + float proj33, float proj34, float proj43) +{ + (void)proj33; + // z = (vd * proj33 + proj34) / (vd * proj43) = proj33/proj43 + proj34/(vd*proj43) + // => view depth = proj34 / (z*proj43 - proj33) + // C = (A * L * (F - D)) / (D * (F - L)) + // = AL/(F-L) * (F/D - 1) + // = AL/(F-L) * (F(z*p43-p33)/p34 - 1) ignore non-factor terms + // = AL/(F-L) * (F(z*p43-.)/p34 - .) + // = AL/(F-L) * (F(z*p43-.)/p34 - .) + // = AL/(F-L) * F*z*p43/p34 + . + // = z * AL/(F-L) * F*p43/p34 + . + float absFocus = focus < 0 ? -focus : focus; + float commonFactor = conversion * aperture * focalLength / (absFocus - focalLength); + return commonFactor * focus * (proj43 / proj34); +} + +/// Calculates the bias parameter in the thin lens model according to lens and projection parameters. +/// @param aperture Aperture radius in view space units +/// @param focus Distance to focus plane in view space units +/// @param focalLength Lens focal length in view space units +/// @param conversion Conversion factor for view units to pixels (i.e. image width in pixels / sensor size) +/// @param proj33 Element (3,3) of the projection matrix (a.k.a. z range scale) +/// @param proj34 Element (3,4) of the projection matrix (a.k.a. z range offset) +/// @param proj43 Element (4,3) of the projection matrix (typically 1 or -1) +/// +/// @ingroup ffxDof +static inline float ffxDofCalculateCocBias(float aperture, float focus, float focalLength, float conversion, + float proj33, float proj34, float proj43) +{ + (void)proj43; + // z = (D * proj33 + proj34) / (D * proj43) = proj33/proj43 + proj34/(D*proj43) + // => view depth D = proj34 / (z*proj43 - proj33) + // C = (A * L * (F - D)) / (D * (F - L)) + // = AL/(F-L) * (F/D - 1) + // = AL/(F-L) * (F(z*p43-p33)/p34 - 1) ignore factor terms + // = AL/(F-L) * (F(0*p43-p33)/p34 - 1) + // = AL/(F-L) * (-F*p33/p34 - 1) + float absFocus = focus < 0 ? -focus : focus; + float commonFactor = conversion * aperture * focalLength / (absFocus - focalLength); + return commonFactor * (-focus * (proj33 / proj34) - 1); +} diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_lens.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_lens.h new file mode 100644 index 00000000..bb111697 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_lens.h @@ -0,0 +1,216 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +// @defgroup Lens + +#pragma once + +// Include the interface for the backend of the Lens API. +#include + +/// @defgroup FfxLens FidelityFX Lens +/// FidelityFX Lens runtime library +/// +/// @ingroup SDKComponents + +/// FidelityFX Lens major version. +/// +/// @ingroup FfxLens +#define FFX_LENS_VERSION_MAJOR (1) + +/// FidelityFX Lens minor version. +/// +/// @ingroup FfxLens +#define FFX_LENS_VERSION_MINOR (1) + +/// FidelityFX Lens patch version. +/// +/// @ingroup FfxLens +#define FFX_LENS_VERSION_PATCH (0) + +/// FidelityFX Lens context count +/// +/// Defines the number of internal effect contexts required by Lens +/// +/// @ingroup FfxLens +#define FFX_LENS_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup FfxLens +#define FFX_LENS_CONTEXT_SIZE (9200) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of the pass which constitutes the Lens algorithm. +/// +/// Lens is implemented as a single pass algorithm. Each call to the +/// FfxLensScheduleGpuJobFunc callback function will +/// correspond to a single lens effect compute job. For a +/// more comprehensive description of Lens's inner workings, please +/// refer to the Lens reference documentation. +/// +/// @ingroup FfxLens +typedef enum FfxLensPass +{ + FFX_LENS_PASS_MAIN_PASS = 0, ///< A pass which which applies the lens effect + FFX_LENS_PASS_COUNT ///< The number of passes in Lens +} FfxLensPass; + +typedef enum FfxLensFloatPrecision +{ + FFX_LENS_FLOAT_PRECISION_32BIT = 0, + FFX_LENS_FLOAT_PRECISION_16BIT = 1, + FFX_LENS_FLOAT_PRECISION_COUNT = 2 +} FfxLensFloatPrecision; + +/// An enumeration of bit flags used when creating a +/// FfxLensContext. See FfxLensContextDescription. +/// +/// @ingroup FfxLens +typedef enum FfxLensInitializationFlagBits { + + FFX_LENS_MATH_NONPACKED = (1 << 0), ///< A bit indicating if we should use floating point math + FFX_LENS_MATH_PACKED = (1 << 1) ///< A bit indicating if we should use 16-bit half precision floating point math (favored) + +} FfxLensInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX +/// Lens. +/// +/// @ingroup FfxLens +typedef struct FfxLensContextDescription { + + uint32_t flags; ///< A collection of FfxLensInitializationFlagBits + FfxSurfaceFormat outputFormat; ///< Format of the output target used for creation of output resource. + FfxLensFloatPrecision floatPrecision; ///< A flag indicating the desired floating point precision for use in ffxBlurContextDispatch + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX. + +} FfxLensContextDescription; + +/// A structure encapsulating the parameters for dispatching +/// of FidelityFX Lens +/// +/// @ingroup FfxLens +typedef struct FfxLensDispatchDescription { + + FfxCommandList commandList; ///< The FfxCommandList to record Lens rendering commands into. + FfxResource resource; ///< The FfxResource to run Lens on. + FfxResource resourceOutput; ///< The FfxResource to write Lens output to. + FfxDimensions2D renderSize; ///< The resolution used for rendering the scene. + float grainScale; ///< Artistic tweaking constant for grain scale.. + float grainAmount; ///< Artistic tweaking constant for how intense the grain is. + uint32_t grainSeed; ///< The seed for grain RNG. + float chromAb; ///< Artistic tweaking constant for chromatic aberration intensity. + float vignette; ///< Artistic tweaking constant for vignette intensity. + +} FfxLensDispatchDescription; + +/// A structure encapsulating the FidelityFX Lens context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by Lens. +/// +/// The FfxLensContext object should have a lifetime matching +/// your use of Lens. Before destroying the Lens context care should be taken +/// to ensure the GPU is not accessing the resources created or used by Lens. +/// It is therefore recommended that the GPU is idle before destroying the +/// Lens context. +/// +/// @ingroup FfxLens +typedef struct FfxLensContext { + uint32_t data[FFX_LENS_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxLensContext; + +/// Create a FidelityFX Lens Downsampler context from the parameters +/// programmed to the FfxLensContextDescription structure. +/// +/// The context structure is the main object used to interact with the Lens +/// API, and is responsible for the management of the internal resources +/// used by the Lens algorithm. When this API is called, multiple calls +/// will be made via the pointers contained in the backendInterface +/// structure. This backend will attempt to retrieve the device capabilities, +/// and create the internal resources, and pipelines required by Lens to function. +/// Depending on the precise configuration used when +/// creating the FfxLensContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The FfxLensContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or Lens +/// upscaling is disabled by a user. To destroy the Lens context you +/// should call ffxLensContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxLensContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxLensContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxLensContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxLens +FFX_API FfxErrorCode ffxLensContextCreate(FfxLensContext* pContext, const FfxLensContextDescription* pContextDescription); + +/// Dispatches work to the FidelityFX Lens context +/// +/// @param [out] pContext A pointer to a FfxLensContext structure to populate. +/// @param [in] pDispatchDescription A pointer to a FfxLensDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxLens +FFX_API FfxErrorCode ffxLensContextDispatch(FfxLensContext* pContext, const FfxLensDispatchDescription* pDispatchDescription); + +/// Destroy the FidelityFX Lens context. +/// +/// @param [out] pContext A pointer to a FfxLensContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context was NULL. +/// +/// @ingroup FfxLens +FFX_API FfxErrorCode ffxLensContextDestroy(FfxLensContext* pContext); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup FfxLens +FFX_API FfxVersionNumber ffxLensGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_lpm.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_lpm.h new file mode 100644 index 00000000..14f65f62 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_lpm.h @@ -0,0 +1,273 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +// @defgroup LPM + +#pragma once + +// Include the interface for the backend of the LPM 1.0 API. +#include + +/// @defgroup FfxLpm FidelityFX LPM +/// FidelityFX Luma Preserving Mapper runtime library +/// +/// @ingroup SDKComponents + +/// FidelityFX Luma Preserving Mapper 1.3 major version. +/// +/// @ingroup FfxLpm +#define FFX_LPM_VERSION_MAJOR (1) + +/// FidelityFX Luma Preserving Mapper 1.3 minor version. +/// +/// @ingroup FfxLpm +#define FFX_LPM_VERSION_MINOR (4) + +/// FidelityFX Luma Preserving Mapper 1.3 patch version. +/// +/// @ingroup FfxLpm +#define FFX_LPM_VERSION_PATCH (0) + +/// FidelityFX Luma Preserving Mapper context count +/// +/// Defines the number of internal effect contexts required by LPM +/// +/// @ingroup FfxLpm +#define FFX_LPM_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup FfxLpm +#define FFX_LPM_CONTEXT_SIZE (9300) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of all the passes which constitute the LPM algorithm. +/// +/// LPM is implemented as a composite of several compute passes each +/// computing a key part of the final result. Each call to the +/// FfxLPMScheduleGpuJobFunc callback function will +/// correspond to a single pass included in FfxLPMPass. For a +/// more comprehensive description of each pass, please refer to the LPM +/// reference documentation. +/// +/// @ingroup FfxLpm +typedef enum FfxLpmPass +{ + + FFX_LPM_PASS_FILTER = 0, ///< A pass which filters the color buffer using LPM's tone and gamut mapping solution. + + FFX_LPM_PASS_COUNT ///< The number of passes performed by LPM. +} FfxLpmPass; + +/// An enumeration of monitor display modes supported by LPM +/// FFX_LPM_DISPLAYMODE_LDR tagets low or standard dynamic range monitor using 8bit back buffer +/// FFX_LPM_DISPLAYMODE_HDR10_2084 targets HDR10 perceptual quantizer (PQ) transfer function using 10bit backbuffer +/// FFX_LPM_DISPLAYMODE_HDR10_SCRGB targets HDR10 linear output with no transfer function using 16bit backbuffer +/// FFX_LPM_DISPLAYMODE_FSHDR_2084 targets freesync premium pro hdr thorugh PQ transfer function using 10bit backbuffer +/// FFX_LPM_DISPLAYMODE_FSHDR_SCRGB targets linear output with no transfer function using 16bit backbuffer +/// @ingroup LPM +typedef enum class FfxLpmDisplayMode +{ + FFX_LPM_DISPLAYMODE_LDR = 0, + FFX_LPM_DISPLAYMODE_HDR10_2084 = 1, + FFX_LPM_DISPLAYMODE_HDR10_SCRGB = 2, + FFX_LPM_DISPLAYMODE_FSHDR_2084 = 3, + FFX_LPM_DISPLAYMODE_FSHDR_SCRGB = 4 +} FfxLpmDisplayMode; + +/// An enumeration of colourspaces supported by LPM +/// FFX_LPM_ColorSpace_REC709 uses rec709 colour primaries used for FFX_LPM_DISPLAYMODE_LDR, FFX_LPM_DISPLAYMODE_HDR10_SCRGB and FFX_LPM_DISPLAYMODE_FSHDR_SCRGB modes +/// FFX_LPM_ColorSpace_P3 uses P3 colour primaries +/// FFX_LPM_ColorSpace_REC2020 uses rec2020 colour primaries used for FFX_LPM_DISPLAYMODE_HDR10_2084 and FFX_LPM_DISPLAYMODE_FSHDR_2084 modes +/// FFX_LPM_ColorSapce_Display uses custom primaries queried from display +/// @ingroup LPM +typedef enum class FfxLpmColorSpace +{ + FFX_LPM_ColorSpace_REC709 = 0, + FFX_LPM_ColorSpace_P3 = 1, + FFX_LPM_ColorSpace_REC2020 = 2, + FFX_LPM_ColorSapce_Display = 3, +} FfxLpmColorSpace; + +/// An enumeration of bit flags used when creating a +/// FfxLpmContext. See FfxLpmContextDescription. +/// +/// @ingroup FfxLpm +typedef enum FfxLpmInitializationFlagBits +{ +} FfxLpmInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX +/// Luma Preserving Mapper +/// +/// @ingroup FfxLpm +typedef struct FfxLpmContextDescription +{ + uint32_t flags; + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for LPM. +} FfxLpmContextDescription; + +/// A structure encapsulating the parameters for dispatching the various passes +/// of FidelityFX Luma Preserving Mapper 1.0 +/// +/// @ingroup FfxLpm +typedef struct FfxLpmDispatchDescription +{ + FfxCommandList commandList; ///< The FfxCommandList to record LPM rendering commands into. + FfxResource inputColor; ///< A FfxResource containing the color buffer for the current frame. + FfxResource outputColor; ///< A FfxResource containing the tone and gamut mapped output color buffer for the current frame. + bool shoulder; + float softGap; + float hdrMax; + float lpmExposure; + float contrast; + float shoulderContrast; + float saturation[3]; + float crosstalk[3]; + FfxLpmColorSpace colorSpace; + FfxLpmDisplayMode displayMode; + float displayRedPrimary[2]; + float displayGreenPrimary[2]; + float displayBluePrimary[2]; + float displayWhitePoint[2]; + float displayMinLuminance; + float displayMaxLuminance; +} FfxLpmDispatchDescription; + +/// A structure encapsulating the FidelityFX Luma Preserving 1.0 context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by LPM. +/// +/// The FfxLpmContext object should have a lifetime matching +/// your use of LPM. Before destroying the LPM context care should be taken +/// to ensure the GPU is not accessing the resources created or used by LPM. +/// It is therefore recommended that the GPU is idle before destroying the +/// LPM context. +/// +/// @ingroup FfxLpm +typedef struct FfxLpmContext +{ + uint32_t data[FFX_LPM_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxLpmContext; + +/// Create a FidelityFX Luma Preserving 1.0 context from the parameters +/// programmed to the FfxLpmContextDescription structure. +/// +/// The context structure is the main object used to interact with the Luma Preserving +/// Mapper 1.0 API, and is responsible for the management of the internal resources +/// used by the LPM algorithm. When this API is called, multiple calls +/// will be made via the pointers contained in the callbacks +/// structure. These callbacks will attempt to retreive the device capabilities, +/// and create the internal resources, and pipelines required by LPM +/// frame-to-frame function. Depending on the precise configuration used when +/// creating the FfxLpmContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The FfxLpmContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or LPM +/// tone and gamut mapping is disabled by a user. To destroy the LPM context you +/// should call ffxLpmContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxLpmContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxLpmContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxLpmContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxLpm +FFX_API FfxErrorCode ffxLpmContextCreate(FfxLpmContext* pContext, const FfxLpmContextDescription* pContextDescription); + +/// Dispatches work to the FidelityFX LPM context +/// @param [out] pContext A pointer to a FfxLpmContext structure to populate. +/// @param [in] pDispatchDescription A pointer to a FfxLpmDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxLpm +FFX_API FfxErrorCode ffxLpmContextDispatch(FfxLpmContext* pContext, const FfxLpmDispatchDescription* pDispatchDescription); + +/// Destroy the FidelityFX LPM context. +/// +/// @param [out] pContext A pointer to a FfxLpmContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context was NULL. +/// +/// @ingroup FfxLpm +FFX_API FfxErrorCode ffxLpmContextDestroy(FfxLpmContext* pContext); + +/// Sets up the constant buffer data necessary for LPM compute +/// +/// @param [in] incon +/// @param [in] insoft +/// @param [in] incon2 +/// @param [in] inclip +/// @param [in] inscaleOnly +/// @param [out] outcon +/// @param [out] outsoft +/// @param [out] outcon2 +/// @param [out] outclip +/// @param [out] outscaleOnly +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// +/// @ingroup FfxLpm +FFX_API FfxErrorCode FfxPopulateLpmConsts(bool incon, + bool insoft, + bool incon2, + bool inclip, + bool inscaleOnly, + uint32_t& outcon, + uint32_t& outsoft, + uint32_t& outcon2, + uint32_t& outclip, + uint32_t& outscaleOnly); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup FfxLpm +FFX_API FfxVersionNumber ffxLpmGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_parallelsort.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_parallelsort.h new file mode 100644 index 00000000..f74b3598 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_parallelsort.h @@ -0,0 +1,210 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +// @defgroup PARALLEL_SORT + +#pragma once + +// Include the interface for the backend of the FSR2 API. +#include + +/// @defgroup FfxParallelSort FidelityFX Parallel Sort +/// FidelityFX Single Pass Downsampler runtime library +/// +/// @ingroup SDKComponents + +/// FidelityFX Parallel Sort major version. +/// +/// @ingroup FfxParallelSort +#define FFX_PARALLELSORT_VERSION_MAJOR (1) + +/// FidelityFX Parallel Sort minor version. +/// +/// @ingroup FfxParallelSort +#define FFX_PARALLELSORT_VERSION_MINOR (3) + +/// FidelityFX Parallel Sort patch version. +/// +/// @ingroup FfxParallelSort +#define FFX_PARALLELSORT_VERSION_PATCH (0) + +/// FidelityFX SPD context count +/// +/// Defines the number of internal effect contexts required by SPD +/// +/// @ingroup FfxParallelSort +#define FFX_PARALLELSORT_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup FfxParallelSort +#define FFX_PARALLELSORT_CONTEXT_SIZE (373794) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of the passes which constitute the Parallel Sort algorithm. +/// +/// Parallel Sort is implemented as a multi-pass algorithm that is invoked over +/// a number of successive iterations until all bits in the key are sorted. +/// For a more comprehensive description of Parallel Sort's inner workings, please +/// refer to the Parallel Sort reference documentation. +/// +/// @ingroup FfxParallelSort +typedef enum FfxParallelSortPass +{ + + FFX_PARALLELSORT_PASS_SETUP_INDIRECT_ARGS = 0, ///< A pass which sets up indirect params to invoke sorting when FFX_PARALLEL_SORT_INDIRECT flag bit is set. + FFX_PARALLELSORT_PASS_SUM, ///< A pass which counts the number of occurrences of each value in the data set. + FFX_PARALLELSORT_PASS_REDUCE, ///< A pass which further reduces the counts across thread groups for faster offset calculations in large data sets. + FFX_PARALLELSORT_PASS_SCAN, ///< A pass which prefixes the count totals into global offsets. + FFX_PARALLELSORT_PASS_SCAN_ADD, ///< A pass which does a second prefix add the global offsets to each local thread group offset. + FFX_PARALLELSORT_PASS_SCATTER, ///< A pass which performs a local sort of all values in the thread group and outputs to new global offset + + FFX_PARALLELSORT_PASS_COUNT ///< The number of passes in Parallel Sort +} FfxParallelSortPass; + +/// An enumeration of bit flags used when creating a +/// FfxParallelSortContextDescription. See FfxParallelSortContextDescription. +/// +/// @ingroup FfxParallelSort +typedef enum FfxParallelSortInitializationFlagBits { + + FFX_PARALLELSORT_INDIRECT_SORT = (1 << 0), ///< A bit indicating if we should use indirect version of sort algorithm + FFX_PARALLELSORT_PAYLOAD_SORT = (1 << 1), ///< A bit indicating if we should sort a payload buffer + +} FfxParallelSortInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX +/// Parallel Sort. +/// +/// @ingroup FfxParallelSort +typedef struct FfxParallelSortContextDescription { + + uint32_t flags; ///< A collection of FfxParallelSortInitializationFlagBits. + uint32_t maxEntries; ///< Maximum number of entries to sort + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX. +} FfxParallelSortContextDescription; + +/// A structure encapsulating the parameters needed to sort +/// the buffer(s) provided +/// +/// @ingroup FfxParallelSort +typedef struct FfxParallelSortDispatchDescription { + + FfxCommandList commandList; ///< The FfxCommandList to record parallel sort compute commands into. + FfxResource keyBuffer; ///< The buffer resource containing the keys to sort + FfxResource payloadBuffer; ///< The (optional) payload buffer to sort (requires FFX_PARALLELSORT_PAYLOAD_SORT be set) + uint32_t numKeysToSort; ///< The number of keys in the buffer requiring sorting +} FfxParallelSortDispatchDescription; + +/// A structure encapsulating the FidelityFX Parallel Sort context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by parallel sort. +/// +/// The FfxParallelSortContext object should have a lifetime matching +/// your use of parallel sort. Before destroying the parallel sort context care +/// should be taken to ensure the GPU is not accessing the resources created or +/// used by parallel sort. It is therefore recommended that the GPU is idle +/// before destroying the parallel sort context. +/// +/// @ingroup FfxParallelSort +typedef struct FfxParallelSortContext { + + uint32_t data[FFX_PARALLELSORT_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxParallelSortContext; + + +/// Create a FidelityFX Parallel Sort context from the parameters +/// programmed to the FfxParallelSortContextDescription structure. +/// +/// The context structure is the main object used to interact with the parallel +/// sort API, and is responsible for the management of the internal resources +/// used by the parallel sort algorithm. When this API is called, multiple calls +/// will be made via the pointers contained in the callbacks +/// structure. These callbacks will attempt to retreive the device capabilities, +/// and create the internal resources, and pipelines required by parallel sorts' +/// frame-to-frame function. Depending on the precise configuration used when +/// creating the FfxParallelSortContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The FfxParallelSortContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or parallel sort +/// upscaling is disabled by a user. To destroy the parallel sort context you +/// should call ffxParallelSortContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxParallelSortContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxParallelSortContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxFsr2ContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxParallelSort +FFX_API FfxErrorCode ffxParallelSortContextCreate(FfxParallelSortContext* pContext, const FfxParallelSortContextDescription* pContextDescription); + +/// Execute a FidelityFX Parallel Sort context to sort the provided data +/// according to the passed in dispatch description. +/// +/// @param [out] pContext A pointer to a FfxParallelSortContext structure to populate. +/// @param [in] pDispatchDescription A pointer to a FfxParallelSortDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or sortDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxParallelSort +FFX_API FfxErrorCode ffxParallelSortContextDispatch(FfxParallelSortContext* pContext, const FfxParallelSortDispatchDescription* pDispatchDescription); + +/// Destroy the FidelityFX Parallel Sort context. +/// +/// @param [out] pContext A pointer to a FfxParallelSortContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context was NULL. +/// +/// @ingroup FfxParallelSort +FFX_API FfxErrorCode ffxParallelSortContextDestroy(FfxParallelSortContext* pContext); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup FfxParallelSort +FFX_API FfxVersionNumber ffxParallelSortGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_spd.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_spd.h new file mode 100644 index 00000000..14e3230e --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_spd.h @@ -0,0 +1,222 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +// @defgroup FSR2 + +#pragma once + +// Include the interface for the backend of the FSR2 API. +#include + +/// @defgroup FfxSpd FidelityFX SPD +/// FidelityFX Single Pass Downsampler runtime library +/// +/// @ingroup SDKComponents + +/// FidelityFX SPD major version. +/// +/// @ingroup FfxSpd +#define FFX_SPD_VERSION_MAJOR (2) + +/// FidelityFX SPD minor version. +/// +/// @ingroup FfxSpd +#define FFX_SPD_VERSION_MINOR (2) + +/// FidelityFX SPD patch version. +/// +/// @ingroup FfxSpd +#define FFX_SPD_VERSION_PATCH (0) + +/// FidelityFX SPD context count +/// +/// Defines the number of internal effect contexts required by SPD +/// +/// @ingroup FfxSpd +#define FFX_SPD_CONTEXT_COUNT 1 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup FfxSpd +#define FFX_SPD_CONTEXT_SIZE (9300) + +/// If this ever changes, need to also reflect a change in number +/// of resources in ffx_spd_resources.h +/// +/// @ingroup FfxSpd +#define SPD_MAX_MIP_LEVELS 12 + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of the pass which constitutes the SPD algorithm. +/// +/// SPD is implemented as a single pass algorithm. Each call to the +/// FfxSPDScheduleGpuJobFunc callback function will +/// correspond to a single downsample job. For a +/// more comprehensive description of SPD's inner workings, please +/// refer to the SPD reference documentation. +/// +/// @ingroup FfxSpd +typedef enum FfxSpdPass +{ + + FFX_SPD_PASS_DOWNSAMPLE = 0, ///< A pass which which downsamples all mips + + FFX_SPD_PASS_COUNT ///< The number of passes in SPD +} FfxSpdPass; + +typedef enum FfxSpdDownsampleFilter +{ + FFX_SPD_DOWNSAMPLE_FILTER_MEAN = 0, + FFX_SPD_DOWNSAMPLE_FILTER_MIN, + FFX_SPD_DOWNSAMPLE_FILTER_MAX, + FFX_SPD_DOWNSAMPLE_FILTER_COUNT +} FfxSpdDownsampleFilter; + +/// An enumeration of bit flags used when creating a +/// FfxSpdContext. See FfxSpdContextDescription. +/// +/// @ingroup FfxSpd +typedef enum FfxSpdInitializationFlagBits { + + FFX_SPD_SAMPLER_LOAD = (1 << 0), ///< A bit indicating if we should use resource loads (favor loads over sampler) + FFX_SPD_SAMPLER_LINEAR = (1 << 1), ///< A bit indicating if we should use sampler to load resources. + FFX_SPD_WAVE_INTEROP_LDS = (1 << 2), ///< A bit indicating if we should use LDS + FFX_SPD_WAVE_INTEROP_WAVE_OPS = (1 << 3), ///< A bit indicating if we should use WAVE OPS (favor wave ops over LDS) + FFX_SPD_MATH_NONPACKED = (1 << 4), ///< A bit indicating if we should use floating point math + FFX_SPD_MATH_PACKED = (1 << 5) ///< A bit indicating if we should use 16-bit half precision floating point math (favored) + +} FfxSpdInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX +/// Single Pass Downsampler. +/// +/// @ingroup FfxSpd +typedef struct FfxSpdContextDescription { + + uint32_t flags; ///< A collection of FfxSpdInitializationFlagBits + FfxSpdDownsampleFilter downsampleFilter; + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX. + +} FfxSpdContextDescription; + +/// A structure encapsulating the parameters for dispatching +/// of FidelityFX Single Pass Downsampler +/// +/// @ingroup FfxSpd +typedef struct FfxSpdDispatchDescription { + + FfxCommandList commandList; ///< The FfxCommandList to record rendering commands into. + FfxResource resource; ///< The FfxResource to downsample + +} FfxSpdDispatchDescription; + +/// A structure encapsulating the FidelityFX single pass downsampler context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by SPD. +/// +/// The FfxSpdContext object should have a lifetime matching +/// your use of FSR1. Before destroying the SPD context care should be taken +/// to ensure the GPU is not accessing the resources created or used by SPD. +/// It is therefore recommended that the GPU is idle before destroying the +/// SPD context. +/// +/// @ingroup FfxSpd +typedef struct FfxSpdContext { + + uint32_t data[FFX_SPD_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxSpdContext; + +/// Create a FidelityFX Single Pass Downsampler context from the parameters +/// programmed to the FfxSpdContextDescription structure. +/// +/// The context structure is the main object used to interact with the Single +/// Pass Downsampler API, and is responsible for the management of the internal resources +/// used by the SPD algorithm. When this API is called, multiple calls +/// will be made via the pointers contained in the backendInterface +/// structure. This backend will attempt to retrieve the device capabilities, +/// and create the internal resources, and pipelines required by SPD to function. +/// Depending on the precise configuration used when +/// creating the FfxSpdContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The FfxSpdContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or SPD +/// upscaling is disabled by a user. To destroy the SPD context you +/// should call ffxSpdContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxSpdContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxSpdContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxSpdContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxSpd +FFX_API FfxErrorCode ffxSpdContextCreate(FfxSpdContext* pContext, const FfxSpdContextDescription* pContextDescription); + +/// Dispatches work to the FidelityFX SPD context +/// +/// @param [out] pContext A pointer to a FfxSpdContext structure to populate. +/// @param [in] pDispatchDescription A pointer to a FfxSpdDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup FfxSpd +FFX_API FfxErrorCode ffxSpdContextDispatch(FfxSpdContext* pContext, const FfxSpdDispatchDescription* pDispatchDescription); + +/// Destroy the FidelityFX SPD context. +/// +/// @param [out] pContext A pointer to a FfxSpdContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context was NULL. +/// +/// @ingroup FfxSpd +FFX_API FfxErrorCode ffxSpdContextDestroy(FfxSpdContext* pContext); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup FfxSpd +FFX_API FfxVersionNumber ffxSpdGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_sssr.h b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_sssr.h new file mode 100644 index 00000000..0083eb8e --- /dev/null +++ b/Kits/AMDTK/fidelityfx/include/FidelityFX/host/ffx_sssr.h @@ -0,0 +1,260 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +// Include the interface for the backend of the SSSR API. +#include + +/// @defgroup FfxSssr FidelityFX SSSR +/// FidelityFX Stochastic Screen Space Reflections runtime library +/// +/// @ingroup SDKComponents + +/// FidelityFX Stochastic Screen Space Reflections major version. +/// +/// @ingroup FfxSssr +#define FFX_SSSR_VERSION_MAJOR (1) + +/// FidelityFX Stochastic Screen Space Reflections minor version. +/// +/// @ingroup FfxSssr +#define FFX_SSSR_VERSION_MINOR (5) + +/// FidelityFX Stochastic Screen Space Reflections patch version. +/// +/// @ingroup FfxSssr +#define FFX_SSSR_VERSION_PATCH (0) + +/// FidelityFX SSSR context count +/// +/// Defines the number of internal effect contexts required by SSSR +/// We need 2, one for the SSSR context and one for the FidelityFX Denoiser +/// +/// @ingroup FfxSssr +#define FFX_SSSR_CONTEXT_COUNT 2 + +/// The size of the context specified in 32bit values. +/// +/// @ingroup FfxSssr +#define FFX_SSSR_CONTEXT_SIZE (118914) + +#if defined(__cplusplus) +extern "C" { +#endif // #if defined(__cplusplus) + +/// An enumeration of all the passes which constitute the SSSR algorithm. +/// +/// SSSR is implemented as a composite of several compute passes each +/// computing a key part of the final result. Each call to the +/// FfxSssrScheduleGpuJobFunc callback function will +/// correspond to a single pass included in FfxSssrPass. For a +/// more comprehensive description of each pass, please refer to the SSSR +/// reference documentation. +/// +/// @ingroup FfxSssr +typedef enum FfxSssrPass +{ + FFX_SSSR_PASS_DEPTH_DOWNSAMPLE = 0, ///< A pass which performs the hierarchical depth buffer generation + FFX_SSSR_PASS_CLASSIFY_TILES = 1, ///< A pass which classifies which pixels require screen space ray marching + FFX_SSSR_PASS_PREPARE_BLUE_NOISE_TEXTURE = 2, ///< A pass which generates an optimized blue noise texture + FFX_SSSR_PASS_PREPARE_INDIRECT_ARGS = 3, ///< A pass which generates the indirect arguments for the intersection pass. + FFX_SSSR_PASS_INTERSECTION = 4, ///< A pass which performs the actual hierarchical depth ray marching. + FFX_SSSR_PASS_COUNT +} FfxSssrPass; + +/// An enumeration of bit flags used when creating a +/// FfxSssrContext. See FfxSssrContextDescription. +/// +/// @ingroup FfxSssr +typedef enum FfxSssrInitializationFlagBits { + + FFX_SSSR_ENABLE_DEPTH_INVERTED = (1 << 0) ///< A bit indicating that the input depth buffer data provided is inverted [1..0]. +} FfxSssrInitializationFlagBits; + +/// A structure encapsulating the parameters required to initialize FidelityFX +/// Stochastic Screen Space Reflections. +/// +/// @ingroup ffxSssr +typedef struct FfxSssrContextDescription +{ + uint32_t flags; ///< A collection of FfxSssrInitializationFlagBits. + FfxDimensions2D renderSize; ///< The resolution we are currently rendering at + FfxSurfaceFormat normalsHistoryBufferFormat; ///< The format used by the reflections denoiser to store the normals buffer history + FfxInterface backendInterface; ///< A set of pointers to the backend implementation for FidelityFX SDK +} FfxSssrContextDescription; + +/// A structure encapsulating the parameters for dispatching the various passes +/// of FidelityFX Stochastic Screen Space Reflections. +/// +/// @ingroup ffxSssr +typedef struct FfxSssrDispatchDescription { + + FfxCommandList commandList; ///< The FfxCommandList to record SSSR rendering commands into. + FfxResource color; ///< A FfxResource containing the color buffer for the current frame. + FfxResource depth; ///< A FfxResource containing the depth buffer for the current frame. + FfxResource motionVectors; ///< A FfxResource containing the motion vectors buffer for the current frame. + FfxResource normal; ///< A FfxResource containing the normal buffer for the current frame. + FfxResource materialParameters; ///< A FfxResource containing the roughness buffer for the current frame. + FfxResource environmentMap; ///< A FfxResource containing the environment map to fallback to when screenspace data is not sufficient. + FfxResource brdfTexture; ///< A FfxResource containing the precomputed brdf LUT. + FfxResource output; ///< A FfxResource to store the result of the SSSR algorithm into. + float invViewProjection[16]; ///< An array containing the inverse of the view projection matrix in column major layout. + float projection[16]; ///< An array containing the projection matrix in column major layout. + float invProjection[16]; ///< An array containing the inverse of the projection matrix in column major layout. + float view[16]; ///< An array containing the view matrix in column major layout. + float invView[16]; ///< An array containing the inverse of the view matrix in column major layout. + float prevViewProjection[16]; ///< An array containing the previous frame's view projection matrix in column major layout. + FfxDimensions2D renderSize; ///< The resolution that was used for rendering the input resources. + FfxFloatCoords2D motionVectorScale; ///< The scale factor to apply to motion vectors. + float iblFactor; ///< A factor to control the intensity of the image based lighting. Set to 1 for an HDR probe. + float normalUnPackMul; ///< A multiply factor to transform the normal to the space expected by SSSR. + float normalUnPackAdd; ///< An offset to transform the normal to the space expected by SSSR. + uint32_t roughnessChannel; ///< The channel to read the roughness from the materialParameters texture + bool isRoughnessPerceptual; ///< A boolean to describe the space used to store roughness in the materialParameters texture. If false, we assume roughness squared was stored in the Gbuffer. + float temporalStabilityFactor; ///< A factor to control the accmulation of history values. Higher values reduce noise, but are more likely to exhibit ghosting artefacts. + float depthBufferThickness; ///< A bias for accepting hits. Larger values can cause streaks, lower values can cause holes. + float roughnessThreshold; ///< Regions with a roughness value greater than this threshold won't spawn rays. + float varianceThreshold; ///< Luminance differences between history results will trigger an additional ray if they are greater than this threshold value. + uint32_t maxTraversalIntersections; ///< Caps the maximum number of lookups that are performed from the depth buffer hierarchy. Most rays should terminate after approximately 20 lookups. + uint32_t minTraversalOccupancy; ///< Exit the core loop early if less than this number of threads are running. + uint32_t mostDetailedMip; ///< The most detailed MIP map level in the depth hierarchy. Perfect mirrors always use 0 as the most detailed level. + uint32_t samplesPerQuad; ///< The minimum number of rays per quad. Variance guided tracing can increase this up to a maximum of 4. + uint32_t temporalVarianceGuidedTracingEnabled; ///< A boolean controlling whether a ray should be spawned on pixels where a temporal variance is detected or not. +} FfxSssrDispatchDescription; + +/// A structure encapsulating the FidelityFX Stochastic Screen Space Reflections context. +/// +/// This sets up an object which contains all persistent internal data and +/// resources that are required by SSSR. +/// +/// The FfxSssrContext object should have a lifetime matching +/// your use of SSSR. Before destroying the SSSR context care should be taken +/// to ensure the GPU is not accessing the resources created or used by SSSR. +/// It is therefore recommended that the GPU is idle before destroying the +/// SSSR context. +/// +/// @ingroup ffxSssr +typedef struct FfxSssrContext +{ + uint32_t data[FFX_SSSR_CONTEXT_SIZE]; ///< An opaque set of uint32_t which contain the data for the context. +} FfxSssrContext; + +/// Create a FidelityFX Stochastic Screen Space Reflections context from the parameters +/// programmed to the FfxSssrCreateParams structure. +/// +/// The context structure is the main object used to interact with the SSSR +/// API, and is responsible for the management of the internal resources used +/// by the SSSR algorithm. When this API is called, multiple calls will be +/// made via the pointers contained in the callbacks structure. +/// These callbacks will attempt to retreive the device capabilities, and +/// create the internal resources, and pipelines required by SSSR's +/// frame-to-frame function. Depending on the precise configuration used when +/// creating the FfxSssrContext a different set of resources and +/// pipelines might be requested via the callback functions. +/// +/// The flags included in the flags field of +/// FfxSssrContext how match the configuration of your +/// application as well as the intended use of SSSR. It is important that these +/// flags are set correctly (as well as a correct programmed +/// FfxSssrDispatchDescription) to ensure correct operation. It is +/// recommended to consult the overview documentation for further details on +/// how SSSR should be integerated into an application. +/// +/// When the FfxSssrContext is created, you should use the +/// ffxSssrContextDispatch function each frame where SSSR +/// algorithm should be applied. See the documentation of +/// ffxSssrContextDispatch for more details. +/// +/// The FfxSssrContext should be destroyed when use of it is +/// completed, typically when an application is unloaded or SSSR upscaling is +/// disabled by a user. To destroy the SSSR context you should call +/// ffxSssrContextDestroy. +/// +/// @param [out] pContext A pointer to a FfxSssrContext structure to populate. +/// @param [in] pContextDescription A pointer to a FfxSssrContextDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or contextDescription was NULL. +/// @retval +/// FFX_ERROR_INCOMPLETE_INTERFACE The operation failed because the FfxSssrContextDescription.callbacks was not fully specified. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxSssr +FFX_API FfxErrorCode ffxSssrContextCreate(FfxSssrContext* context, const FfxSssrContextDescription* contextDescription); + +/// Dispatch the various passes that constitute the FidelityFX Stochastic Screen Space Reflections. +/// +/// SSSR is a composite effect, meaning that it is compromised of multiple +/// constituent passes (implemented as one or more clears, copies and compute +/// dispatches). The ffxSssrContextDispatch function is the +/// function which (via the use of the functions contained in the +/// callbacks field of the FfxSssrContext +/// structure) utlimately generates the sequence of graphics API calls required +/// each frame. +/// +/// As with the creation of the FfxSssrContext correctly +/// programming the FfxSssrDispatchDescription is key to ensuring +/// the correct operation of SSSR. +/// +/// @param [in] pContext A pointer to a FfxSssrContext structure. +/// @param [in] pDispatchDescription A pointer to a FfxSssrDispatchDescription structure. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context or dispatchDescription was NULL. +/// @retval +/// FFX_ERROR_NULL_DEVICE The operation failed because the device inside the context was NULL. +/// @retval +/// FFX_ERROR_BACKEND_API_ERROR The operation failed because of an error returned from the backend. +/// +/// @ingroup ffxSssr +FFX_API FfxErrorCode ffxSssrContextDispatch(FfxSssrContext* context, const FfxSssrDispatchDescription* dispatchDescription); + + +/// Destroy the FidelityFX Stochastic Screen Space Reflections context. +/// +/// @param [out] pContext A pointer to a FfxSssrContext structure to destroy. +/// +/// @retval +/// FFX_OK The operation completed successfully. +/// @retval +/// FFX_ERROR_CODE_NULL_POINTER The operation failed because either context was NULL. +/// +/// @ingroup ffxSssr +FFX_API FfxErrorCode ffxSssrContextDestroy(FfxSssrContext* context); + +/// Queries the effect version number. +/// +/// @returns +/// The SDK version the effect was built with. +/// +/// @ingroup ffxSssr +FFX_API FfxVersionNumber ffxSssrGetEffectVersion(); + +#if defined(__cplusplus) +} +#endif // #if defined(__cplusplus) diff --git a/Kits/AMDTK/fidelityfx/libs/antilag2/ffx_antilag2_dx12.h b/Kits/AMDTK/fidelityfx/libs/antilag2/ffx_antilag2_dx12.h new file mode 100644 index 00000000..446b5fcb --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/antilag2/ffx_antilag2_dx12.h @@ -0,0 +1,249 @@ +// This file is part of the Anti-Lag 2.0 SDK. +// +// Copyright (c) 2024 Advanced Micro Devices, Inc. All rights reserved. +// +// 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. + +#pragma once + +namespace AMD { +namespace AntiLag2DX12 { + + struct Context; + + // Initialize function - call this once before the Update function. + // context - Declare a persistent Context variable in your game code. Ensure the contents are zero'ed, and pass the address in to initialize it. + // Be sure to use the *same* context object everywhere when calling the Anti-Lag 2.0 SDK functions. + // device - The game's D3D12 device. + // A return value of S_OK indicates that Anti-Lag 2.0 is available on the system. + HRESULT Initialize( Context* context, ID3D12Device* device ); + + // DeInitialize function - call this before destroying the device. + // context - address of the game's context object. + // The return value is the reference count of the internal API. It should be 0. + ULONG DeInitialize( Context* context ); + + // Update function - call this just before the input to the game is polled. + // context - address of the game's context object. + // enable - enables or disables Anti-Lag 2.0. + // maxFPS - sets a framerate limit. Zero will disable the limiter. + HRESULT Update( Context* context, bool enable, unsigned int maxFPS ); + + // Call this on the game render thread once the game's main rendering workload has been submitted in an ExecuteCommandLists call. + // Call before the FSR 3 Present call is made. + // This is only required if frame generation is enabled, but calling it anyway is harmless. + // context - address of the game's context object. + HRESULT MarkEndOfFrameRendering( Context* context ); + + // Call this on the presentation thread just before the Present call. + // This is only required if frame generation is enabled, but calling it anyway is harmless. + // context - address of the game's context object. + // bInterpolatedFrame - whether the frame about to be presented is interpolated. + HRESULT SetFrameGenFrameType( Context* context, bool bInterpolatedFrame ); + + // + // End of public API section. + // Private implementation details below. + // + + // Forward declaration of the Anti-Lag interface into the DX12 driver + MIDL_INTERFACE("44085fbe-e839-40c5-bf38-0ebc5ab4d0a6") + IAmdExtAntiLagApi: public IUnknown + { + public: + virtual HRESULT UpdateAntiLagState(VOID* pData) = 0; + }; + + // Context structure for the SDK. Declare a persistent object of this type *once* in your game code. + // Ensure the contents are initialized to zero before calling Initialize() but do not modify these members directly after that. + struct Context + { + IAmdExtAntiLagApi* m_pAntiLagAPI = nullptr; + bool m_enabled = false; + unsigned int m_maxFPS = 0; + }; + + // Structure version 1 for Anti-Lag 2.0: + struct APIData_v1 + { + unsigned int uiSize; + unsigned int uiVersion; + unsigned int eMode; + const char* sControlStr; + unsigned int uiControlStrLength; + unsigned int maxFPS; + }; + static_assert(sizeof(APIData_v1) == 32, "Check structure packing compiler settings."); + + // Structure version 2 for Anti-Lag 2.0: + struct APIData_v2 + { + unsigned int uiSize; + unsigned int uiVersion; + struct Flags + { + unsigned int unused0 : 1; + unsigned int unused1 : 1; + + unsigned int signalFgFrameType : 1; + unsigned int isInterpolatedFrame : 1; + + unsigned int signalGetUserInputIdx : 1; + unsigned int signalEndOfFrameIdx : 1; + + unsigned int reserved :26; + } flags; + unsigned __int64 iiFrameIdx; + unsigned __int64 uiiReserved[19]; + }; + static_assert(sizeof(APIData_v2) == 176, "Check structure packing compiler settings."); + + inline HRESULT Initialize( Context* context, ID3D12Device* device ) + { + HRESULT hr = E_INVALIDARG; + if ( context && device && context->m_pAntiLagAPI == nullptr ) + { + HMODULE hModule = GetModuleHandleA("amdxc64.dll"); + if ( hModule ) + { + typedef HRESULT(__cdecl* PFNAmdExtD3DCreateInterface)( IUnknown* pOuter, REFIID riid, void** ppvObject ); + PFNAmdExtD3DCreateInterface AmdExtD3DCreateInterface = static_cast( (VOID*)GetProcAddress(hModule, "AmdExtD3DCreateInterface") ); + if ( AmdExtD3DCreateInterface ) + { + hr = AmdExtD3DCreateInterface( device, __uuidof(IAmdExtAntiLagApi), (void**)&context->m_pAntiLagAPI ); + if ( hr == S_OK && context->m_pAntiLagAPI ) + { + APIData_v1 data = {}; + data.uiSize = sizeof(data); + data.uiVersion = 1; + data.eMode = 2; // Anti-Lag 2.0 is disabled during initialization + data.sControlStr = nullptr; + data.uiControlStrLength = 0; + data.maxFPS = 0; + + hr = context->m_pAntiLagAPI->UpdateAntiLagState( &data ); + } + + if ( hr != S_OK ) + { + DeInitialize( context ); + } + } + } + else + { + hr = E_HANDLE; + } + } + return hr; + } + + inline ULONG DeInitialize( Context* context ) + { + ULONG refCount = 0; + if ( context ) + { + if ( context->m_pAntiLagAPI ) + { + refCount = context->m_pAntiLagAPI->Release(); + context->m_pAntiLagAPI = nullptr; + } + context->m_enabled = false; + } + + return refCount; + } + + inline HRESULT Update( Context* context, bool enabled, unsigned int maxFPS ) + { + // This function needs to be called once per frame, before the user input + // is sampled - or optionally also when the UI settings are modified. + if ( context && context->m_pAntiLagAPI ) + { + // Update the Anti-Lag 2.0 internal state only when necessary: + if ( context->m_enabled != enabled || context->m_maxFPS != maxFPS ) + { + context->m_enabled = enabled; + context->m_maxFPS = maxFPS; + + APIData_v1 data = {}; + data.uiSize = sizeof(data); + data.uiVersion = 1; + data.eMode = enabled ? 1 : 2; + data.sControlStr = nullptr; + data.uiControlStrLength = 0; + data.maxFPS = maxFPS; + + // Only call the function with non-null arguments when setting state. + // Make sure not to set the state every frame. + context->m_pAntiLagAPI->UpdateAntiLagState( &data ); + } + + // Call the function with a nullptr to insert the latency-reducing delay. + // (if the state has not been set to 'enabled' this call will have no effect) + HRESULT hr = context->m_pAntiLagAPI->UpdateAntiLagState( nullptr ); + if ( hr == S_OK || hr == S_FALSE ) + { + return S_OK; + } + else + { + return hr; + } + } + else + { + return E_NOINTERFACE; + } + } + + // Internal helper function + inline HRESULT SetFrameGenParamsInternal( Context* context, APIData_v2::Flags flags ) + { + if ( context && context->m_pAntiLagAPI ) + { + APIData_v2 data = {}; + data.uiSize = sizeof(data); + data.uiVersion = 2; + data.flags = flags; + data.iiFrameIdx = 0; + + return context->m_pAntiLagAPI->UpdateAntiLagState( &data ); + } + else + { + return E_NOINTERFACE; + } + } + + inline HRESULT MarkEndOfFrameRendering( Context* context ) + { + APIData_v2::Flags flags = {}; + flags.signalEndOfFrameIdx = 1; + return SetFrameGenParamsInternal( context, flags ); + } + + inline HRESULT SetFrameGenFrameType( Context* context, bool bInterpolatedFrame ) + { + APIData_v2::Flags flags = {}; + flags.signalFgFrameType = 1; + flags.isInterpolatedFrame = bInterpolatedFrame ? 1 : 0; + return SetFrameGenParamsInternal( context, flags ); + } +} // namespace AntiLag2DX12 +} // namespace AMD \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/libs/pix/CMakeLists.txt b/Kits/AMDTK/fidelityfx/libs/pix/CMakeLists.txt new file mode 100644 index 00000000..3b491a26 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/pix/CMakeLists.txt @@ -0,0 +1,63 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +add_library(pixlib SHARED IMPORTED GLOBAL) +set_property(TARGET pixlib PROPERTY IMPORTED_IMPLIB ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_GENERATOR_PLATFORM}/WinPixEventRuntime.lib) + +set(winpixevent_binary + ${CMAKE_CURRENT_SOURCE_DIR}/bin/${CMAKE_GENERATOR_PLATFORM}/WinPixEventRuntime.dll) + +set(winpixgpucapturer_binary + ${CMAKE_CURRENT_SOURCE_DIR}/bin/WinPixGpuCapturer.dll) + +# Copies a set of files to a directory (only if they already don't exist or are different) +# +# Usage example: +# add_library(my_lib ...) +# set(media_src ${CMAKE_CURRENT_SOURCE_DIR}/../../media/brdfLut.dds ) +# copyTargetCommand("${media_src}" ${CMAKE_HOME_DIRECTORY}/bin copied_media_src) +# add_dependencies(my_lib copied_media_src) +# +function(copyTargetCommand list dest returned_target_name) + set_property(GLOBAL PROPERTY USE_FOLDERS ON) + + foreach(fullFileName ${list}) + get_filename_component(file ${fullFileName} NAME) + message("Generating custom command for ${fullFileName}") + add_custom_command( + OUTPUT ${dest}/${file} + PRE_BUILD + COMMAND ${CMAKE_COMMAND} -E make_directory ${dest} + COMMAND ${CMAKE_COMMAND} -E copy_if_different ${fullFileName} ${dest} + MAIN_DEPENDENCY ${fullFileName} + COMMENT "Updating ${file} into ${dest}" + ) + list(APPEND dest_list ${dest}/${file}) + endforeach() + + add_custom_target(${returned_target_name} DEPENDS "${dest_list}") + set_target_properties(${returned_target_name} PROPERTIES FOLDER CopyTargets) +endfunction() + +copyTargetCommand("${winpixevent_binary}" ${FFX_BIN_PATH} copied_winpixevent_bin) + +add_dependencies(pixlib copied_winpixevent_bin) diff --git a/Kits/AMDTK/fidelityfx/libs/pix/FFX_SDK_README.md b/Kits/AMDTK/fidelityfx/libs/pix/FFX_SDK_README.md new file mode 100644 index 00000000..109efc29 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/pix/FFX_SDK_README.md @@ -0,0 +1,12 @@ +# WinPixEventRuntime + +## Current Version +1.0.240308001 + +## How to update +1. Download the nuget package from the webpage https://www.nuget.org/packages/WinPixEventRuntime +2. Rename its `.nupkg` extension into `.zip` +3. Unzip it +4. Replace the current header files by the ones in `Include/WinPixEventRuntime/` +5. Replace the current `WinPixEventRuntime.lib` and `WinPixEventRuntime.dll` files by the ones in `bin/x64/` +6. Update this `FFX_SDK_README.md` with the new version number! \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/libs/pix/PIXEvents.h b/Kits/AMDTK/fidelityfx/libs/pix/PIXEvents.h new file mode 100644 index 00000000..1a9fdf0d --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/pix/PIXEvents.h @@ -0,0 +1,1578 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// Don't include this file directly - use pix3.h + +#pragma once + +#ifndef _PixEvents_H_ +#define _PixEvents_H_ + +#ifndef _PIX3_H_ +# error Do not include this file directly - use pix3.h +#endif + +#include "PIXEventsCommon.h" + +#if _MSC_VER < 1800 +# error This version of pix3.h is only supported on Visual Studio 2013 or higher +#elif _MSC_VER < 1900 +# ifndef constexpr // Visual Studio 2013 doesn't support constexpr +# define constexpr +# define PIX3__DEFINED_CONSTEXPR +# endif +#endif + + // Xbox does not support CPU events for retail scenarios +#if defined(USE_PIX) || !defined(PIX_XBOX) +#define PIX_CONTEXT_EMIT_CPU_EVENTS +#endif + +namespace PIXEventsDetail +{ + inline void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit) + { + // nothing + UNREFERENCED_PARAMETER(destination); + UNREFERENCED_PARAMETER(limit); + } + + template + void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, ARG const& arg, ARGS const&... args) + { + PIXCopyEventArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); + } + + template + void PIXCopyStringArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, ARG const& arg, ARGS const&... args) + { + PIXCopyStringArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); + } + + template + void PIXCopyStringArgumentsWithContext(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, void* context, ARG const& arg, ARGS const&... args) + { +#ifdef PIX_XBOX + UNREFERENCED_PARAMETER(context); + PIXCopyStringArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); +#else + PIXCopyEventArgument(destination, limit, context); + PIXCopyStringArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); +#endif + } + + inline UINT8 PIXGetEventSize(const UINT64* end, const UINT64* start) + { + const UINT64 actualEventSize = end - start; + + return static_cast(actualEventSize > PIXEventsSizeMax ? PIXEventsSizeMax : actualEventSize); + } + + template + inline UINT8 PIXEncodeStringIsAnsi() + { + return PIX_EVENT_METADATA_NONE; + } + + template<> + inline UINT8 PIXEncodeStringIsAnsi() + { + return PIX_EVENT_METADATA_STRING_IS_ANSI; + } + + template<> + inline UINT8 PIXEncodeStringIsAnsi() + { + return PIX_EVENT_METADATA_STRING_IS_ANSI; + } + + template + __declspec(noinline) void PIXBeginEventAllocate(PIXEventsThreadInfo* threadInfo, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_HAS_COLOR | + PIXEncodeStringIsAnsi(); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXBeginEvent(UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_HAS_COLOR | + PIXEncodeStringIsAnsi(); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXBeginEventAllocate(PIXEventsThreadInfo* threadInfo, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXBeginEvent(UINT8 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXSetMarkerAllocate(PIXEventsThreadInfo* threadInfo, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXSetMarker(UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXSetMarkerAllocate(PIXEventsThreadInfo* threadInfo, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXSetMarker(UINT8 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + UINT64* eventDestination = destination++; + + PIXCopyStringArguments(destination, limit, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerAllocate(threadInfo, color, formatString, args...); + } + } + } + + template + __declspec(noinline) void PIXBeginEventOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXBeginEventOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXBeginEvent(CONTEXT* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXBeginEventOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_BeginEvent, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeBeginEventForContext(buffer, color, formatString, args...); + PIXBeginGPUEventOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + template + __declspec(noinline) void PIXBeginEventOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXBeginEventOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT8 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_BeginEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXBeginEventOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXBeginEvent(CONTEXT* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXBeginEventOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_BeginEvent, eventSize, eventMetadata); + + PIXInsertGPUMarkerOnContextForBeginEvent(context, PIXEvent_BeginEvent, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeBeginEventForContext(buffer, color, formatString, args...); + PIXBeginGPUEventOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + template + __declspec(noinline) void PIXSetMarkerOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXSetMarkerOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT64 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXSetMarker(CONTEXT* context, UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXSetMarkerOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + *destination++ = color; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIX_EVENT_METADATA_HAS_COLOR; + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_SetMarker, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeSetMarkerForContext(buffer, color, formatString, args...); + PIXSetGPUMarkerOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + template + __declspec(noinline) void PIXSetMarkerOnContextCpuAllocate(UINT64*& eventDestination, UINT8& eventSize, PIXEventsThreadInfo* threadInfo, void* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, false); + if (!time) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + { + eventDestination = nullptr; + return; + } + + limit += PIXEventsSafeFastCopySpaceQwords; + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + + template + void PIXSetMarkerOnContextCpu(UINT64*& eventDestination, UINT8& eventSize, void* context, UINT8 color, STR formatString, ARGS... args) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit == nullptr) + { + eventDestination = nullptr; + return; + } + + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = PIXEventsBlockEndMarker; + + eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_SetMarker, eventSize, eventMetadata); + + threadInfo->destination = destination; + } + else + { + PIXSetMarkerOnContextCpuAllocate(eventDestination, eventSize, threadInfo, context, color, formatString, args...); + } + } + + template + void PIXSetMarker(CONTEXT* context, UINT8 color, STR formatString, ARGS... args) + { + UINT64* destination = nullptr; + UINT8 eventSize = 0u; + +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + PIXSetMarkerOnContextCpu(destination, eventSize, context, color, formatString, args...); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(destination), eventSize * sizeof(UINT64)); + } + else +#endif + { + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + +#ifdef PIX_USE_GPU_MARKERS_V2 + destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + UINT64* eventDestination = destination++; + + PIXCopyStringArgumentsWithContext(destination, limit, context, formatString, args...); + *destination = 0ull; + + eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = + PIX_EVENT_METADATA_ON_CONTEXT | + PIXEncodeStringIsAnsi() | + PIXEncodeIndexColor(color); + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_SetMarker, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForSetMarker(context, PIXEvent_SetMarker, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + destination = PixEventsLegacy::EncodeSetMarkerForContext(buffer, color, formatString, args...); + PIXSetGPUMarkerOnContext(context, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#endif + } + } + + __declspec(noinline) inline void PIXEndEventAllocate(PIXEventsThreadInfo* threadInfo) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, true); + if (!time) + return; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return; + + limit += PIXEventsSafeFastCopySpaceQwords; + const UINT8 eventSize = 1; + const UINT8 eventMetadata = PIX_EVENT_METADATA_NONE; + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + *destination = PIXEventsBlockEndMarker; + + threadInfo->destination = destination; + } + + inline void PIXEndEvent() + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + const UINT8 eventSize = 1; + const UINT8 eventMetadata = PIX_EVENT_METADATA_NONE; + *destination++ = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + *destination = PIXEventsBlockEndMarker; + + threadInfo->destination = destination; + } + else + { + PIXEndEventAllocate(threadInfo); + } + } + } + + __declspec(noinline) inline UINT64* PIXEndEventOnContextCpuAllocate(PIXEventsThreadInfo* threadInfo, void* context) + { + UINT64 time = PIXEventsReplaceBlock(threadInfo, true); + if (!time) + return nullptr; + + UINT64* destination = threadInfo->destination; + UINT64* limit = threadInfo->biasedLimit; + + if (destination >= limit) + return nullptr; + + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64* eventDestination = destination++; +#ifdef PIX_XBOX + UNREFERENCED_PARAMETER(context); +#else + PIXCopyEventArgument(destination, limit, context); +#endif + * destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = PIX_EVENT_METADATA_ON_CONTEXT; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + + return eventDestination; + } + + inline UINT64* PIXEndEventOnContextCpu(void* context) + { + PIXEventsThreadInfo* threadInfo = PIXGetThreadInfo(); + UINT64* limit = threadInfo->biasedLimit; + if (limit != nullptr) + { + UINT64* destination = threadInfo->destination; + if (destination < limit) + { + limit += PIXEventsSafeFastCopySpaceQwords; + UINT64 time = PIXGetTimestampCounter(); + UINT64* eventDestination = destination++; +#ifndef PIX_XBOX + PIXCopyEventArgument(destination, limit, context); +#endif + * destination = PIXEventsBlockEndMarker; + + const UINT8 eventSize = PIXGetEventSize(destination, threadInfo->destination); + const UINT8 eventMetadata = PIX_EVENT_METADATA_ON_CONTEXT; + *eventDestination = PIXEncodeEventInfo(time, PIXEvent_EndEvent, eventSize, eventMetadata); + + threadInfo->destination = destination; + + return eventDestination; + } + else + { + return PIXEndEventOnContextCpuAllocate(threadInfo, context); + } + } + + return nullptr; + } + + template + void PIXEndEvent(CONTEXT* context) + { + UINT64* destination = nullptr; +#ifdef PIX_CONTEXT_EMIT_CPU_EVENTS + destination = PIXEndEventOnContextCpu(context); +#endif + +#ifdef PIX_USE_GPU_MARKERS_V2 + if (destination != nullptr) + { + PIXInsertTimingMarkerOnContextForEndEvent(context, PIXEvent_EndEvent); + } + else +#endif + { +#ifdef PIX_USE_GPU_MARKERS_V2 + UINT64 buffer[PIXEventsGraphicsRecordSpaceQwords]; + destination = buffer; + + UINT64* eventDestination = destination++; + + const UINT8 eventSize = static_cast(destination - buffer); + const UINT8 eventMetadata = PIX_EVENT_METADATA_NONE; + *eventDestination = PIXEncodeEventInfo(0, PIXEvent_EndEvent, eventSize, eventMetadata); + PIXInsertGPUMarkerOnContextForEndEvent(context, PIXEvent_EndEvent, static_cast(buffer), static_cast(reinterpret_cast(destination) - reinterpret_cast(buffer))); +#else + PIXEndGPUEventOnContext(context); +#endif + } + } +} + +#if defined(USE_PIX) + +template +void PIXBeginEvent(UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(color, formatString, args...); +} + +template +void PIXBeginEvent(UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(color, formatString, args...); +} + +template +void PIXBeginEvent(UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(color, formatString, args...); +} + +template +void PIXBeginEvent(UINT8 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(color, formatString, args...); +} + +template +void PIXSetMarker(UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(color, formatString, args...); +} + +template +void PIXSetMarker(UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(color, formatString, args...); +} + +template +void PIXSetMarker(UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(color, formatString, args...); +} + +template +void PIXSetMarker(UINT8 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(color, formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT8 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginEvent(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetMarker(CONTEXT* context, UINT8 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +inline void PIXEndEvent() +{ + PIXEventsDetail::PIXEndEvent(); +} + +template +void PIXEndEvent(CONTEXT* context) +{ + PIXEventsDetail::PIXEndEvent(context); +} + +#else // USE_PIX_RETAIL + +inline void PIXBeginEvent(UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(UINT64, _In_ PCWSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXEndEvent() {} +inline void PIXEndEvent(void*) {} +inline void PIXSetMarker(UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(UINT64, _In_ PCWSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCWSTR, ...) {} + +#endif // USE_PIX + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, static_cast(color), formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXBeginRetailEvent(CONTEXT* context, UINT8 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXBeginEvent(context, color, formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, static_cast(color), formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXSetRetailMarker(CONTEXT* context, UINT8 color, PCSTR formatString, ARGS... args) +{ + PIXEventsDetail::PIXSetMarker(context, color, formatString, args...); +} + +template +void PIXEndRetailEvent(CONTEXT* context) +{ + PIXEventsDetail::PIXEndEvent(context); +} + +template +class PIXScopedEventObject +{ + CONTEXT* m_context; + +public: + template + PIXScopedEventObject(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + template + PIXScopedEventObject(CONTEXT* context, UINT8 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginEvent(m_context, color, formatString, args...); + } + + ~PIXScopedEventObject() + { + PIXEndEvent(m_context); + } +}; + +template +class PIXScopedRetailEventObject +{ + CONTEXT* m_context; + +public: + template + PIXScopedRetailEventObject(CONTEXT* context, UINT64 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT64 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, INT32 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, INT32 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, DWORD color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, DWORD color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT8 color, PCWSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + template + PIXScopedRetailEventObject(CONTEXT* context, UINT8 color, PCSTR formatString, ARGS... args) + : m_context(context) + { + PIXBeginRetailEvent(m_context, color, formatString, args...); + } + + ~PIXScopedRetailEventObject() + { + PIXEndRetailEvent(m_context); + } +}; + +template<> +class PIXScopedEventObject +{ +public: + template + PIXScopedEventObject(UINT64 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT64 color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT32 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT32 color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(INT32 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(INT32 color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(DWORD color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(DWORD color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT8 color, PCWSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + template + PIXScopedEventObject(UINT8 color, PCSTR formatString, ARGS... args) + { + PIXBeginEvent(color, formatString, args...); + } + + ~PIXScopedEventObject() + { + PIXEndEvent(); + } +}; + +#define PIXConcatenate(a, b) a ## b +#define PIXGetScopedEventVariableName(a, b) PIXConcatenate(a, b) +#define PIXScopedEvent(context, ...) PIXScopedEventObject::Type> PIXGetScopedEventVariableName(pixEvent, __LINE__)(context, __VA_ARGS__) + +#ifdef PIX3__DEFINED_CONSTEXPR +#undef constexpr +#undef PIX3__DEFINED_CONSTEXPR +#endif + +#endif // _PIXEvents_H__ + diff --git a/Kits/AMDTK/fidelityfx/libs/pix/PIXEventsCommon.h b/Kits/AMDTK/fidelityfx/libs/pix/PIXEventsCommon.h new file mode 100644 index 00000000..ff26230c --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/pix/PIXEventsCommon.h @@ -0,0 +1,610 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// Don't include this file directly - use pix3.h + +#pragma once + +#ifndef _PIXEventsCommon_H_ +#define _PIXEventsCommon_H_ + +// +// The PIXBeginEvent and PIXSetMarker functions have an optimized path for +// copying strings that work by copying 128-bit or 64-bits at a time. In some +// circumstances this may result in PIX logging the remaining memory after the +// null terminator. +// +// By default this optimization is enabled unless Address Sanitizer is enabled, +// since this optimization can trigger a global-buffer-overflow when copying +// string literals. +// +// The PIX_ENABLE_BLOCK_ARGUMENT_COPY controls whether or not this optimization +// is enabled. Applications may also explicitly set this macro to 0 to disable +// the optimization if necessary. +// + +// Check for Address Sanitizer on either Clang or MSVC + +#if defined(__has_feature) +#if __has_feature(address_sanitizer) +#define PIX_ASAN_ENABLED +#endif +#elif defined(__SANITIZE_ADDRESS__) +#define PIX_ASAN_ENABLED +#endif + +#if defined(PIX_ENABLE_BLOCK_ARGUMENT_COPY) +// Previously set values override everything +# define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 0 +#elif defined(PIX_ASAN_ENABLED) +// Disable block argument copy when address sanitizer is enabled +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY 0 +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 1 +#endif + +#if !defined(PIX_ENABLE_BLOCK_ARGUMENT_COPY) +// Default to enabled. +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY 1 +#define PIX_ENABLE_BLOCK_ARGUMENT_COPY_SET 1 +#endif + +struct PIXEventsBlockInfo; + +struct PIXEventsThreadInfo +{ + PIXEventsBlockInfo* block; + UINT64* biasedLimit; + UINT64* destination; +}; + +extern "C" UINT64 WINAPI PIXEventsReplaceBlock(PIXEventsThreadInfo * threadInfo, bool getEarliestTime) noexcept; + +#define PIX_EVENT_METADATA_NONE 0x0 +#define PIX_EVENT_METADATA_ON_CONTEXT 0x1 +#define PIX_EVENT_METADATA_STRING_IS_ANSI 0x2 +#define PIX_EVENT_METADATA_HAS_COLOR 0xF0 + +#ifndef PIX_GAMING_XBOX +#include "PIXEventsLegacy.h" +#endif + +enum PIXEventType : UINT8 +{ + PIXEvent_EndEvent = 0x00, + PIXEvent_BeginEvent = 0x01, + PIXEvent_SetMarker = 0x02, +}; + +static const UINT64 PIXEventsReservedRecordSpaceQwords = 64; +//this is used to make sure SSE string copy always will end 16-byte write in the current block +//this way only a check if destination < limit can be performed, instead of destination < limit - 1 +//since both these are UINT64* and SSE writes in 16 byte chunks, 8 bytes are kept in reserve +//so even if SSE overwrites 8-15 extra bytes, those will still belong to the correct block +//on next iteration check destination will be greater than limit +//this is used as well for fixed size UMD events and PIXEndEvent since these require less space +//than other variable length user events and do not need big reserved space +static const UINT64 PIXEventsReservedTailSpaceQwords = 2; +static const UINT64 PIXEventsSafeFastCopySpaceQwords = PIXEventsReservedRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; +static const UINT64 PIXEventsGraphicsRecordSpaceQwords = 64; + +//Bits 7-19 (13 bits) +static const UINT64 PIXEventsBlockEndMarker = 0x00000000000FFF80; + + +// V2 events + +// Bits 00..06 (7 bits) - Size in QWORDS +static const UINT64 PIXEventsSizeWriteMask = 0x000000000000007F; +static const UINT64 PIXEventsSizeBitShift = 0; +static const UINT64 PIXEventsSizeReadMask = PIXEventsSizeWriteMask << PIXEventsSizeBitShift; +static const UINT64 PIXEventsSizeMax = (1ull << 7) - 1ull; + +// Bits 07..11 (5 bits) - Event Type +static const UINT64 PIXEventsTypeWriteMask = 0x000000000000001F; +static const UINT64 PIXEventsTypeBitShift = 7; +static const UINT64 PIXEventsTypeReadMask = PIXEventsTypeWriteMask << PIXEventsTypeBitShift; + +// Bits 12..19 (8 bits) - Event Specific Metadata +static const UINT64 PIXEventsMetadataWriteMask = 0x00000000000000FF; +static const UINT64 PIXEventsMetadataBitShift = 12; +static const UINT64 PIXEventsMetadataReadMask = PIXEventsMetadataWriteMask << PIXEventsMetadataBitShift; + +// Buts 20..63 (44 bits) - Timestamp +static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF; +static const UINT64 PIXEventsTimestampBitShift = 20; +static const UINT64 PIXEventsTimestampReadMask = PIXEventsTimestampWriteMask << PIXEventsTimestampBitShift; + +inline UINT64 PIXEncodeEventInfo(UINT64 timestamp, PIXEventType eventType, UINT8 eventSize, UINT8 eventMetadata) +{ + return + ((timestamp & PIXEventsTimestampWriteMask) << PIXEventsTimestampBitShift) | + (((UINT64)eventType & PIXEventsTypeWriteMask) << PIXEventsTypeBitShift) | + (((UINT64)eventMetadata & PIXEventsMetadataWriteMask) << PIXEventsMetadataBitShift) | + (((UINT64)eventSize & PIXEventsSizeWriteMask) << PIXEventsSizeBitShift); +} + +inline UINT8 PIXEncodeIndexColor(UINT8 color) +{ + // There are 8 index colors, indexed 0 (default) to 7 + return (color & 0x7) << 4; +} + +//Bits 60-63 (4) +static const UINT64 PIXEventsStringAlignmentWriteMask = 0x000000000000000F; +static const UINT64 PIXEventsStringAlignmentReadMask = 0xF000000000000000; +static const UINT64 PIXEventsStringAlignmentBitShift = 60; + +//Bits 55-59 (5) +static const UINT64 PIXEventsStringCopyChunkSizeWriteMask = 0x000000000000001F; +static const UINT64 PIXEventsStringCopyChunkSizeReadMask = 0x0F80000000000000; +static const UINT64 PIXEventsStringCopyChunkSizeBitShift = 55; + +//Bit 54 +static const UINT64 PIXEventsStringIsANSIWriteMask = 0x0000000000000001; +static const UINT64 PIXEventsStringIsANSIReadMask = 0x0040000000000000; +static const UINT64 PIXEventsStringIsANSIBitShift = 54; + +//Bit 53 +static const UINT64 PIXEventsStringIsShortcutWriteMask = 0x0000000000000001; +static const UINT64 PIXEventsStringIsShortcutReadMask = 0x0020000000000000; +static const UINT64 PIXEventsStringIsShortcutBitShift = 53; + +inline void PIXEncodeStringInfo(UINT64*& destination, BOOL isANSI) +{ + const UINT64 encodedStringInfo = + ((sizeof(UINT64) & PIXEventsStringCopyChunkSizeWriteMask) << PIXEventsStringCopyChunkSizeBitShift) | + (((UINT64)isANSI & PIXEventsStringIsANSIWriteMask) << PIXEventsStringIsANSIBitShift); + + *destination++ = encodedStringInfo; +} + +template +inline bool PIXIsPointerAligned(T* pointer) +{ + return !(((UINT64)pointer) & (alignment - 1)); +} + +// Generic template version slower because of the additional clear write +template +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, T argument) +{ + if (destination < limit) + { + *destination = 0ull; + *((T*)destination) = argument; + ++destination; + } +} + +// int32 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT32 argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } +} + +// unsigned int32 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT32 argument) +{ + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } +} + +// int64 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT64 argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = argument; + ++destination; + } +} + +// unsigned int64 specialization to avoid slower double memory writes +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT64 argument) +{ + if (destination < limit) + { + *destination = argument; + ++destination; + } +} + +//floats must be cast to double during writing the data to be properly printed later when reading the data +//this is needed because when float is passed to varargs function it's cast to double +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, float argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } +} + +//char has to be cast to a longer signed integer type +//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, char argument) +{ + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } +} + +//UINT8 has to be cast to a longer unsigned integer type +//this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT8 argument) +{ + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } +} + +//bool has to be cast to an integer since it's not explicitly supported by string format routines +//there's no format specifier for bool type, but it should work with integer format specifiers +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, bool argument) +{ + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } +} + +inline void PIXCopyEventStringArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + while (destination < limit) + { + UINT64 c = static_cast(argument[0]); + if (!c) + { + *destination++ = 0; + return; + } + UINT64 x = c; + c = static_cast(argument[1]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 8; + c = static_cast(argument[2]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 16; + c = static_cast(argument[3]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 24; + c = static_cast(argument[4]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 32; + c = static_cast(argument[5]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 40; + c = static_cast(argument[6]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 48; + c = static_cast(argument[7]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 56; + *destination++ = x; + argument += 8; + } +} + +template +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + PIXEncodeStringInfo(destination, TRUE); + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +template<> +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + +inline void PIXCopyEventStringArgumentFast(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + constexpr UINT64 mask1 = 0x0101010101010101ULL; + constexpr UINT64 mask2 = 0x8080808080808080ULL; + UINT64* source = (UINT64*)argument; + + while (destination < limit) + { + UINT64 qword = *source++; + *destination++ = qword; + + //check if any of the characters is a terminating zero + UINT64 isTerminated = (qword - mask1) & (~qword & mask2); + + if (isTerminated) + { + break; + } + } +} +#endif + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + if (destination < limit) + { + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + PIXEncodeStringInfo(destination, TRUE); + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } +} + +inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) +{ + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } +} + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument) +{ + PIXCopyEventArgument(destination, limit, (PCSTR)argument); +} + +inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument) +{ + PIXCopyStringArgument(destination, limit, (PCSTR)argument); +} + +inline void PIXCopyEventStringArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + while (destination < limit) + { + UINT64 c = static_cast(argument[0]); + if (!c) + { + *destination++ = 0; + return; + } + UINT64 x = c; + c = static_cast(argument[1]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 16; + c = static_cast(argument[2]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 32; + c = static_cast(argument[3]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 48; + *destination++ = x; + argument += 4; + } +} + +template +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + PIXEncodeStringInfo(destination, FALSE); + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +template<> +inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + PIXCopyEventStringArgumentSlow(destination, limit, argument); +} + +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY +inline void PIXCopyEventStringArgumentFast(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + UINT64* source = (UINT64*)argument; + while (destination < limit) + { + UINT64 qword = *source++; + *destination++ = qword; + //check if any of the characters is a terminating zero + //TODO: check if reversed condition is faster + if (!((qword & 0xFFFF000000000000) && + (qword & 0xFFFF00000000) && + (qword & 0xFFFF0000) && + (qword & 0xFFFF))) + { + break; + } + } +} +#endif + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + if (destination < limit) + { + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + PIXEncodeStringInfo(destination, FALSE); + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } +} + +inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) +{ + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + PIXCopyEventStringArgumentFast(destination, limit, argument); + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } +} + +template<> +inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PWSTR argument) +{ + PIXCopyEventArgument(destination, limit, (PCWSTR)argument); +}; + +inline void PIXCopyStringArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PWSTR argument) +{ + PIXCopyStringArgument(destination, limit, (PCWSTR)argument); +}; + +#if defined(__d3d12_x_h__) || defined(__d3d12_xs_h__) || defined(__d3d12_h__) + +inline void PIXSetGPUMarkerOnContext(_In_ ID3D12GraphicsCommandList* commandList, _In_reads_bytes_(size) void* data, UINT size) +{ + commandList->SetMarker(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXSetGPUMarkerOnContext(_In_ ID3D12CommandQueue* commandQueue, _In_reads_bytes_(size) void* data, UINT size) +{ + commandQueue->SetMarker(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXBeginGPUEventOnContext(_In_ ID3D12GraphicsCommandList* commandList, _In_reads_bytes_(size) void* data, UINT size) +{ + commandList->BeginEvent(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXBeginGPUEventOnContext(_In_ ID3D12CommandQueue* commandQueue, _In_reads_bytes_(size) void* data, UINT size) +{ + commandQueue->BeginEvent(D3D12_EVENT_METADATA, data, size); +} + +inline void PIXEndGPUEventOnContext(_In_ ID3D12GraphicsCommandList* commandList) +{ + commandList->EndEvent(); +} + +inline void PIXEndGPUEventOnContext(_In_ ID3D12CommandQueue* commandQueue) +{ + commandQueue->EndEvent(); +} + +#endif //__d3d12_h__ + +template struct PIXInferScopedEventType { typedef T Type; }; +template struct PIXInferScopedEventType { typedef T Type; }; +template struct PIXInferScopedEventType { typedef T Type; }; +template struct PIXInferScopedEventType { typedef T Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; +template<> struct PIXInferScopedEventType { typedef void Type; }; + +#endif //_PIXEventsCommon_H_ diff --git a/Kits/AMDTK/fidelityfx/libs/pix/PIXEventsLegacy.h b/Kits/AMDTK/fidelityfx/libs/pix/PIXEventsLegacy.h new file mode 100644 index 00000000..b5b08bea --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/pix/PIXEventsLegacy.h @@ -0,0 +1,565 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +// Don't include this file directly - use pix3.h +// This file encodes PIX events in the legacy PIX event format. + +#ifndef _PIXEventsLegacy_H_ +#define _PIXEventsLegacy_H_ + +#include + +#if defined(_M_X64) || defined(_M_IX86) +#include +#endif + +namespace PixEventsLegacy +{ + enum PIXEventType + { + PIXEvent_EndEvent = 0x000, + PIXEvent_BeginEvent_VarArgs = 0x001, + PIXEvent_BeginEvent_NoArgs = 0x002, + PIXEvent_SetMarker_VarArgs = 0x007, + PIXEvent_SetMarker_NoArgs = 0x008, + + PIXEvent_EndEvent_OnContext = 0x010, + PIXEvent_BeginEvent_OnContext_VarArgs = 0x011, + PIXEvent_BeginEvent_OnContext_NoArgs = 0x012, + PIXEvent_SetMarker_OnContext_VarArgs = 0x017, + PIXEvent_SetMarker_OnContext_NoArgs = 0x018, + }; + + static const UINT64 PIXEventsReservedRecordSpaceQwords = 64; + static const UINT64 PIXEventsReservedTailSpaceQwords = 2; + static const UINT64 PIXEventsSafeFastCopySpaceQwords = PIXEventsReservedRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + static const UINT64 PIXEventsGraphicsRecordSpaceQwords = 64; + + //Bits 7-19 (13 bits) + static const UINT64 PIXEventsBlockEndMarker = 0x00000000000FFF80; + + //Bits 10-19 (10 bits) + static const UINT64 PIXEventsTypeReadMask = 0x00000000000FFC00; + static const UINT64 PIXEventsTypeWriteMask = 0x00000000000003FF; + static const UINT64 PIXEventsTypeBitShift = 10; + + //Bits 20-63 (44 bits) + static const UINT64 PIXEventsTimestampReadMask = 0xFFFFFFFFFFF00000; + static const UINT64 PIXEventsTimestampWriteMask = 0x00000FFFFFFFFFFF; + static const UINT64 PIXEventsTimestampBitShift = 20; + + inline UINT64 PIXEncodeEventInfo(UINT64 timestamp, PIXEventType eventType) + { + return ((timestamp & PIXEventsTimestampWriteMask) << PIXEventsTimestampBitShift) | + (((UINT64)eventType & PIXEventsTypeWriteMask) << PIXEventsTypeBitShift); + } + + //Bits 60-63 (4) + static const UINT64 PIXEventsStringAlignmentWriteMask = 0x000000000000000F; + static const UINT64 PIXEventsStringAlignmentReadMask = 0xF000000000000000; + static const UINT64 PIXEventsStringAlignmentBitShift = 60; + + //Bits 55-59 (5) + static const UINT64 PIXEventsStringCopyChunkSizeWriteMask = 0x000000000000001F; + static const UINT64 PIXEventsStringCopyChunkSizeReadMask = 0x0F80000000000000; + static const UINT64 PIXEventsStringCopyChunkSizeBitShift = 55; + + //Bit 54 + static const UINT64 PIXEventsStringIsANSIWriteMask = 0x0000000000000001; + static const UINT64 PIXEventsStringIsANSIReadMask = 0x0040000000000000; + static const UINT64 PIXEventsStringIsANSIBitShift = 54; + + //Bit 53 + static const UINT64 PIXEventsStringIsShortcutWriteMask = 0x0000000000000001; + static const UINT64 PIXEventsStringIsShortcutReadMask = 0x0020000000000000; + static const UINT64 PIXEventsStringIsShortcutBitShift = 53; + + inline UINT64 PIXEncodeStringInfo(UINT64 alignment, UINT64 copyChunkSize, BOOL isANSI, BOOL isShortcut) + { + return ((alignment & PIXEventsStringAlignmentWriteMask) << PIXEventsStringAlignmentBitShift) | + ((copyChunkSize & PIXEventsStringCopyChunkSizeWriteMask) << PIXEventsStringCopyChunkSizeBitShift) | + (((UINT64)isANSI & PIXEventsStringIsANSIWriteMask) << PIXEventsStringIsANSIBitShift) | + (((UINT64)isShortcut & PIXEventsStringIsShortcutWriteMask) << PIXEventsStringIsShortcutBitShift); + } + + template + inline bool PIXIsPointerAligned(T* pointer) + { + return !(((UINT64)pointer) & (alignment - 1)); + } + + // Generic template version slower because of the additional clear write + template + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, T argument) + { + if (destination < limit) + { + *destination = 0ull; + *((T*)destination) = argument; + ++destination; + } + } + + // int32 specialization to avoid slower double memory writes + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT32 argument) + { + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } + } + + // unsigned int32 specialization to avoid slower double memory writes + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT32 argument) + { + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } + } + + // int64 specialization to avoid slower double memory writes + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, INT64 argument) + { + if (destination < limit) + { + *reinterpret_cast(destination) = argument; + ++destination; + } + } + + // unsigned int64 specialization to avoid slower double memory writes + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, UINT64 argument) + { + if (destination < limit) + { + *destination = argument; + ++destination; + } + } + + //floats must be cast to double during writing the data to be properly printed later when reading the data + //this is needed because when float is passed to varargs function it's cast to double + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, float argument) + { + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } + } + + //char has to be cast to a longer signed integer type + //this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, char argument) + { + if (destination < limit) + { + *reinterpret_cast(destination) = static_cast(argument); + ++destination; + } + } + + //unsigned char has to be cast to a longer unsigned integer type + //this is due to printf not ignoring correctly the upper bits of unsigned long long for a char format specifier + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, unsigned char argument) + { + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } + } + + //bool has to be cast to an integer since it's not explicitly supported by string format routines + //there's no format specifier for bool type, but it should work with integer format specifiers + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, bool argument) + { + if (destination < limit) + { + *destination = static_cast(argument); + ++destination; + } + } + + inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) + { + *destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE); + while (destination < limit) + { + UINT64 c = static_cast(argument[0]); + if (!c) + { + *destination++ = 0; + return; + } + UINT64 x = c; + c = static_cast(argument[1]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 8; + c = static_cast(argument[2]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 16; + c = static_cast(argument[3]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 24; + c = static_cast(argument[4]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 32; + c = static_cast(argument[5]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 40; + c = static_cast(argument[6]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 48; + c = static_cast(argument[7]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 56; + *destination++ = x; + argument += 8; + } + } + + inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) + { +#if PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 8, TRUE, FALSE); + UINT64* source = (UINT64*)argument; + while (destination < limit) + { + UINT64 qword = *source++; + *destination++ = qword; + //check if any of the characters is a terminating zero + if (!((qword & 0xFF00000000000000) && + (qword & 0xFF000000000000) && + (qword & 0xFF0000000000) && + (qword & 0xFF00000000) && + (qword & 0xFF000000) && + (qword & 0xFF0000) && + (qword & 0xFF00) && + (qword & 0xFF))) + { + break; + } + } + } + else +#endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlowest(destination, limit, argument); + } + } + + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCSTR argument) + { + if (destination < limit) + { + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<16>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 16, TRUE, FALSE); + __m128i zero = _mm_setzero_si128(); + if (PIXIsPointerAligned<16>(destination)) + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_store_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi8(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 16; + } + } + else + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_storeu_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi8(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 16; + } + } + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } + } + + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PSTR argument) + { + PIXCopyEventArgument(destination, limit, (PCSTR)argument); + } + + inline void PIXCopyEventArgumentSlowest(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) + { + *destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE); + while (destination < limit) + { + UINT64 c = static_cast(argument[0]); + if (!c) + { + *destination++ = 0; + return; + } + UINT64 x = c; + c = static_cast(argument[1]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 16; + c = static_cast(argument[2]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 32; + c = static_cast(argument[3]); + if (!c) + { + *destination++ = x; + return; + } + x |= c << 48; + *destination++ = x; + argument += 4; + } + } + + inline void PIXCopyEventArgumentSlow(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) + { +#if PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<8>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 8, FALSE, FALSE); + UINT64* source = (UINT64*)argument; + while (destination < limit) + { + UINT64 qword = *source++; + *destination++ = qword; + //check if any of the characters is a terminating zero + //TODO: check if reversed condition is faster + if (!((qword & 0xFFFF000000000000) && + (qword & 0xFFFF00000000) && + (qword & 0xFFFF0000) && + (qword & 0xFFFF))) + { + break; + } + } + } + else +#endif // PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlowest(destination, limit, argument); + } + } + + template<> + inline void PIXCopyEventArgument(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, _In_ PCWSTR argument) + { + if (destination < limit) + { + if (argument != nullptr) + { +#if (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + if (PIXIsPointerAligned<16>(argument)) + { + *destination++ = PIXEncodeStringInfo(0, 16, FALSE, FALSE); + __m128i zero = _mm_setzero_si128(); + if (PIXIsPointerAligned<16>(destination)) + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_store_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi16(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 8; + } + } + else + { + while (destination < limit) + { + __m128i mem = _mm_load_si128((__m128i*)argument); + _mm_storeu_si128((__m128i*)destination, mem); + //check if any of the characters is a terminating zero + __m128i res = _mm_cmpeq_epi16(mem, zero); + destination += 2; + if (_mm_movemask_epi8(res)) + break; + argument += 8; + } + } + } + else +#endif // (defined(_M_X64) || defined(_M_IX86)) && PIX_ENABLE_BLOCK_ARGUMENT_COPY + { + PIXCopyEventArgumentSlow(destination, limit, argument); + } + } + else + { + *destination++ = 0ull; + } + } + } + + inline void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit) + { + // nothing + UNREFERENCED_PARAMETER(destination); + UNREFERENCED_PARAMETER(limit); + } + + template + void PIXCopyEventArguments(_Out_writes_to_ptr_(limit) UINT64*& destination, _In_ const UINT64* limit, ARG const& arg, ARGS const&... args) + { + PIXCopyEventArgument(destination, limit, arg); + PIXCopyEventArguments(destination, limit, args...); + } + + template + struct PIXEventTypeInferer + { + static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_VarArgs; } + static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_VarArgs; } + static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; } + static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; } + static constexpr PIXEventType End() { return PIXEvent_EndEvent; } + + // Xbox and Windows store different types of events for context events. + // On Xbox these include a context argument, while on Windows they do + // not. It is important not to change the event types used on the + // Windows version as there are OS components (eg debug layer & DRED) + // that decode event structs. +#ifdef PIX_XBOX + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_VarArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_VarArgs; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; } +#else + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_VarArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_VarArgs; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; } +#endif + }; + + template<> + struct PIXEventTypeInferer<> + { + static constexpr PIXEventType Begin() { return PIXEvent_BeginEvent_NoArgs; } + static constexpr PIXEventType SetMarker() { return PIXEvent_SetMarker_NoArgs; } + static constexpr PIXEventType BeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; } + static constexpr PIXEventType SetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; } + static constexpr PIXEventType End() { return PIXEvent_EndEvent; } + +#ifdef PIX_XBOX + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_OnContext_NoArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_OnContext_NoArgs; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent_OnContext; } +#else + static constexpr PIXEventType GpuBeginOnContext() { return PIXEvent_BeginEvent_NoArgs; } + static constexpr PIXEventType GpuSetMarkerOnContext() { return PIXEvent_SetMarker_NoArgs; } + static constexpr PIXEventType GpuEndOnContext() { return PIXEvent_EndEvent; } +#endif + }; + + + template + UINT64* EncodeBeginEventForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer::GpuBeginOnContext()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + *destination = 0ull; + + return destination; + } + + template + UINT64* EncodeSetMarkerForContext(UINT64 (&buffer)[size], UINT64 color, STR formatString, ARGS... args) + { + UINT64* destination = buffer; + UINT64* limit = buffer + PIXEventsGraphicsRecordSpaceQwords - PIXEventsReservedTailSpaceQwords; + + *destination++ = PIXEncodeEventInfo(0, PIXEventTypeInferer::GpuSetMarkerOnContext()); + *destination++ = color; + + PIXCopyEventArguments(destination, limit, formatString, args...); + *destination = 0ull; + + return destination; + } +} + +#endif //_PIXEventsLegacy_H_ diff --git a/Kits/AMDTK/fidelityfx/libs/pix/pix3.h b/Kits/AMDTK/fidelityfx/libs/pix/pix3.h new file mode 100644 index 00000000..b13e8bc7 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/pix/pix3.h @@ -0,0 +1,195 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. + +#pragma once + +#ifndef _PIX3_H_ +#define _PIX3_H_ + +#include + +#ifndef __cplusplus +#error "Only C++ files can include pix3.h. C is not supported." +#endif + +#if !defined(USE_PIX_SUPPORTED_ARCHITECTURE) +#if defined(_M_X64) || defined(USE_PIX_ON_ALL_ARCHITECTURES) || defined(_M_ARM64) +#define USE_PIX_SUPPORTED_ARCHITECTURE +#endif +#endif + +#if !defined(USE_PIX) +#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && (defined(_DEBUG) || DBG || defined(PROFILE) || defined(PROFILE_BUILD)) && !defined(_PREFAST_) +#define USE_PIX +#endif +#endif + +#if defined(USE_PIX) && !defined(USE_PIX_SUPPORTED_ARCHITECTURE) +#pragma message("Warning: Pix markers are only supported on AMD64 and ARM64") +#endif + + +// These flags are used by both PIXBeginCapture and PIXGetCaptureState +#define PIX_CAPTURE_TIMING (1 << 0) +#define PIX_CAPTURE_GPU (1 << 1) +#define PIX_CAPTURE_FUNCTION_SUMMARY (1 << 2) +#define PIX_CAPTURE_FUNCTION_DETAILS (1 << 3) +#define PIX_CAPTURE_CALLGRAPH (1 << 4) +#define PIX_CAPTURE_INSTRUCTION_TRACE (1 << 5) +#define PIX_CAPTURE_SYSTEM_MONITOR_COUNTERS (1 << 6) +#define PIX_CAPTURE_VIDEO (1 << 7) +#define PIX_CAPTURE_AUDIO (1 << 8) +#define PIX_CAPTURE_GPU_TRACE (1 << 9) +#define PIX_CAPTURE_RESERVED (1 << 15) + +union PIXCaptureParameters +{ + enum PIXCaptureStorage + { + Memory = 0, + MemoryCircular = 1, // Xbox only + FileCircular = 2, // PC only + }; + + struct GpuCaptureParameters + { + PCWSTR FileName; + } GpuCaptureParameters; + + struct TimingCaptureParameters + { + PCWSTR FileName; + UINT32 MaximumToolingMemorySizeMb; + PIXCaptureStorage CaptureStorage; + + BOOL CaptureGpuTiming; + + BOOL CaptureCallstacks; + BOOL CaptureCpuSamples; + UINT32 CpuSamplesPerSecond; + + BOOL CaptureFileIO; + + BOOL CaptureVirtualAllocEvents; + BOOL CaptureHeapAllocEvents; + BOOL CaptureXMemEvents; // Xbox only + BOOL CapturePixMemEvents; + BOOL CapturePageFaultEvents; + BOOL CaptureVideoFrames; // Xbox only + } TimingCaptureParameters; + + struct GpuTraceParameters // Xbox Series and newer only + { + PWSTR FileName; + UINT32 MaximumToolingMemorySizeMb; + + BOOL CaptureGpuOccupancy; + + } GpuTraceParameters; +}; + +typedef PIXCaptureParameters* PPIXCaptureParameters; + +#if defined(XBOX) || defined(_XBOX_ONE) || defined(_DURANGO) || defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT) +#include "pix3_xbox.h" +#else +#include "pix3_win.h" +#endif + +#if defined(XBOX) || defined(_XBOX_ONE) || defined(_DURANGO) || defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT) +#define PIX_XBOX +#if defined(_GAMING_XBOX) || defined(_GAMING_XBOX_SCARLETT) +#define PIX_GAMING_XBOX +#endif +#endif + +#if !defined(PIX_USE_GPU_MARKERS_V2) +#ifdef PIX_GAMING_XBOX +#define PIX_USE_GPU_MARKERS_V2 +#endif +#endif + +#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && (defined(USE_PIX) || defined(USE_PIX_RETAIL)) + +#define PIX_EVENTS_ARE_TURNED_ON + +#include "PIXEventsCommon.h" +#include "PIXEvents.h" + +#ifdef USE_PIX +// Starts a programmatically controlled capture. +// captureFlags uses the PIX_CAPTURE_* family of flags to specify the type of capture to take +extern "C" HRESULT WINAPI PIXBeginCapture2(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters); +inline HRESULT PIXBeginCapture(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters) { return PIXBeginCapture2(captureFlags, captureParameters); } + +// Stops a programmatically controlled capture +// If discard == TRUE, the captured data is discarded +// If discard == FALSE, the captured data is saved +// discard parameter is not supported on Windows +extern "C" HRESULT WINAPI PIXEndCapture(BOOL discard); + +extern "C" DWORD WINAPI PIXGetCaptureState(); + +extern "C" void WINAPI PIXReportCounter(_In_ PCWSTR name, float value); + +#endif // USE_PIX + +#endif // (USE_PIX_SUPPORTED_ARCHITECTURE) && (USE_PIX || USE_PIX_RETAIL) + +#if !defined(USE_PIX_SUPPORTED_ARCHITECTURE) || !defined(USE_PIX) + +// Eliminate these APIs when not using PIX +inline HRESULT PIXBeginCapture2(DWORD, _In_opt_ const PIXCaptureParameters*) { return S_OK; } +inline HRESULT PIXBeginCapture(DWORD, _In_opt_ const PIXCaptureParameters*) { return S_OK; } +inline HRESULT PIXEndCapture(BOOL) { return S_OK; } +inline HRESULT PIXGpuCaptureNextFrames(PCWSTR, UINT32) { return S_OK; } +inline HRESULT PIXSetTargetWindow(HWND) { return S_OK; } +inline HRESULT PIXForceD3D11On12() { return S_OK; } +inline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions) { return S_OK; } +inline bool WINAPI PIXIsAttachedForGpuCapture() { return false; } +inline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR) { return 0; } +inline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary() { return nullptr; } +inline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary() { return nullptr; } +inline DWORD PIXGetCaptureState() { return 0; } +inline void PIXReportCounter(_In_ PCWSTR, float) {} +inline void PIXNotifyWakeFromFenceSignal(_In_ HANDLE) {} + +#if !defined(USE_PIX_RETAIL) + +inline void PIXBeginEvent(UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(UINT64, _In_ PCWSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginEvent(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXEndEvent() {} +inline void PIXEndEvent(void*) {} +inline void PIXSetMarker(UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(UINT64, _In_ PCWSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXSetMarker(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXBeginRetailEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXBeginRetailEvent(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXEndRetailEvent(void*) {} +inline void PIXSetRetailMarker(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXSetRetailMarker(void*, UINT64, _In_ PCWSTR, ...) {} +inline void PIXScopedEvent(UINT64, _In_ PCSTR, ...) {} +inline void PIXScopedEvent(UINT64, _In_ PCWSTR, ...) {} +inline void PIXScopedEvent(void*, UINT64, _In_ PCSTR, ...) {} +inline void PIXScopedEvent(void*, UINT64, _In_ PCWSTR, ...) {} + +#endif // !USE_PIX_RETAIL + +// don't show warnings about expressions with no effect +#pragma warning(disable:4548) +#pragma warning(disable:4555) + +#endif // !USE_PIX_SUPPORTED_ARCHITECTURE || !USE_PIX + +// Use these functions to specify colors to pass as metadata to a PIX event/marker API. +// Use PIX_COLOR() to specify a particular color for an event. +// Or, use PIX_COLOR_INDEX() to specify a set of unique event categories, and let PIX choose +// the colors to represent each category. +inline UINT32 PIX_COLOR(UINT8 r, UINT8 g, UINT8 b) { return 0xff000000u | ((UINT32)r << 16) | ((UINT32)g << 8) | (UINT32)b; } +inline UINT8 PIX_COLOR_INDEX(UINT8 i) { return i; } +const UINT8 PIX_COLOR_DEFAULT = PIX_COLOR_INDEX(0); + +#endif // _PIX3_H_ diff --git a/Kits/AMDTK/fidelityfx/libs/pix/pix3_win.h b/Kits/AMDTK/fidelityfx/libs/pix/pix3_win.h new file mode 100644 index 00000000..9fd7baff --- /dev/null +++ b/Kits/AMDTK/fidelityfx/libs/pix/pix3_win.h @@ -0,0 +1,509 @@ +// Copyright (c) Microsoft Corporation. +// Licensed under the MIT License. +// Don't include this file directly - use pix3.h + +#pragma once + +#ifndef _PIX3_H_ +#error Don't include this file directly - use pix3.h +#endif + +#ifndef _PIX3_WIN_H_ +#define _PIX3_WIN_H_ + +// PIXEventsThreadInfo is defined in PIXEventsCommon.h +struct PIXEventsThreadInfo; + +extern "C" PIXEventsThreadInfo* WINAPI PIXGetThreadInfo() noexcept; + +#if defined(USE_PIX) && defined(USE_PIX_SUPPORTED_ARCHITECTURE) +// Notifies PIX that an event handle was set as a result of a D3D12 fence being signaled. +// The event specified must have the same handle value as the handle +// used in ID3D12Fence::SetEventOnCompletion. +extern "C" void WINAPI PIXNotifyWakeFromFenceSignal(_In_ HANDLE event); + +// Notifies PIX that a block of memory was allocated +extern "C" void WINAPI PIXRecordMemoryAllocationEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata); + +// Notifies PIX that a block of memory was freed +extern "C" void WINAPI PIXRecordMemoryFreeEvent(USHORT allocatorId, void* baseAddress, size_t size, UINT64 metadata); + +#else + +// Eliminate these APIs when not using PIX +inline void PIXRecordMemoryAllocationEvent(USHORT, void*, size_t, UINT64) {} +inline void PIXRecordMemoryFreeEvent(USHORT, void*, size_t, UINT64) {} + +#endif + +// The following WINPIX_EVENT_* defines denote the different metadata values that have +// been used by tools to denote how to parse pix marker event data. The first two values +// are legacy values used by pix.h in the Windows SDK. +#define WINPIX_EVENT_UNICODE_VERSION 0 +#define WINPIX_EVENT_ANSI_VERSION 1 + +// These values denote PIX marker event data that was created by the WinPixEventRuntime. +// In early 2023 we revised the PIX marker format and defined a new version number. +#define WINPIX_EVENT_PIX3BLOB_VERSION 2 +#define WINPIX_EVENT_PIX3BLOB_V2 6345127 // A number that other applications are unlikely to have used before + +// For backcompat reasons, the WinPixEventRuntime uses the older PIX3BLOB format when it passes data +// into the D3D12 runtime. It will be updated to use the V2 format in the future. +#define D3D12_EVENT_METADATA WINPIX_EVENT_PIX3BLOB_VERSION + +__forceinline UINT64 PIXGetTimestampCounter() +{ + LARGE_INTEGER time = {}; + QueryPerformanceCounter(&time); + return static_cast(time.QuadPart); +} + +enum PIXHUDOptions +{ + PIX_HUD_SHOW_ON_ALL_WINDOWS = 0x1, + PIX_HUD_SHOW_ON_TARGET_WINDOW_ONLY = 0x2, + PIX_HUD_SHOW_ON_NO_WINDOWS = 0x4 +}; +DEFINE_ENUM_FLAG_OPERATORS(PIXHUDOptions); + +#if defined(USE_PIX_SUPPORTED_ARCHITECTURE) && defined(USE_PIX) + +#if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM | WINAPI_PARTITION_GAMES) + +#include +#include +#include +#include + +#define PIXERRORCHECK(value) do { \ + if (FAILED(value)) \ + return nullptr; \ + } while(0) + +namespace PixImpl +{ +#ifndef PIX3_WIN_UNIT_TEST + + __forceinline BOOL GetModuleHandleExW( + DWORD dwFlags, + LPCWSTR lpModuleName, + HMODULE* phModule) + { + return ::GetModuleHandleExW(dwFlags, lpModuleName, phModule); + } + + __forceinline HRESULT SHGetKnownFolderPath( + REFKNOWNFOLDERID rfid, + DWORD dwFlags, + HANDLE hToken, + PWSTR* ppszPath) + { + return ::SHGetKnownFolderPath(rfid, dwFlags, hToken, ppszPath); + } + + __forceinline void CoTaskMemFree(LPVOID pv) + { + return ::CoTaskMemFree(pv); + } + + __forceinline HANDLE FindFirstFileW( + LPCWSTR lpFileName, + LPWIN32_FIND_DATAW lpFindFileData) + { + return ::FindFirstFileW(lpFileName, lpFindFileData); + } + + __forceinline DWORD GetFileAttributesW(LPCWSTR lpFileName) + { + return ::GetFileAttributesW(lpFileName); + } + + __forceinline BOOL FindNextFileW( + HANDLE hFindFile, + LPWIN32_FIND_DATAW lpFindFileData) + { + return ::FindNextFileW(hFindFile, lpFindFileData); + } + + __forceinline BOOL FindClose(HANDLE hFindFile) + { + return ::FindClose(hFindFile); + } + + __forceinline HMODULE LoadLibraryExW(LPCWSTR lpLibFileName, DWORD flags) + { + return ::LoadLibraryExW(lpLibFileName, NULL, flags); + } + +#endif // !PIX3_WIN_UNIT_TESTS + + __forceinline void * GetGpuCaptureFunctionPtr(LPCSTR fnName) noexcept + { + HMODULE module = GetModuleHandleW(L"WinPixGpuCapturer.dll"); + if (module == NULL) + { + return nullptr; + } + + auto fn = (void*)GetProcAddress(module, fnName); + if (fn == nullptr) + { + return nullptr; + } + + return fn; + } + + __forceinline void* GetTimingCaptureFunctionPtr(LPCSTR fnName) noexcept + { + HMODULE module = GetModuleHandleW(L"WinPixTimingCapturer.dll"); + if (module == NULL) + { + return nullptr; + } + + auto fn = (void*)GetProcAddress(module, fnName); + if (fn == nullptr) + { + return nullptr; + } + + return fn; + } + + __forceinline HMODULE PIXLoadLatestCapturerLibrary(wchar_t const* capturerDllName, DWORD flags) + { + HMODULE libHandle{}; + + if (PixImpl::GetModuleHandleExW(0, capturerDllName, &libHandle)) + { + return libHandle; + } + + LPWSTR programFilesPath = nullptr; + if (FAILED(PixImpl::SHGetKnownFolderPath(FOLDERID_ProgramFiles, KF_FLAG_DEFAULT, NULL, &programFilesPath))) + { + PixImpl::CoTaskMemFree(programFilesPath); + return nullptr; + } + + wchar_t pixSearchPath[MAX_PATH]; + + if (FAILED(StringCchCopyW(pixSearchPath, MAX_PATH, programFilesPath))) + { + PixImpl::CoTaskMemFree(programFilesPath); + return nullptr; + } + PixImpl::CoTaskMemFree(programFilesPath); + + PIXERRORCHECK(StringCchCatW(pixSearchPath, MAX_PATH, L"\\Microsoft PIX\\*")); + + WIN32_FIND_DATAW findData; + bool foundPixInstallation = false; + wchar_t newestVersionFound[MAX_PATH]; + wchar_t output[MAX_PATH]; + wchar_t possibleOutput[MAX_PATH]; + + HANDLE hFind = PixImpl::FindFirstFileW(pixSearchPath, &findData); + if (hFind != INVALID_HANDLE_VALUE) + { + do + { + if (((findData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY) && + (findData.cFileName[0] != '.')) + { + if (!foundPixInstallation || wcscmp(newestVersionFound, findData.cFileName) <= 0) + { + // length - 1 to get rid of the wildcard character in the search path + PIXERRORCHECK(StringCchCopyNW(possibleOutput, MAX_PATH, pixSearchPath, wcslen(pixSearchPath) - 1)); + PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, findData.cFileName)); + PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, L"\\")); + PIXERRORCHECK(StringCchCatW(possibleOutput, MAX_PATH, capturerDllName)); + + DWORD result = PixImpl::GetFileAttributesW(possibleOutput); + + if (result != INVALID_FILE_ATTRIBUTES && !(result & FILE_ATTRIBUTE_DIRECTORY)) + { + foundPixInstallation = true; + PIXERRORCHECK(StringCchCopyW(newestVersionFound, _countof(newestVersionFound), findData.cFileName)); + PIXERRORCHECK(StringCchCopyW(output, _countof(possibleOutput), possibleOutput)); + } + } + } + } while (PixImpl::FindNextFileW(hFind, &findData) != 0); + } + + PixImpl::FindClose(hFind); + + if (!foundPixInstallation) + { + SetLastError(ERROR_FILE_NOT_FOUND); + return nullptr; + } + + return PixImpl::LoadLibraryExW(output, flags); + } +} + +#undef PIXERRORCHECK + +__forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary() +{ + return PixImpl::PIXLoadLatestCapturerLibrary( + L"WinPixGpuCapturer.dll", + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS); +} + +__forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary() +{ + return PixImpl::PIXLoadLatestCapturerLibrary( + L"WinPixTimingCapturer.dll", + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS | LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR); +} + +__forceinline HRESULT WINAPI PIXSetTargetWindow(HWND hwnd) +{ + typedef void(WINAPI* SetGlobalTargetWindowFn)(HWND); + + auto fn = (SetGlobalTargetWindowFn)PixImpl::GetGpuCaptureFunctionPtr("SetGlobalTargetWindow"); + if (fn == nullptr) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + fn(hwnd); + return S_OK; +} + +__forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR fileName, UINT32 numFrames) +{ + typedef HRESULT(WINAPI* CaptureNextFrameFn)(PCWSTR, UINT32); + + auto fn = (CaptureNextFrameFn)PixImpl::GetGpuCaptureFunctionPtr("CaptureNextFrame"); + if (fn == nullptr) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + return fn(fileName, numFrames); +} + +extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD captureFlags, _In_opt_ const PPIXCaptureParameters captureParameters) +{ + if (captureFlags == PIX_CAPTURE_GPU) + { + typedef HRESULT(WINAPI* BeginProgrammaticGpuCaptureFn)(const PPIXCaptureParameters); + + auto fn = (BeginProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("BeginProgrammaticGpuCapture"); + if (fn == nullptr) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + return fn(captureParameters); + } + else if (captureFlags == PIX_CAPTURE_TIMING) + { + typedef HRESULT(WINAPI* BeginProgrammaticTimingCaptureFn)(void const*, UINT64); + + auto fn = (BeginProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("BeginProgrammaticTimingCapture"); + if (fn == nullptr) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + return fn(&captureParameters->TimingCaptureParameters, sizeof(captureParameters->TimingCaptureParameters)); + } + else + { + return E_NOTIMPL; + } +} + +extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL discard) +{ + // We can't tell if the user wants to end a GPU Capture or a Timing Capture. + // The user shouldn't have both WinPixGpuCapturer and WinPixTimingCapturer loaded in the process though, + // so we can just look for one of them and call it. + typedef HRESULT(WINAPI* EndProgrammaticGpuCaptureFn)(void); + auto gpuFn = (EndProgrammaticGpuCaptureFn)PixImpl::GetGpuCaptureFunctionPtr("EndProgrammaticGpuCapture"); + if (gpuFn != NULL) + { + return gpuFn(); + } + + typedef HRESULT(WINAPI* EndProgrammaticTimingCaptureFn)(BOOL); + auto timingFn = (EndProgrammaticTimingCaptureFn)PixImpl::GetTimingCaptureFunctionPtr("EndProgrammaticTimingCapture"); + if (timingFn != NULL) + { + return timingFn(discard); + } + + return HRESULT_FROM_WIN32(GetLastError()); +} + +__forceinline HRESULT WINAPI PIXForceD3D11On12() +{ + typedef HRESULT (WINAPI* ForceD3D11On12Fn)(void); + + auto fn = (ForceD3D11On12Fn)PixImpl::GetGpuCaptureFunctionPtr("ForceD3D11On12"); + if (fn == NULL) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + return fn(); +} + +__forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions hudOptions) +{ + typedef HRESULT(WINAPI* SetHUDOptionsFn)(PIXHUDOptions); + + auto fn = (SetHUDOptionsFn)PixImpl::GetGpuCaptureFunctionPtr("SetHUDOptions"); + if (fn == NULL) + { + return HRESULT_FROM_WIN32(GetLastError()); + } + + return fn(hudOptions); +} + +__forceinline bool WINAPI PIXIsAttachedForGpuCapture() +{ + typedef bool(WINAPI* GetIsAttachedToPixFn)(void); + auto fn = (GetIsAttachedToPixFn)PixImpl::GetGpuCaptureFunctionPtr("GetIsAttachedToPix"); + if (fn == NULL) + { + OutputDebugStringW(L"WinPixEventRuntime error: Mismatched header/dll. Please ensure that pix3.h and WinPixGpuCapturer.dll match"); + return false; + } + + return fn(); +} + +__forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR fileName) +{ + return ShellExecuteW(0, 0, fileName, 0, 0, SW_SHOW); +} + +#else +__forceinline HMODULE PIXLoadLatestWinPixGpuCapturerLibrary() +{ + return nullptr; +} +__forceinline HMODULE PIXLoadLatestWinPixTimingCapturerLibrary() +{ + return nullptr; +} +__forceinline HRESULT WINAPI PIXSetTargetWindow(HWND) +{ + return E_NOTIMPL; +} + +__forceinline HRESULT WINAPI PIXGpuCaptureNextFrames(PCWSTR, UINT32) +{ + return E_NOTIMPL; +} +extern "C" __forceinline HRESULT WINAPI PIXBeginCapture2(DWORD, _In_opt_ const PPIXCaptureParameters) +{ + return E_NOTIMPL; +} +extern "C" __forceinline HRESULT WINAPI PIXEndCapture(BOOL) +{ + return E_NOTIMPL; +} +__forceinline HRESULT WINAPI PIXForceD3D11On12() +{ + return E_NOTIMPL; +} +__forceinline HRESULT WINAPI PIXSetHUDOptions(PIXHUDOptions) +{ + return E_NOTIMPL; +} +__forceinline bool WINAPI PIXIsAttachedForGpuCapture() +{ + return false; +} +__forceinline HINSTANCE WINAPI PIXOpenCaptureInUI(PCWSTR) +{ + return 0; +} +#endif // WINAPI_PARTITION + +#endif // USE_PIX_SUPPORTED_ARCHITECTURE || USE_PIX + +#if defined(__d3d12_h__) + +inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->EndEvent(); +} + +inline void PIXInsertTimingMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->EndEvent(); +} + +inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForBeginEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->BeginEvent(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12GraphicsCommandList* commandList, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandList->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForSetMarker(_In_ ID3D12CommandQueue* commandQueue, UINT8 eventType, _In_reads_bytes_(size) void* data, UINT size) +{ + UNREFERENCED_PARAMETER(eventType); + commandQueue->SetMarker(WINPIX_EVENT_PIX3BLOB_V2, data, size); +} + +inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12GraphicsCommandList* commandList, UINT8, void*, UINT) +{ + commandList->EndEvent(); +} + +inline void PIXInsertGPUMarkerOnContextForEndEvent(_In_ ID3D12CommandQueue* commandQueue, UINT8, void*, UINT) +{ + commandQueue->EndEvent(); +} + +#endif + +#endif //_PIX3_WIN_H_ diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeLists.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeLists.txt new file mode 100644 index 00000000..7e843fec --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeLists.txt @@ -0,0 +1,569 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +if(NOT ${FFX_API_DX12}) + return() +endif() + +#include CMake custom command generator functions for compiling shaders. +include("${FFX_GPU_PATH}/CMakeCompileShaders.txt") + +set(PUBLIC_SHADERS "") +set(PRIVATE_SHADERS "") + +file(GLOB PRIVATE_SOURCE + "${FFX_SHARED_PATH}/ffx_assert.cpp" + "${FFX_SHARED_PATH}/ffx_message.cpp" + "${FFX_SHARED_PATH}/ffx_breadcrumbs_list.h" + "${FFX_SHARED_PATH}/ffx_breadcrumbs_list.cpp" + "${FFX_SRC_BACKENDS_PATH}/shared/*.h" + "${FFX_SRC_BACKENDS_PATH}/shared/*.cpp" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/" + "${CMAKE_CURRENT_SOURCE_DIR}/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/FrameInterpolationSwapchain/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/FrameInterpolationSwapchain/*.cpp" +) + +if (FFX_FSR1 OR FFX_ALL) + set(FFX_FSR1_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_fsr1_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_fsr1_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_FSR1_PRIVATE_SOURCE}) + + # Add shaders for FSR1 + + file(GLOB FFX_FSR1_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/fsr1/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_FSR1_PRIVATE_SHADERS}) + + file(GLOB FFX_FSR1_PUBLIC_SHADERS + "${FFX_GPU_PATH}/fsr1/*.h" + "${FFX_GPU_PATH}/fsr1/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_FSR1_PUBLIC_SHADERS}) +endif() + +if (FFX_FSR2 OR FFX_ALL) + set(FFX_FSR2_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_fsr2_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_fsr2_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_FSR2_PRIVATE_SOURCE}) + + # Add shaders for FSR2 + + file(GLOB FFX_FSR2_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/fsr2/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_FSR2_PRIVATE_SHADERS}) + + file(GLOB FFX_FSR2_PUBLIC_SHADERS + "${FFX_GPU_PATH}/fsr2/*.h" + "${FFX_GPU_PATH}/fsr2/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_FSR2_PUBLIC_SHADERS}) +endif() + +if (FFX_FSR3UPSCALER OR FFX_ALL) + set(FFX_FSR3UPSCALER_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_fsr3upscaler_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_fsr3upscaler_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_FSR3UPSCALER_PRIVATE_SOURCE}) + + # Add shaders for FSR3UPSCALER + + file(GLOB FFX_FSR3UPSCALER_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/fsr3upscaler/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_FSR3UPSCALER_PRIVATE_SHADERS}) + + file(GLOB FFX_FSR3UPSCALER_PUBLIC_SHADERS + "${FFX_GPU_PATH}/fsr3upscaler/*.h" + "${FFX_GPU_PATH}/fsr3upscaler/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_FSR3UPSCALER_PUBLIC_SHADERS}) +endif() + +if (FFX_FI OR FFX_ALL) + set(FFX_FI_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_frameinterpolation_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_frameinterpolation_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_FI_PRIVATE_SOURCE}) + + # Add shaders for Frame Interpolation + + file(GLOB FFX_FI_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/frameinterpolation/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_FI_PRIVATE_SHADERS}) + + file(GLOB FFX_FI_PUBLIC_SHADERS + "${FFX_GPU_PATH}/frameinterpolation/*.h" + "${FFX_GPU_PATH}/frameinterpolation/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_FI_PUBLIC_SHADERS}) +endif() + +if (FFX_OF OR FFX_ALL) + set(FFX_OF_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_opticalflow_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_opticalflow_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_OF_PRIVATE_SOURCE}) + + # Add shaders for Optical Flow + + file(GLOB FFX_OF_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/opticalflow/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_OF_PRIVATE_SHADERS}) + + file(GLOB FFX_OF_PUBLIC_SHADERS + "${FFX_GPU_PATH}/opticalflow/*.h" + "${FFX_GPU_PATH}/opticalflow/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_OF_PUBLIC_SHADERS}) +endif() + +if (FFX_SPD OR FFX_ALL) + set(FFX_SPD_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_spd_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_spd_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_SPD_PRIVATE_SOURCE}) + + # Add shaders for SPD + + file(GLOB FFX_SPD_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/spd/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_SPD_PRIVATE_SHADERS}) + + file(GLOB FFX_SPD_PUBLIC_SHADERS + "${FFX_GPU_PATH}/spd/*.h" + "${FFX_GPU_PATH}/spd/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_SPD_PUBLIC_SHADERS}) +endif() + +if (FFX_CACAO OR FFX_ALL) + set(FFX_CACAO_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_cacao_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_cacao_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_CACAO_PRIVATE_SOURCE}) + + # Add shaders for CACAO + + file(GLOB FFX_CACAO_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/cacao/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_CACAO_PRIVATE_SHADERS}) + + file(GLOB FFX_CACAO_PUBLIC_SHADERS + "${FFX_GPU_PATH}/cacao/*.h" + "${FFX_GPU_PATH}/cacao/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_CACAO_PUBLIC_SHADERS}) +endif() + +if (FFX_LPM OR FFX_ALL) + set(FFX_LPM_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_lpm_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_lpm_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_LPM_PRIVATE_SOURCE}) + + # Add shaders for LPM + + file(GLOB FFX_LPM_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/lpm/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_LPM_PRIVATE_SHADERS}) + + file(GLOB FFX_LPM_PUBLIC_SHADERS + "${FFX_GPU_PATH}/lpm/*.h" + "${FFX_GPU_PATH}/lpm/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_LPM_PUBLIC_SHADERS}) +endif() + +if (FFX_BLUR OR FFX_ALL) + set(FFX_BLUR_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_blur_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_blur_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_BLUR_PRIVATE_SOURCE}) + + # Add shaders for BLUR + + file(GLOB FFX_BLUR_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/blur/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_BLUR_PRIVATE_SHADERS}) + + file(GLOB FFX_BLUR_PUBLIC_SHADERS + "${FFX_GPU_PATH}/blur/*.h" + "${FFX_GPU_PATH}/blur/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_BLUR_PUBLIC_SHADERS}) +endif() + +if (FFX_VRS OR FFX_ALL) + set(FFX_VRS_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_vrs_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_vrs_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_VRS_PRIVATE_SOURCE}) + + # Add shaders for VRS + + file(GLOB FFX_VRS_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/vrs/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_VRS_PRIVATE_SHADERS}) + + file(GLOB FFX_VRS_PUBLIC_SHADERS + "${FFX_GPU_PATH}/vrs/*.h" + "${FFX_GPU_PATH}/vrs/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_VRS_PUBLIC_SHADERS}) +endif() + +if (FFX_CAS OR FFX_ALL) + set(FFX_CAS_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_cas_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_cas_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_CAS_PRIVATE_SOURCE}) + + # Add shaders for CAS + + file(GLOB FFX_CAS_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/cas/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_CAS_PRIVATE_SHADERS}) + + file(GLOB FFX_CAS_PUBLIC_SHADERS + "${FFX_GPU_PATH}/cas/*.h" + "${FFX_GPU_PATH}/cas/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_CAS_PUBLIC_SHADERS}) +endif() + +if (FFX_DOF OR FFX_ALL) + set(FFX_DOF_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_dof_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_dof_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_DOF_PRIVATE_SOURCE}) + + # Add shaders for DOF + + file(GLOB FFX_DOF_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/dof/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_DOF_PRIVATE_SHADERS}) + + file(GLOB FFX_DOF_PUBLIC_SHADERS + "${FFX_GPU_PATH}/dof/*.h" + "${FFX_GPU_PATH}/dof/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_DOF_PUBLIC_SHADERS}) +endif() + +if (FFX_LENS OR FFX_ALL) + set(FFX_LENS_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_lens_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_lens_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_LENS_PRIVATE_SOURCE}) + + # Add shaders for LENS + + file(GLOB FFX_LENS_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/lens/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_LENS_PRIVATE_SHADERS}) + + file(GLOB FFX_LENS_PUBLIC_SHADERS + "${FFX_GPU_PATH}/lens/*.h" + "${FFX_GPU_PATH}/lens/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_LENS_PUBLIC_SHADERS}) +endif() + +if (FFX_PARALLEL_SORT OR FFX_ALL) + set(FFX_PARALLEL_SORT_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_parallelsort_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_parallelsort_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_PARALLEL_SORT_PRIVATE_SOURCE}) + + # Add shaders for PARALLEL_SORT + + file(GLOB FFX_PARALLEL_SORT_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/parallelsort/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_PARALLEL_SORT_PRIVATE_SHADERS}) + + file(GLOB FFX_PARALLEL_SORT_PUBLIC_SHADERS + "${FFX_GPU_PATH}/parallelsort/*.h" + "${FFX_GPU_PATH}/parallelsort/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_PARALLEL_SORT_PUBLIC_SHADERS}) +endif() + +if (FFX_DENOISER OR FFX_ALL) + set(FFX_DENOISER_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_denoiser_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_denoiser_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_DENOISER_PRIVATE_SOURCE}) + + # Add shaders for DENOISER + + file(GLOB FFX_DENOISER_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/denoiser/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_DENOISER_PRIVATE_SHADERS}) + + file(GLOB FFX_DENOISER_SORT_PUBLIC_SHADERS + "${FFX_GPU_PATH}/denoiser/*.h" + "${FFX_GPU_PATH}/denoiser/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_DENOISER_SORT_PUBLIC_SHADERS}) +endif() + +if (FFX_CLASSIFIER OR FFX_ALL) + set(FFX_CLASSIFIER_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_classifier_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_classifier_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_CLASSIFIER_PRIVATE_SOURCE}) + + # Add shaders for CLASSIFIER + + file(GLOB FFX_CLASSIFIER_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/classifier/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_CLASSIFIER_PRIVATE_SHADERS}) + + file(GLOB FFX_CLASSIFIER_PUBLIC_SHADERS + "${FFX_GPU_PATH}/classifier/*.h" + "${FFX_GPU_PATH}/classifier/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_CLASSIFIER_PUBLIC_SHADERS}) +endif() + +if (FFX_SSSR OR FFX_ALL) + set(FFX_SSSR_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_sssr_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_sssr_shaderblobs.cpp" + ) + list(APPEND PRIVATE_SOURCE ${FFX_SSSR_PRIVATE_SOURCE}) + + # Add shaders for SSSR + + file(GLOB FFX_SSSR_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/sssr/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_SSSR_PRIVATE_SHADERS}) + + file(GLOB FFX_SSSR_PUBLIC_SHADERS + "${FFX_GPU_PATH}/sssr/*.h" + "${FFX_GPU_PATH}/sssr/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_SSSR_PUBLIC_SHADERS}) +endif() + +if (FFX_BRIXELIZER OR FFX_ALL) + set(FFX_BRIXELIZER_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_brixelizer_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_brixelizer_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_BRIXELIZER_PRIVATE_SOURCE}) + + # Add shaders for Brixelizer + + file(GLOB FFX_BRIXELIZER_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/brixelizer/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_BRIXELIZER_PRIVATE_SHADERS}) + + file(GLOB FFX_BRIXELIZER_PUBLIC_SHADERS + "${FFX_GPU_PATH}/brixelizer/*.h" + "${FFX_GPU_PATH}/brixelizer/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_BRIXELIZER_PUBLIC_SHADERS}) +endif() + +if (FFX_BRIXELIZER_GI OR FFX_ALL) + set(FFX_BRIXELIZER_GI_PRIVATE_SOURCE + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_brixelizergi_shaderblobs.h" + "${FFX_SRC_BACKENDS_PATH}/shared/blob_accessors/ffx_brixelizergi_shaderblobs.cpp") + list(APPEND PRIVATE_SOURCE ${FFX_BRIXELIZER_GI_PRIVATE_SOURCE}) + + # Add shaders for Brixelizer GI + + file(GLOB FFX_BRIXELIZER_GI_PRIVATE_SHADERS + "${CMAKE_CURRENT_SOURCE_DIR}/shaders/brixelizergi/*.hlsl") + list(APPEND PRIVATE_SHADERS ${FFX_BRIXELIZER_GI_PRIVATE_SHADERS}) + + file(GLOB FFX_BRIXELIZER_GI_PUBLIC_SHADERS + "${FFX_GPU_PATH}/brixelizergi/*.h" + "${FFX_GPU_PATH}/brixelizergi/*.hlsl") + list(APPEND PUBLIC_SHADERS ${FFX_BRIXELIZER_GI_PUBLIC_SHADERS}) +endif() + +# Does this need to recurse?? +file(GLOB_RECURSE PUBLIC_SOURCE + "${FFX_HOST_BACKENDS_PATH}/dx12/*.h") + +if (FFX_BUILD_AS_DLL) + add_library(ffx_backend_dx12_${FFX_PLATFORM_NAME} SHARED ${PRIVATE_SOURCE} ${PUBLIC_SOURCE} ${PRIVATE_SHADERS} ${PUBLIC_SHADERS}) +else() + add_library(ffx_backend_dx12_${FFX_PLATFORM_NAME} STATIC ${PRIVATE_SOURCE} ${PUBLIC_SOURCE} ${PRIVATE_SHADERS} ${PUBLIC_SHADERS}) +endif() + +# dx12 backend source +source_group("private_source" FILES ${PRIVATE_SOURCE}) +source_group("public_source" FILES ${PUBLIC_SOURCE}) +source_group("private_shaders" FILES ${PRIVATE_SHADERS}) +source_group("public_shaders" FILES ${PUBLIC_SHADERS}) + +get_filename_component(FFX_PASS_SHADER_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}/../shaders/dx12 ABSOLUTE) + +target_include_directories(ffx_backend_dx12_${FFX_PLATFORM_NAME} PUBLIC ${FFX_INCLUDE_PATH}) +target_include_directories(ffx_backend_dx12_${FFX_PLATFORM_NAME} PUBLIC ${FFX_LIB_PATH}) +target_include_directories(ffx_backend_dx12_${FFX_PLATFORM_NAME} PUBLIC ${FFX_PASS_SHADER_OUTPUT_PATH}) +target_include_directories(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE ${FFX_COMPONENTS_PATH}) +target_include_directories(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE ${FFX_SHARED_PATH}) +target_include_directories(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE "${FFX_SRC_BACKENDS_PATH}/shared") +target_include_directories(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE ${FFX_PASS_SHADER_OUTPUT_PATH}) + +target_link_libraries(ffx_backend_dx12_${FFX_PLATFORM_NAME} pixlib dxgi) + +set_source_files_properties(${PRIVATE_SHADERS} PROPERTIES HEADER_FILE_ONLY TRUE) +set_source_files_properties(${PUBLIC_SHADERS} PROPERTIES HEADER_FILE_ONLY TRUE) + +file(MAKE_DIRECTORY ${FFX_PASS_SHADER_OUTPUT_PATH}) + +if (FFX_AUTO_COMPILE_SHADERS) + set(FFX_SC_DEPENDENT_TARGET ffx_backend_dx12_${FFX_PLATFORM_NAME}) +else() + set(FFX_SC_DEPENDENT_TARGET ffx_backend_dx12_shaders_${FFX_PLATFORM_NAME}) + add_custom_target(${FFX_SC_DEPENDENT_TARGET}) + #add_dependencies(ffx_backend_dx12_${FFX_PLATFORM_NAME} ${FFX_SC_DEPENDENT_TARGET}) +endif() + +if(${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.20.0") + cmake_policy(SET CMP0116 OLD) +endif() + +target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE + NOMINMAX + WIN32_LEAN_AND_MEAN) + +if (MSVC) + target_compile_options(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE + "/W4" # warning level 4 + "/WX" # warnings as errors + # disable MSVC warnings that are too strict + "/wd4201" # nonstandard extension used: nameless struct/union + "/wd4324" # structure was padded due to alignment specifier + "/wd4408" # anonymous struct did not declare any data members + "/wd4505" # unreferenced function with internal linkage has been removed + ) +endif() + +# add pass shaders for all the components +if (FFX_FSR1 OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_FSR1) + include (CMakeShadersFSR1.txt) +endif() + +if (FFX_FSR2 OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_FSR2) + include (CMakeShadersFSR2.txt) +endif() + +if (FFX_FSR3 OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_FSR3) +endif() + +if (FFX_FSR3UPSCALER OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_FSR3UPSCALER) + include (CMakeShadersFSR3Upscaler.txt) +endif() + +if (FFX_FI OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_FI) + include (CMakeShadersFrameinterpolation.txt) +endif() + +if (FFX_OF OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_OF) + include (CMakeShadersOpticalflow.txt) +endif() + +if (FFX_SPD OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_SPD) + include (CMakeShadersSPD.txt) +endif() + +if (FFX_CACAO OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_CACAO) + include (CMakeShadersCACAO.txt) +endif() + +if (FFX_LPM OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_LPM) + include (CMakeShadersLPM.txt) +endif() + +if (FFX_BLUR OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_BLUR) + include (CMakeShadersBlur.txt) +endif() + +if (FFX_VRS OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_VRS) + include (CMakeShadersVRS.txt) +endif() + +if (FFX_CAS OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_CAS) + include (CMakeShadersCAS.txt) +endif() + +if (FFX_DOF OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_DOF) + include (CMakeShadersDOF.txt) +endif() + +if (FFX_LENS OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_LENS) + include (CMakeShadersLENS.txt) +endif() + +if (FFX_PARALLEL_SORT OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_PARALLEL_SORT) + include (CMakeShadersParallelSort.txt) +endif() + +if (FFX_DENOISER OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_DENOISER) + include (CMakeShadersDenoiser.txt) +endif() + +if (FFX_CLASSIFIER OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_CLASSIFIER) + include (CMakeShadersClassifier.txt) +endif() + +if (FFX_SSSR OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_SSSR) + include (CMakeShadersSSSR.txt) +endif() + +if (FFX_BREADCRUMBS OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_BREADCRUMBS) +endif() + +if (FFX_BRIXELIZER OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_BRIXELIZER) + include (CMakeShadersBrixelizer.txt) +endif() + +if (FFX_BRIXELIZER_GI OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_BRIXELIZER_GI) + include (CMakeShadersBrixelizerGI.txt) +endif() + +if (FFX_CLASSIFIER OR FFX_ALL) + target_compile_definitions(ffx_backend_dx12_${FFX_PLATFORM_NAME} PRIVATE FFX_CLASSIFIER) + include (CMakeShadersClassifier.txt) +endif() + +add_custom_target(ffx_shader_permutations_dx12 DEPENDS ${FFX_SC_PERMUTATION_OUTPUTS}) +add_dependencies(${FFX_SC_DEPENDENT_TARGET} ffx_shader_permutations_dx12) + +# Make sure shader builds are a dependency of the backend +add_dependencies(ffx_backend_dx12_${FFX_PLATFORM_NAME} ffx_shader_permutations_dx12) + +# Add to solution folder. +set_target_properties(ffx_backend_dx12_${FFX_PLATFORM_NAME} PROPERTIES FOLDER Backends) +set_target_properties(ffx_shader_permutations_dx12 PROPERTIES FOLDER Backends) diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBlur.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBlur.txt new file mode 100644 index 00000000..62ddf949 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBlur.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(BLUR_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl blur shaders +include("${FFX_GPU_PATH}/blur/CMakeCompileBlurShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBrixelizer.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBrixelizer.txt new file mode 100644 index 00000000..68ce8911 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBrixelizer.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler arguments +set(BRIXELIZER_API_BASE_ARGS + -E CS -Wignored-attributes -O3 -no-warnings -T cs_6_6 -DFFX_HLSL=1) + +# compile hlsl Brixelizer shaders +include("${FFX_GPU_PATH}/brixelizer/CMakeCompileBrixelizerShaders.txt") \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBrixelizerGI.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBrixelizerGI.txt new file mode 100644 index 00000000..062a4daf --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersBrixelizerGI.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler arguments +set(BRIXELIZER_GI_API_BASE_ARGS + -E CS -Wignored-attributes -O3 -no-warnings -T cs_6_6 -DFFX_HLSL=1) + +# compile hlsl Brixelizer GI shaders +include("${FFX_GPU_PATH}/brixelizergi/CMakeCompileBrixelizerGIShaders.txt") \ No newline at end of file diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersCACAO.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersCACAO.txt new file mode 100644 index 00000000..2bab8219 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersCACAO.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(CACAO_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl cacao shaders +include("${FFX_GPU_PATH}/cacao/CMakeCompileCACAOShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersCAS.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersCAS.txt new file mode 100644 index 00000000..63e79a75 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersCAS.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(CAS_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/cas/CMakeCompileCASShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersClassifier.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersClassifier.txt new file mode 100644 index 00000000..5553bd0a --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersClassifier.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(CLASSIFIER_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/classifier/CMakeCompileClassifierShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersDOF.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersDOF.txt new file mode 100644 index 00000000..b1c77f93 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersDOF.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(DOF_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/dof/CMakeCompileDOFShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersDenoiser.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersDenoiser.txt new file mode 100644 index 00000000..01630ab1 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersDenoiser.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(DENOISER_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/denoiser/CMakeCompileDenoiserShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR1.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR1.txt new file mode 100644 index 00000000..7fb38f9b --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR1.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(FSR1_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/fsr1/CMakeCompileFSR1Shaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR2.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR2.txt new file mode 100644 index 00000000..198c7784 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR2.txt @@ -0,0 +1,29 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(FSR2_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/fsr2/CMakeCompileFSR2Shaders.txt") + diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR3Upscaler.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR3Upscaler.txt new file mode 100644 index 00000000..909ee921 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFSR3Upscaler.txt @@ -0,0 +1,27 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(FSR3UPSCALER_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/fsr3upscaler/CMakeCompileFSR3UpscalerShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFrameinterpolation.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFrameinterpolation.txt new file mode 100644 index 00000000..d449aa85 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersFrameinterpolation.txt @@ -0,0 +1,27 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(FRAMEINTERPOLATION_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/frameinterpolation/CMakeCompileFrameinterpolationShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersLENS.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersLENS.txt new file mode 100644 index 00000000..229ab3ab --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersLENS.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(LENS_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/lens/CMakeCompileLENSShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersLPM.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersLPM.txt new file mode 100644 index 00000000..d7403aa0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersLPM.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(LPM_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/lpm/CMakeCompileLPMShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersOpticalflow.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersOpticalflow.txt new file mode 100644 index 00000000..a7b4c4eb --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersOpticalflow.txt @@ -0,0 +1,27 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +set(OPTICALFLOW_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/opticalflow/CMakeCompileOpticalflowShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersParallelSort.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersParallelSort.txt new file mode 100644 index 00000000..cbc2b432 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersParallelSort.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(PARALLELSORT_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/parallelsort/CMakeCompileParallelSortShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersSPD.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersSPD.txt new file mode 100644 index 00000000..f2558e89 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersSPD.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(SPD_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/spd/CMakeCompileSPDShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersSSSR.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersSSSR.txt new file mode 100644 index 00000000..d8eaedf0 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersSSSR.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(SSSR_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/sssr/CMakeCompileSSSRShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersVRS.txt b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersVRS.txt new file mode 100644 index 00000000..4f62b0b2 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/CMakeShadersVRS.txt @@ -0,0 +1,28 @@ +# This file is part of the FidelityFX SDK. +# +# Copyright (C) 2024 Advanced Micro Devices, Inc. +# +# 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. + +# Set DX12 specific compiler args +set(VRS_API_BASE_ARGS + -E CS -Wno-for-redefinition -Wno-ambig-lit-shift -DFFX_HLSL=1) + +# Compile hlsl shaders +include("${FFX_GPU_PATH}/vrs/CMakeCompileVRSShaders.txt") diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDX12_DebugPacing.cpp b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDX12_DebugPacing.cpp new file mode 100644 index 00000000..862c9b53 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDX12_DebugPacing.cpp @@ -0,0 +1,365 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#include "d3d12.h" +#include "FrameInterpolationSwapchainDX12.h" +#include "FrameInterpolationSwapchainDX12_Helpers.h" +#include "FrameInterpolationSwapchainDX12_DebugPacing.h" + +namespace DebugPacingshaders +{ +#include "FrameInterpolationSwapchainDebugPacingVS.h" +#include "FrameInterpolationSwapchainDebugPacingPS.h" +} // namespace DebugPacingshaders; + +typedef HRESULT(__stdcall* D3D12SerializeVersionedRootSignatureType)(const D3D12_VERSIONED_ROOT_SIGNATURE_DESC* pRootSignature, + ID3DBlob** ppBlob, + ID3DBlob** ppErrorBlob); + +const uint32_t s_debugPacingDescRingBufferSize = FFX_FRAME_INTERPOLATION_SWAP_CHAIN_MAX_BUFFER_COUNT * 2 * 1; // FFX_FRAME_INTERPOLATION_SWAP_CHAIN_MAX_BUFFER_COUNT real frames (i.e. * 2), 1 CBV each should be enough +const uint32_t s_debugPacingDescHeapRtvSize = FFX_FRAME_INTERPOLATION_SWAP_CHAIN_MAX_BUFFER_COUNT * 2; +ID3D12RootSignature* s_debugPacingRootSignature; +ID3D12PipelineState* s_debugPacingPipeline; +uint32_t s_debugPacingDescRingBufferBase; +ID3D12DescriptorHeap* s_debugPacingDescRingBuffer; +uint32_t s_debugPacingNextRtvDescriptor; +ID3D12DescriptorHeap* s_debugPacingDescHeapRtvCpu; +ID3D12Resource* s_debugPacingConstantBuffer[FFX_FRAME_INTERPOLATION_SWAP_CHAIN_MAX_BUFFER_COUNT]; +uint32_t s_debugPacingFrameIndex; +const unsigned int s_debugPacingConstantBufferSize = 256u; + +// create the pipeline state to use for UI composition +// pretty similar to FfxCreatePipelineFunc +FfxErrorCodes CreateDebugPacingPipeline(ID3D12Device* dx12Device, DXGI_FORMAT fmt) +{ + D3D12_DESCRIPTOR_RANGE1 range; + range.RangeType = D3D12_DESCRIPTOR_RANGE_TYPE_CBV; + range.NumDescriptors = 1; + range.BaseShaderRegister = 0; + range.RegisterSpace = 0; + range.Flags = D3D12_DESCRIPTOR_RANGE_FLAG_NONE; + range.OffsetInDescriptorsFromTableStart = D3D12_DESCRIPTOR_RANGE_OFFSET_APPEND; + + D3D12_ROOT_PARAMETER1 rootParameters; + rootParameters.ParameterType = D3D12_ROOT_PARAMETER_TYPE_DESCRIPTOR_TABLE; + rootParameters.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; + rootParameters.DescriptorTable.NumDescriptorRanges = 1; + rootParameters.DescriptorTable.pDescriptorRanges = ⦥ + + D3D12_VERSIONED_ROOT_SIGNATURE_DESC rootSignatureDesc; + rootSignatureDesc.Version = D3D_ROOT_SIGNATURE_VERSION_1_1; + rootSignatureDesc.Desc_1_1.NumParameters = 1; + rootSignatureDesc.Desc_1_1.pParameters = &rootParameters; + rootSignatureDesc.Desc_1_1.NumStaticSamplers = 0; + rootSignatureDesc.Desc_1_1.pStaticSamplers = nullptr; + rootSignatureDesc.Desc_1_1.Flags = D3D12_ROOT_SIGNATURE_FLAG_ALLOW_INPUT_ASSEMBLER_INPUT_LAYOUT; + + ID3D12RootSignature* dx12RootSignature; + ID3DBlob* signature = nullptr; + ID3DBlob* error = nullptr; + HMODULE d3d12ModuleHandle = GetModuleHandleW(L"D3D12.dll"); + if (NULL != d3d12ModuleHandle) + { + D3D12SerializeVersionedRootSignatureType d3d12SerializeVersionedRootSignatureFunc = + (D3D12SerializeVersionedRootSignatureType)GetProcAddress(d3d12ModuleHandle, "D3D12SerializeVersionedRootSignature"); + + if (nullptr != d3d12SerializeVersionedRootSignatureFunc) + { + HRESULT result = d3d12SerializeVersionedRootSignatureFunc(&rootSignatureDesc, &signature, &error); + if (FAILED(result)) + { + return FFX_ERROR_BACKEND_API_ERROR; + } + + result = dx12Device->CreateRootSignature(0, signature->GetBufferPointer(), signature->GetBufferSize(), IID_PPV_ARGS(&dx12RootSignature)); + SafeRelease(signature); + SafeRelease(error); + + if (FAILED(result)) + { + return FFX_ERROR_BACKEND_API_ERROR; + } + } + else + { + return FFX_ERROR_BACKEND_API_ERROR; + } + } + else + { + return FFX_ERROR_BACKEND_API_ERROR; + } + + // create the PSO + D3D12_RASTERIZER_DESC rasterDesc; + rasterDesc.FillMode = D3D12_FILL_MODE_SOLID; + rasterDesc.CullMode = D3D12_CULL_MODE_BACK; + rasterDesc.FrontCounterClockwise = FALSE; + rasterDesc.DepthBias = D3D12_DEFAULT_DEPTH_BIAS; + rasterDesc.DepthBiasClamp = D3D12_DEFAULT_DEPTH_BIAS_CLAMP; + rasterDesc.SlopeScaledDepthBias = D3D12_DEFAULT_SLOPE_SCALED_DEPTH_BIAS; + rasterDesc.DepthClipEnable = FALSE; + rasterDesc.MultisampleEnable = FALSE; + rasterDesc.AntialiasedLineEnable = FALSE; + rasterDesc.ForcedSampleCount = 0; + rasterDesc.ConservativeRaster = D3D12_CONSERVATIVE_RASTERIZATION_MODE_OFF; + + D3D12_BLEND_DESC blendDesc; + blendDesc.AlphaToCoverageEnable = FALSE; + blendDesc.IndependentBlendEnable = FALSE; + const D3D12_RENDER_TARGET_BLEND_DESC defaultRenderTargetBlendDesc = { + FALSE, + FALSE, + D3D12_BLEND_ONE, + D3D12_BLEND_ZERO, + D3D12_BLEND_OP_ADD, + D3D12_BLEND_ONE, + D3D12_BLEND_ZERO, + D3D12_BLEND_OP_ADD, + D3D12_LOGIC_OP_NOOP, + D3D12_COLOR_WRITE_ENABLE_ALL, + }; + for (UINT i = 0; i < D3D12_SIMULTANEOUS_RENDER_TARGET_COUNT; ++i) + blendDesc.RenderTarget[i] = defaultRenderTargetBlendDesc; + + D3D12_DEPTH_STENCIL_DESC depthStencilDesc; + depthStencilDesc.DepthEnable = FALSE; + depthStencilDesc.DepthWriteMask = D3D12_DEPTH_WRITE_MASK_ALL; + depthStencilDesc.DepthFunc = D3D12_COMPARISON_FUNC_LESS; + depthStencilDesc.StencilEnable = FALSE; + depthStencilDesc.StencilReadMask = D3D12_DEFAULT_STENCIL_READ_MASK; + depthStencilDesc.StencilWriteMask = D3D12_DEFAULT_STENCIL_WRITE_MASK; + const D3D12_DEPTH_STENCILOP_DESC defaultStencilOp = {D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_STENCIL_OP_KEEP, D3D12_COMPARISON_FUNC_ALWAYS}; + depthStencilDesc.FrontFace = defaultStencilOp; + depthStencilDesc.BackFace = defaultStencilOp; + + D3D12_GRAPHICS_PIPELINE_STATE_DESC dx12PipelineStateDescription = {}; + dx12PipelineStateDescription.RasterizerState = rasterDesc; + dx12PipelineStateDescription.BlendState = blendDesc; + dx12PipelineStateDescription.DepthStencilState = depthStencilDesc; + dx12PipelineStateDescription.DepthStencilState.DepthEnable = FALSE; + dx12PipelineStateDescription.SampleMask = UINT_MAX; + dx12PipelineStateDescription.PrimitiveTopologyType = D3D12_PRIMITIVE_TOPOLOGY_TYPE_TRIANGLE; + dx12PipelineStateDescription.SampleDesc = {1, 0}; + dx12PipelineStateDescription.NumRenderTargets = 1; + dx12PipelineStateDescription.RTVFormats[0] = fmt; + + dx12PipelineStateDescription.Flags = D3D12_PIPELINE_STATE_FLAG_NONE; + dx12PipelineStateDescription.pRootSignature = dx12RootSignature; + + s_debugPacingRootSignature = dx12RootSignature; + + { + dx12PipelineStateDescription.VS.pShaderBytecode = DebugPacingshaders::g_mainVS; + dx12PipelineStateDescription.VS.BytecodeLength = sizeof(DebugPacingshaders::g_mainVS); + dx12PipelineStateDescription.PS.pShaderBytecode = DebugPacingshaders::g_mainPS; + dx12PipelineStateDescription.PS.BytecodeLength = sizeof(DebugPacingshaders::g_mainPS); + + if (FAILED(dx12Device->CreateGraphicsPipelineState(&dx12PipelineStateDescription, + IID_PPV_ARGS(reinterpret_cast(&s_debugPacingPipeline))))) + return FFX_ERROR_BACKEND_API_ERROR; + } + + return FFX_OK; +} + +FfxErrorCodes verifyDebugPacingGpuResources(ID3D12Device* dx12Device, DXGI_FORMAT fmt) +{ + FFX_ASSERT(nullptr != dx12Device); + + if (nullptr == s_debugPacingPipeline) + { + FfxErrorCodes res = CreateDebugPacingPipeline(dx12Device, fmt); + if (res != FFX_OK) + return res; + } + + if (nullptr == s_debugPacingDescRingBuffer) + { + D3D12_DESCRIPTOR_HEAP_DESC descHeap = {}; + descHeap.NumDescriptors = s_debugPacingDescRingBufferSize; + descHeap.Type = D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV; + descHeap.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_SHADER_VISIBLE; + descHeap.NodeMask = 0; + s_debugPacingDescRingBufferBase = 0; + if(FAILED(dx12Device->CreateDescriptorHeap(&descHeap, IID_PPV_ARGS(&s_debugPacingDescRingBuffer)))) + return FFX_ERROR_BACKEND_API_ERROR; + } + + if (nullptr == s_debugPacingDescHeapRtvCpu) + { + D3D12_DESCRIPTOR_HEAP_DESC descHeap = {}; + descHeap.NumDescriptors = s_debugPacingDescHeapRtvSize; + descHeap.Type = D3D12_DESCRIPTOR_HEAP_TYPE_RTV; + descHeap.NodeMask = 0; + descHeap.Flags = D3D12_DESCRIPTOR_HEAP_FLAG_NONE; + if(FAILED(dx12Device->CreateDescriptorHeap(&descHeap, IID_PPV_ARGS(&s_debugPacingDescHeapRtvCpu)))) + return FFX_ERROR_BACKEND_API_ERROR; + } + + if (nullptr == s_debugPacingConstantBuffer[0]) + { + D3D12_RESOURCE_DESC constantBufferDesc = {}; + constantBufferDesc.Dimension = D3D12_RESOURCE_DIMENSION_BUFFER; + constantBufferDesc.Width = s_debugPacingConstantBufferSize; + constantBufferDesc.Height = 1; + constantBufferDesc.DepthOrArraySize = 1; + constantBufferDesc.MipLevels = 1; + constantBufferDesc.SampleDesc.Count = 1; + constantBufferDesc.Layout = D3D12_TEXTURE_LAYOUT_ROW_MAJOR; + constantBufferDesc.Format = DXGI_FORMAT_UNKNOWN; + + D3D12_HEAP_PROPERTIES heapProperties = {}; + heapProperties.Type = D3D12_HEAP_TYPE_UPLOAD; + + for (int i = 0; i < FFX_FRAME_INTERPOLATION_SWAP_CHAIN_MAX_BUFFER_COUNT; ++i) + { + if(FAILED(dx12Device->CreateCommittedResource( + &heapProperties, + D3D12_HEAP_FLAG_NONE, + &constantBufferDesc, + D3D12_RESOURCE_STATE_GENERIC_READ, + nullptr, + IID_PPV_ARGS(&s_debugPacingConstantBuffer[i])))) + { + return FFX_ERROR_BACKEND_API_ERROR; + } + } + + s_debugPacingFrameIndex = 0; + } + + return FFX_OK; +} + +void releasePacingDebugGpuResources() +{ + for (int i = 0; i < FFX_FRAME_INTERPOLATION_SWAP_CHAIN_MAX_BUFFER_COUNT; ++i) + { + SafeRelease(s_debugPacingConstantBuffer[i]); + } + s_debugPacingFrameIndex = 0; + + SafeRelease(s_debugPacingRootSignature); + SafeRelease(s_debugPacingPipeline); + + SafeRelease(s_debugPacingDescRingBuffer); + s_debugPacingDescRingBufferBase = 0; + + SafeRelease(s_debugPacingDescHeapRtvCpu); + s_debugPacingNextRtvDescriptor = 0; +} + +FFX_API FfxErrorCode ffxFrameInterpolationDebugPacing(const FfxPresentCallbackDescription* params) +{ + ID3D12Device* dx12Device = reinterpret_cast(params->device); + ID3D12Resource* pRtResource = (ID3D12Resource*)(params->currentBackBuffer.resource); + + FFX_ASSERT(nullptr != dx12Device); + FFX_ASSERT(nullptr != pRtResource); + + // blit backbuffer and composit UI using a VS/PS pass + D3D12_RESOURCE_DESC desc = pRtResource->GetDesc(); + + FfxErrorCode res = verifyDebugPacingGpuResources(dx12Device, desc.Format); + if (res != FFX_OK) + return res; + + ID3D12CommandList* pCommandList = reinterpret_cast(params->commandList); + ID3D12GraphicsCommandList* pCmdList = (ID3D12GraphicsCommandList*)pCommandList; + ID3D12PipelineState* dx12PipelineStateObject = nullptr; + + dx12PipelineStateObject = s_debugPacingPipeline; + + FFX_ASSERT(nullptr != pCommandList); + FFX_ASSERT(nullptr != pCmdList); + FFX_ASSERT(nullptr != dx12PipelineStateObject); + + D3D12_RESOURCE_BARRIER barrier = {}; + barrier.Type = D3D12_RESOURCE_BARRIER_TYPE_TRANSITION; + barrier.Transition.pResource = pRtResource; + barrier.Transition.StateBefore = D3D12_RESOURCE_STATE_PRESENT; + barrier.Transition.StateAfter = D3D12_RESOURCE_STATE_RENDER_TARGET; + if (barrier.Transition.StateBefore != barrier.Transition.StateAfter) + { + pCmdList->ResourceBarrier(1, &barrier); + } + + // set root signature + pCmdList->SetGraphicsRootSignature(s_debugPacingRootSignature); + + // set descriptor heap + ID3D12DescriptorHeap* dx12DescriptorHeap = reinterpret_cast(s_debugPacingDescRingBuffer); + pCmdList->SetDescriptorHeaps(1, &dx12DescriptorHeap); + + // set up the descriptor table + D3D12_GPU_DESCRIPTOR_HANDLE gpuView = dx12DescriptorHeap->GetGPUDescriptorHandleForHeapStart(); + gpuView.ptr += s_debugPacingDescRingBufferBase * dx12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + D3D12_CPU_DESCRIPTOR_HANDLE cpuView = dx12DescriptorHeap->GetCPUDescriptorHandleForHeapStart(); + cpuView.ptr += s_debugPacingDescRingBufferBase * dx12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_CBV_SRV_UAV); + + UINT8* gpuData; + s_debugPacingConstantBuffer[s_debugPacingFrameIndex]->Map(0, nullptr, reinterpret_cast(&gpuData)); + memcpy(gpuData, &s_debugPacingFrameIndex, sizeof(s_debugPacingFrameIndex)); + s_debugPacingConstantBuffer[s_debugPacingFrameIndex]->Unmap(0, nullptr); + + D3D12_CONSTANT_BUFFER_VIEW_DESC dx12CbvDescription = {}; + dx12CbvDescription.BufferLocation = s_debugPacingConstantBuffer[s_debugPacingFrameIndex]->GetGPUVirtualAddress(); + dx12CbvDescription.SizeInBytes = s_debugPacingConstantBufferSize; + dx12Device->CreateConstantBufferView(&dx12CbvDescription, cpuView); + + s_debugPacingFrameIndex = (s_debugPacingFrameIndex + 1) % FFX_FRAME_INTERPOLATION_SWAP_CHAIN_MAX_BUFFER_COUNT; + + s_debugPacingDescRingBufferBase = (s_debugPacingDescRingBufferBase + 1) % s_debugPacingDescRingBufferSize; + pCmdList->SetGraphicsRootDescriptorTable(0, gpuView); + + D3D12_RENDER_TARGET_VIEW_DESC colorDesc = {}; + colorDesc.Format = desc.Format; + colorDesc.ViewDimension = D3D12_RTV_DIMENSION_TEXTURE2D; + colorDesc.Texture2D.MipSlice = 0; + colorDesc.Texture2D.PlaneSlice = 0; + + D3D12_CPU_DESCRIPTOR_HANDLE backbufferRTV = s_debugPacingDescHeapRtvCpu->GetCPUDescriptorHandleForHeapStart(); + backbufferRTV.ptr += s_debugPacingNextRtvDescriptor * dx12Device->GetDescriptorHandleIncrementSize(D3D12_DESCRIPTOR_HEAP_TYPE_RTV); + s_debugPacingNextRtvDescriptor = (s_debugPacingNextRtvDescriptor + 1) % s_debugPacingDescHeapRtvSize; + dx12Device->CreateRenderTargetView(pRtResource, &colorDesc, backbufferRTV); + + D3D12_RESOURCE_DESC backBufferDesc = pRtResource->GetDesc(); + D3D12_VIEWPORT vpd = {0.0f, 0.0f, 32, static_cast(backBufferDesc.Height), 0.0f, 1.0f}; + D3D12_RECT srd = {0, 0, (LONG)backBufferDesc.Width, (LONG)backBufferDesc.Height}; + + pCmdList->OMSetRenderTargets(1, &backbufferRTV, true, NULL); + pCmdList->IASetPrimitiveTopology(D3D_PRIMITIVE_TOPOLOGY_TRIANGLELIST); + pCmdList->SetPipelineState(dx12PipelineStateObject); + pCmdList->RSSetViewports(1, &vpd); + pCmdList->RSSetScissorRects(1, &srd); + pCmdList->DrawInstanced(3, 1, 0, 0); + + D3D12_RESOURCE_STATES tmpStateBefore = barrier.Transition.StateBefore; + barrier.Transition.StateBefore = barrier.Transition.StateAfter; + barrier.Transition.StateAfter = tmpStateBefore; + + pCmdList->ResourceBarrier(1, &barrier); + + return FFX_OK; +} diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDX12_DebugPacing.h b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDX12_DebugPacing.h new file mode 100644 index 00000000..45c12208 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDX12_DebugPacing.h @@ -0,0 +1,30 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +#pragma once + +#include +void releasePacingDebugGpuResources(); + +D3D12_RESOURCE_STATES ffxGetDX12StateFromResourceState(FfxResourceStates state); + +FFX_API FfxErrorCode ffxFrameInterpolationDebugPacing(const FfxPresentCallbackDescription* params); diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDebugPacing.hlsl b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDebugPacing.hlsl new file mode 100644 index 00000000..52d3eeaf --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDebugPacing.hlsl @@ -0,0 +1,50 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. + +cbuffer input : register(b0) +{ + uint frameIndex; +}; + +float4 mainVS(uint vertexId : SV_VertexID) : SV_POSITION +{ + return float4((int) (vertexId & 1) * 4 - 1, (int) (vertexId & 2) * (-2) + 1, 0.5, 1); +} + +float4 mainPS(float4 vPosition: SV_POSITION) : SV_Target +{ + float a = frameIndex & 1; + float b = (~frameIndex) & 1; + + if (vPosition.x < 16.0f) + { + // Alternate between magenta and green + return float4(b, a, b, 1.0f); + } + else if (vPosition.x < 32.0f) + { + // Alternate between black and white + return float4(a, a, a, 1); + } + + return float4(0.0f, 0.0f, 0.0f, 0.0f); +} diff --git a/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDebugPacingPS.h b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDebugPacingPS.h new file mode 100644 index 00000000..90db5da6 --- /dev/null +++ b/Kits/AMDTK/fidelityfx/src/backends/dx12/FrameInterpolationSwapchain/FrameInterpolationSwapchainDebugPacingPS.h @@ -0,0 +1,459 @@ +// This file is part of the FidelityFX SDK. +// +// Copyright (C) 2024 Advanced Micro Devices, Inc. +// +// 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. +#if 0 +; +; Input signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; SV_Position 0 xyzw 0 POS float x +; +; +; Output signature: +; +; Name Index Mask Register SysValue Format Used +; -------------------- ----- ------ -------- -------- ------- ------ +; SV_Target 0 xyzw 0 TARGET float xyzw +; +; shader hash: 19decc2ff08fd3cbd2edcf26536e91df +; +; Pipeline Runtime Information: +; +; Pixel Shader +; DepthOutput=0 +; SampleFrequency=0 +; +; +; Input signature: +; +; Name Index InterpMode DynIdx +; -------------------- ----- ---------------------- ------ +; SV_Position 0 noperspective +; +; Output signature: +; +; Name Index InterpMode DynIdx +; -------------------- ----- ---------------------- ------ +; SV_Target 0 +; +; Buffer Definitions: +; +; cbuffer input +; { +; +; struct input +; { +; +; uint frameIndex; ; Offset: 0 +; +; } input; ; Offset: 0 Size: 4 +; +; } +; +; +; Resource Bindings: +; +; Name Type Format Dim ID HLSL Bind Count +; ------------------------------ ---------- ------- ----------- ------- -------------- ------ +; input cbuffer NA NA CB0 cb0 1 +; +; +; ViewId state: +; +; Number of inputs: 4, outputs: 4 +; Outputs dependent on ViewId: { } +; Inputs contributing to computation of Outputs: +; output 0 depends on inputs: { 0 } +; output 1 depends on inputs: { 0 } +; output 2 depends on inputs: { 0 } +; output 3 depends on inputs: { 0 } +; +target datalayout = "e-m:e-p:32:32-i1:32-i8:32-i16:32-i32:32-i64:64-f16:32-f32:32-f64:64-n8:16:32:64" +target triple = "dxil-ms-dx" + +%dx.types.Handle = type { i8* } +%dx.types.CBufRet.i32 = type { i32, i32, i32, i32 } +%input = type { i32 } + +define void @mainPS() { + %1 = call %dx.types.Handle @dx.op.createHandle(i32 57, i8 2, i32 0, i32 0, i1 false) ; CreateHandle(resourceClass,rangeId,index,nonUniformIndex) + %2 = call float @dx.op.loadInput.f32(i32 4, i32 0, i32 0, i8 0, i32 undef) ; LoadInput(inputSigId,rowIndex,colIndex,gsVertexAxis) + %3 = call %dx.types.CBufRet.i32 @dx.op.cbufferLoadLegacy.i32(i32 59, %dx.types.Handle %1, i32 0) ; CBufferLoadLegacy(handle,regIndex) + %4 = extractvalue %dx.types.CBufRet.i32 %3, 0 + %5 = and i32 %4, 1 + %6 = uitofp i32 %5 to float + %7 = xor i32 %5, 1 + %8 = uitofp i32 %7 to float + %9 = fcmp fast olt float %2, 1.600000e+01 + br i1 %9, label %13, label %10 + +;