├── .gitattributes ├── .gitignore ├── .gitlab-ci.yml ├── .gitmodules ├── CMakeLists.txt ├── build ├── .gitignore └── GenerateSolutions.bat ├── common.cmake ├── license.txt ├── readme.md ├── screenshot.png └── src ├── Common ├── CMakeLists.txt └── GLTFSample.json └── DX12 ├── CMakeLists.txt ├── GLTFSample.cpp ├── GLTFSample.h ├── Renderer.cpp ├── Renderer.h ├── UI.cpp ├── UI.h ├── dpiawarescaling.manifest ├── stdafx.cpp └── stdafx.h /.gitattributes: -------------------------------------------------------------------------------- 1 | libs/Cauldron/libs/DXC/bin/dxcompiler.dll filter=lfs diff=lfs merge=lfs -text 2 | libs/Cauldron/libs/DXC/bin/dxc.exe filter=lfs diff=lfs merge=lfs -text 3 | libs/Cauldron/libs/DXC/bin/dxil.dll filter=lfs diff=lfs merge=lfs -text 4 | libs/Cauldron/libs/DXC/bin/x64/dxcompiler.dll filter=lfs diff=lfs merge=lfs -text 5 | libs/Cauldron/libs/DXC/bin/x64/dxc.exe filter=lfs diff=lfs merge=lfs -text 6 | libs/Cauldron/libs/DXC/bin/x64/dxil.dll filter=lfs diff=lfs merge=lfs -text 7 | libs/Cauldron/libs/DXCwg/*.exe filter=lfs diff=lfs merge=lfs -text 8 | libs/Cauldron/libs/DXCwg/*.dll filter=lfs diff=lfs merge=lfs -text 9 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Aa][Rr][Mm]/ 27 | [Aa][Rr][Mm]64/ 28 | bld/ 29 | [Bb]in/ 30 | [Oo]bj/ 31 | [Ll]og/ 32 | 33 | # CMake generated files 34 | CMakeCache.txt 35 | CMakeFiles/ 36 | cmake_install.cmake 37 | 38 | # Visual Studio 2015/2017 cache/options directory 39 | .vs/ 40 | # Uncomment if you have tasks that create the project's static files in wwwroot 41 | #wwwroot/ 42 | 43 | # Visual Studio 2017 auto generated files 44 | Generated\ Files/ 45 | 46 | # Visual Studio 2019 Open Folder 47 | out/ 48 | CMakeSettings.json 49 | 50 | # MSTest test Results 51 | [Tt]est[Rr]esult*/ 52 | [Bb]uild[Ll]og.* 53 | 54 | # NUnit 55 | *.VisualState.xml 56 | TestResult.xml 57 | nunit-*.xml 58 | 59 | # Build Results of an ATL Project 60 | [Dd]ebugPS/ 61 | [Rr]eleasePS/ 62 | dlldata.c 63 | 64 | # Benchmark Results 65 | BenchmarkDotNet.Artifacts/ 66 | 67 | # .NET Core 68 | project.lock.json 69 | project.fragment.lock.json 70 | artifacts/ 71 | 72 | # StyleCop 73 | StyleCopReport.xml 74 | 75 | # Files built by Visual Studio 76 | *_i.c 77 | *_p.c 78 | *_h.h 79 | *.ilk 80 | *.meta 81 | *.obj 82 | *.iobj 83 | *.pch 84 | *.pdb 85 | *.ipdb 86 | *.pgc 87 | *.pgd 88 | *.rsp 89 | *.sbr 90 | *.tlb 91 | *.tli 92 | *.tlh 93 | *.tmp 94 | *.tmp_proj 95 | *_wpftmp.csproj 96 | *.log 97 | *.vspscc 98 | *.vssscc 99 | .builds 100 | *.pidb 101 | *.svclog 102 | *.scc 103 | 104 | # Chutzpah Test files 105 | _Chutzpah* 106 | 107 | # Visual C++ cache files 108 | ipch/ 109 | *.aps 110 | *.ncb 111 | *.opendb 112 | *.opensdf 113 | *.sdf 114 | *.cachefile 115 | *.VC.db 116 | *.VC.VC.opendb 117 | 118 | # Visual Studio profiler 119 | *.psess 120 | *.vsp 121 | *.vspx 122 | *.sap 123 | 124 | # Visual Studio Trace Files 125 | *.e2e 126 | 127 | # TFS 2012 Local Workspace 128 | $tf/ 129 | 130 | # Guidance Automation Toolkit 131 | *.gpState 132 | 133 | # ReSharper is a .NET coding add-in 134 | _ReSharper*/ 135 | *.[Rr]e[Ss]harper 136 | *.DotSettings.user 137 | 138 | # JustCode is a .NET coding add-in 139 | .JustCode 140 | 141 | # TeamCity is a build add-in 142 | _TeamCity* 143 | 144 | # DotCover is a Code Coverage Tool 145 | *.dotCover 146 | 147 | # AxoCover is a Code Coverage Tool 148 | .axoCover/* 149 | !.axoCover/settings.json 150 | 151 | # Visual Studio code coverage results 152 | *.coverage 153 | *.coveragexml 154 | 155 | # NCrunch 156 | _NCrunch_* 157 | .*crunch*.local.xml 158 | nCrunchTemp_* 159 | 160 | # MightyMoose 161 | *.mm.* 162 | AutoTest.Net/ 163 | 164 | # Web workbench (sass) 165 | .sass-cache/ 166 | 167 | # Installshield output folder 168 | [Ee]xpress/ 169 | 170 | # DocProject is a documentation generator add-in 171 | DocProject/buildhelp/ 172 | DocProject/Help/*.HxT 173 | DocProject/Help/*.HxC 174 | DocProject/Help/*.hhc 175 | DocProject/Help/*.hhk 176 | DocProject/Help/*.hhp 177 | DocProject/Help/Html2 178 | DocProject/Help/html 179 | 180 | # Click-Once directory 181 | publish/ 182 | 183 | # Publish Web Output 184 | *.[Pp]ublish.xml 185 | *.azurePubxml 186 | # Note: Comment the next line if you want to checkin your web deploy settings, 187 | # but database connection strings (with potential passwords) will be unencrypted 188 | *.pubxml 189 | *.publishproj 190 | 191 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 192 | # checkin your Azure Web App publish settings, but sensitive information contained 193 | # in these scripts will be unencrypted 194 | PublishScripts/ 195 | 196 | # NuGet Packages 197 | *.nupkg 198 | # NuGet Symbol Packages 199 | *.snupkg 200 | # The packages folder can be ignored because of Package Restore 201 | **/[Pp]ackages/* 202 | # except build/, which is used as an MSBuild target. 203 | !**/[Pp]ackages/build/ 204 | # Uncomment if necessary however generally it will be regenerated when needed 205 | #!**/[Pp]ackages/repositories.config 206 | # NuGet v3's project.json files produces more ignorable files 207 | *.nuget.props 208 | *.nuget.targets 209 | 210 | # Microsoft Azure Build Output 211 | csx/ 212 | *.build.csdef 213 | 214 | # Microsoft Azure Emulator 215 | ecf/ 216 | rcf/ 217 | 218 | # Windows Store app package directories and files 219 | AppPackages/ 220 | BundleArtifacts/ 221 | Package.StoreAssociation.xml 222 | _pkginfo.txt 223 | *.appx 224 | *.appxbundle 225 | *.appxupload 226 | 227 | # Visual Studio cache files 228 | # files ending in .cache can be ignored 229 | *.[Cc]ache 230 | # but keep track of directories ending in .cache 231 | !?*.[Cc]ache/ 232 | 233 | # Others 234 | ClientBin/ 235 | ~$* 236 | *~ 237 | *.dbmdl 238 | *.dbproj.schemaview 239 | *.jfm 240 | *.pfx 241 | *.publishsettings 242 | orleans.codegen.cs 243 | 244 | # Including strong name files can present a security risk 245 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 246 | #*.snk 247 | 248 | # Since there are multiple workflows, uncomment next line to ignore bower_components 249 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 250 | #bower_components/ 251 | 252 | # RIA/Silverlight projects 253 | Generated_Code/ 254 | 255 | # Backup & report files from converting an old project file 256 | # to a newer Visual Studio version. Backup files are not needed, 257 | # because we have git ;-) 258 | _UpgradeReport_Files/ 259 | Backup*/ 260 | UpgradeLog*.XML 261 | UpgradeLog*.htm 262 | ServiceFabricBackup/ 263 | *.rptproj.bak 264 | 265 | # SQL Server files 266 | *.mdf 267 | *.ldf 268 | *.ndf 269 | 270 | # Business Intelligence projects 271 | *.rdl.data 272 | *.bim.layout 273 | *.bim_*.settings 274 | *.rptproj.rsuser 275 | *- [Bb]ackup.rdl 276 | *- [Bb]ackup ([0-9]).rdl 277 | *- [Bb]ackup ([0-9][0-9]).rdl 278 | 279 | # Microsoft Fakes 280 | FakesAssemblies/ 281 | 282 | # GhostDoc plugin setting file 283 | *.GhostDoc.xml 284 | 285 | # Node.js Tools for Visual Studio 286 | .ntvs_analysis.dat 287 | node_modules/ 288 | 289 | # Visual Studio 6 build log 290 | *.plg 291 | 292 | # Visual Studio 6 workspace options file 293 | *.opt 294 | 295 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 296 | *.vbw 297 | 298 | # Visual Studio LightSwitch build output 299 | **/*.HTMLClient/GeneratedArtifacts 300 | **/*.DesktopClient/GeneratedArtifacts 301 | **/*.DesktopClient/ModelManifest.xml 302 | **/*.Server/GeneratedArtifacts 303 | **/*.Server/ModelManifest.xml 304 | _Pvt_Extensions 305 | 306 | # Paket dependency manager 307 | .paket/paket.exe 308 | paket-files/ 309 | 310 | # FAKE - F# Make 311 | .fake/ 312 | 313 | # CodeRush personal settings 314 | .cr/personal 315 | 316 | # Python Tools for Visual Studio (PTVS) 317 | __pycache__/ 318 | *.pyc 319 | 320 | # Cake - Uncomment if you are using it 321 | # tools/** 322 | # !tools/packages.config 323 | 324 | # Tabs Studio 325 | *.tss 326 | 327 | # Telerik's JustMock configuration file 328 | *.jmconfig 329 | 330 | # BizTalk build output 331 | *.btp.cs 332 | *.btm.cs 333 | *.odx.cs 334 | *.xsd.cs 335 | 336 | # OpenCover UI analysis results 337 | OpenCover/ 338 | 339 | # Azure Stream Analytics local run output 340 | ASALocalRun/ 341 | 342 | # MSBuild Binary and Structured Log 343 | *.binlog 344 | 345 | # NVidia Nsight GPU debugger configuration file 346 | *.nvuser 347 | 348 | # MFractors (Xamarin productivity tool) working folder 349 | .mfractor/ 350 | 351 | # Local History for Visual Studio 352 | .localhistory/ 353 | 354 | # BeatPulse healthcheck temp database 355 | healthchecksdb 356 | 357 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 358 | MigrationBackup/ 359 | /libs/Cauldron/libs/DXCwg/*.exe 360 | /libs/Cauldron/libs/DXCwg/*.dll 361 | /libs/Cauldron/libs/DXCwg/LICENSE*.txt 362 | /libs/Cauldron/libs/DXCwg/LICENCE*.txt 363 | -------------------------------------------------------------------------------- /.gitlab-ci.yml: -------------------------------------------------------------------------------- 1 | variables: 2 | SampleName: GLTFSample 3 | CMakeConfig: -G "Visual Studio 16 2019" -A x64 4 | GIT_SUBMODULE_STRATEGY: normal 5 | 6 | stages: 7 | - build 8 | - deploy 9 | 10 | build_dx12: 11 | tags: 12 | - windows 13 | - amd64 14 | stage: build 15 | artifacts: 16 | paths: 17 | - bin/ 18 | script: 19 | - 'cmake -S . -B build/DX12 -DGFX_API=DX12 %CMakeConfig%' 20 | - 'cmake --build build/DX12 --config Release' 21 | 22 | package_sample: 23 | tags: 24 | - windows 25 | - amd64 26 | stage: deploy 27 | dependencies: 28 | - build_dx12 29 | script: 30 | - echo cd .\bin\ > %SampleName%_DX12.bat 31 | - echo start %SampleName%_DX12.exe >> %SampleName%_DX12.bat 32 | artifacts: 33 | name: "$SampleName-$CI_COMMIT_SHORT_SHA" 34 | paths: 35 | - "bin/" 36 | - "license.txt" 37 | - "media/cauldron-media/" 38 | - "${SampleName_DX12}.bat" 39 | - "readme.md" 40 | - "screenshot.png" 41 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "media/Cauldron-Media"] 2 | path = media/Cauldron-Media 3 | url = https://github.com/GPUOpen-LibrariesAndSDKs/Cauldron-Media.git 4 | [submodule "libs/Cauldron"] 5 | path = libs/Cauldron 6 | url = ../Cauldron.git 7 | branch = WorkGraphComputeRasterizer -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | set(CMAKE_CXX_STANDARD 20) 3 | 4 | option (GFX_API_DX12 "Build with DX12" ON) 5 | option (GFX_API_WG "Build with Work graphs" ON) 6 | 7 | if(NOT DEFINED GFX_API) 8 | project (GLTFSample) 9 | else() 10 | project (GLTFSample_${GFX_API}) 11 | 12 | set_property(DIRECTORY ${CMAKE_PROJECT_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) 13 | 14 | if(GFX_API STREQUAL DX12) 15 | set(GFX_API_DX12 ON) 16 | else() 17 | message(STATUS "----------------------------------------------------------------------------------------") 18 | message(STATUS "") 19 | message(STATUS "** Almost there!!") 20 | message(STATUS "") 21 | message(STATUS " This framework supports DX12 only, you need to invoke cmake in one of these ways:") 22 | message(STATUS "") 23 | message(STATUS " Examples:") 24 | message(STATUS " Generate selected one:") 25 | message(STATUS " cmake -DGFX_API=DX12") 26 | message(STATUS " Generate with switches (Default is ON):") 27 | message(STATUS " cmake [-DGFX_API_DX12=ON|OFF]") 28 | message(STATUS "") 29 | message(STATUS "----------------------------------------------------------------------------------------") 30 | message(FATAL_ERROR "") 31 | endif() 32 | endif() 33 | 34 | # Check MSVC toolset version, Visual Studio 2019 required 35 | if(MSVC_TOOLSET_VERSION VERSION_LESS 142) 36 | message(FATAL_ERROR "Cannot find MSVC toolset version 142 or greater. Please make sure Visual Studio 2019 or newer installed") 37 | endif() 38 | 39 | # ouput exe to bin directory 40 | SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin) 41 | foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) 42 | string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) 43 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_HOME_DIRECTORY}/bin ) 44 | endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) 45 | 46 | add_compile_options(/MP) 47 | 48 | if(GFX_API_WG) 49 | add_definitions(-DENABLE_WORKGRAPHS) 50 | endif() 51 | 52 | # reference libs used by both backends 53 | add_subdirectory(libs/cauldron) 54 | add_subdirectory(src/Common) 55 | 56 | # application icon 57 | set(icon_src 58 | ${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/GPUOpenChip.ico 59 | ${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/resource.h 60 | ${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/Cauldron_Common.rc 61 | ) 62 | 63 | if(GFX_API_DX12) 64 | add_subdirectory(src/DX12) 65 | endif() 66 | 67 | set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/Cauldron_Common.rc PROPERTIES VS_TOOL_OVERRIDE "Resource compiler") 68 | set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/GPUOpenChip.ico PROPERTIES VS_TOOL_OVERRIDE "Image") -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | DX12/ -------------------------------------------------------------------------------- /build/GenerateSolutions.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | setlocal enabledelayedexpansion 3 | 4 | echo Checking pre-requisites... 5 | 6 | :: Check if CMake is installed 7 | cmake --version > nul 2>&1 8 | if %errorlevel% NEQ 0 ( 9 | echo Cannot find path to cmake. Is CMake installed? Exiting... 10 | exit /b -1 11 | ) else ( 12 | echo CMake - Ready. 13 | ) 14 | 15 | :: Check if submodule is initialized (first time) to avoid CMake file not found errors 16 | if not exist ..\libs\cauldron\common.cmake ( 17 | echo File: common.cmake doesn't exist in '.\libs\cauldron\' - Initializing submodule... 18 | 19 | :: attempt to initialize submodule 20 | cd .. 21 | echo. 22 | git submodule sync --recursive 23 | git submodule update --init --recursive 24 | cd build 25 | 26 | 27 | :: check if submodule initialized properly 28 | if not exist ..\libs\cauldron\common.cmake ( 29 | echo. 30 | echo '..\libs\cauldron\common.cmake is still not there.' 31 | echo Could not initialize submodule. Make sure all the submodules are initialized and updated. 32 | echo Exiting... 33 | echo. 34 | exit /b -1 35 | ) else ( 36 | echo Cauldron - Ready. 37 | ) 38 | ) else ( 39 | echo Cauldron - Ready. 40 | ) 41 | 42 | 43 | :: Call CMake 44 | mkdir DX12 45 | cd DX12 46 | cmake -A x64 ..\.. -DGFX_API=DX12 -DCMAKE_CXX_STANDARD=23 47 | cd .. 48 | -------------------------------------------------------------------------------- /common.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # enables multithreading compilation 3 | # 4 | 5 | add_compile_options(/MP) 6 | 7 | # 8 | # includes cauldron's helper cmakes 9 | # 10 | include(${CMAKE_CURRENT_SOURCE_DIR}/../../libs/cauldron/common.cmake) 11 | 12 | # 13 | # Add manifest so the app uses the right DPI settings 14 | # 15 | function(addManifest PROJECT_NAME) 16 | IF (MSVC) 17 | IF (CMAKE_MAJOR_VERSION LESS 3) 18 | MESSAGE(WARNING "CMake version 3.0 or newer is required use build variable TARGET_FILE") 19 | ELSE() 20 | ADD_CUSTOM_COMMAND( 21 | TARGET ${PROJECT_NAME} 22 | POST_BUILD 23 | COMMAND "mt.exe" -manifest \"${CMAKE_CURRENT_SOURCE_DIR}\\dpiawarescaling.manifest\" -inputresource:\"$\"\;\#1 -outputresource:\"$\"\;\#1 24 | COMMENT "Adding display aware manifest..." 25 | ) 26 | ENDIF() 27 | ENDIF(MSVC) 28 | endfunction() -------------------------------------------------------------------------------- /license.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2021 Advanced Micro Devices, Inc. All rights reserved. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # Work Graphs Compute Rasterizer Sample 2 | 3 | A compute rasterizer sample implemented with Work Graphs running inside the [Cauldron framework](https://github.com/GPUOpen-LibrariesAndSDKs/Cauldron). 4 | 5 | ![Screenshot](screenshot.png) 6 | 7 | # Build Instructions 8 | 9 | ### Prerequisites 10 | 11 | To build the Work Graphs Compute Rasterizer Sample, you must first install the following tools: 12 | 13 | - [CMake 3.16](https://cmake.org/download/) 14 | - [Visual Studio 2022](https://visualstudio.microsoft.com/downloads/) 15 | - [Windows 10 SDK 10.0.18362.0](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) 16 | 17 | ### Getting up and running 18 | 19 | Follow the next steps: 20 | 21 | 1) Clone the repo with its submodules: 22 | ``` 23 | > git clone https://github.com/GPUOpen-LibrariesAndSDKs/WorkGraphComputeRasterizer --recurse-submodules 24 | ``` 25 | 26 | 2) Generate the solutions: 27 | ``` 28 | > cd WorkGraphComputeRasterizer\build 29 | > GenerateSolutions.bat 30 | ``` 31 | 32 | 3) Open the solution in the DX12 directory, compile and run. VK isn't supported. 33 | 34 | 4) The define `ENABLE_WORKGRAPHS` enables Work graphs. It's enabled by default. It can be disabled if [PIX](https://devblogs.microsoft.com/pix/introduction/), [RenderDoc](https://renderdoc.org) or another tool without Work graphs support is used to debug. Use CMake to disable the feature: 35 | ``` 36 | > cmake -DGFX_API_WG=OFF 37 | ``` 38 | 39 | 5) The media samples from Cauldron may change and not all scenes may load, you can adjust scenes in [src\Common\GLTFSample.json](src\Common\GLTFSample.json) 40 | 41 | 6) You can request precise profiling data through commandline by passing json as arguments: 42 | ``` 43 | > cd WorkGraphComputeRasterizer\bin 44 | > GLTFSample_DX12.exe { "algorithm" : 4, "bins" : 13, "threadlaunch" : true, ^ 45 | "stablePowerState" : true, "profile" : true, "ProfileSettings": { "filter" : ^ 46 | "Rasterize", "exitWhenTimeEnds": true, "resultsFilename": "Sponza.csv", ^ 47 | "warmUpFrames": 50, "durationFrames": 20 } } 48 | ``` 49 | 50 | These are the custom parameters for the rasterizer, the many other options can be looked up in the Cauldron docs: 51 | 52 | `algorithm`: 53 | > 0 - monolithic compute rasterizer, called once per object 54 | > 1 - monolithic compute rasterizer, all objects are consumed by one ExecuteIndirect 55 | > 2 - multi-pass compute rasterizer, all objects are consumed by a pipeline of three ExecuteIndirect 56 | > 3 - workgraph rasterizer, called once per object 57 | > 4 - workgraph rasterizer, called once in total with all object batched 58 | > 5 - workgraph rasterizer, all objects are consumed by an initial Broadcaster node 59 | 60 | `bins`: 61 | > 1 to 15: number of buckets/bins to group triangles by, 2^(bin-1) = area 62 | 63 | `threadlaunch`: 64 | > false/true: use a thread-launch or coalesce node for triangle rasterization 65 | 66 | `profile`: 67 | > false/true: enables automatic profiling and generation of a csv file 68 | 69 | `filter`: 70 | > label: the label of the pass to collect timestamps for, if empty all passes are included in the csv 71 | 72 | `resultsFilename`: 73 | > filename: the name of the csv in the current directory 74 | 75 | `warmUpFrames`: 76 | > 0 to inf: how many frames to wait for initialization to settle 77 | 78 | `durationFrames`: 79 | > 0 to inf: how many frames to include in the csv 80 | 81 | The values in the resulting csv are raw gpu ticks without any conversion. 82 | 83 | 7) The algorithm and some results are presented in this GPUOpen blog entry: 84 | 85 | https://gpuopen.com/learn/work_graphs_learning_sample/ 86 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-LibrariesAndSDKs/WorkGraphComputeRasterizer/a88088d438403dbc80ef27f3027ffd5bcbfda627/screenshot.png -------------------------------------------------------------------------------- /src/Common/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include(${CMAKE_CURRENT_SOURCE_DIR}/../../common.cmake) 2 | 3 | add_library(GLTFSample_Common INTERFACE) 4 | 5 | set(config 6 | ${CMAKE_CURRENT_SOURCE_DIR}/../Common/GLTFSample.json 7 | ) 8 | 9 | copyTargetCommand("${config}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} copied_common_config) 10 | add_dependencies(GLTFSample_Common copied_common_config) 11 | -------------------------------------------------------------------------------- /src/Common/GLTFSample.json: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "CpuValidationLayerEnabled": false, 4 | "GpuValidationLayerEnabled": false, 5 | "presentationMode": 0, 6 | "width": 1920, 7 | "height": 1080, 8 | "activeScene": 0, 9 | "benchmark": false, 10 | "profile": false, 11 | "vsync": false, 12 | "stablePowerState": true, 13 | "FreesyncHDROptionEnabled": false, 14 | "fontsize": 13 15 | }, 16 | "scenes": [ 17 | { 18 | "name": "Sponza", 19 | "directory": "..\\media\\cauldron-media\\sponza\\GLTF\\", 20 | "filename": "sponza.gltf", 21 | "TAA": false, 22 | "toneMapper": 0, 23 | "iblFactor": 0.36, 24 | "emmisiveFactor": 1, 25 | "intensity": 10, 26 | "exposure": 1, 27 | "activeCamera": -1, 28 | "camera": { 29 | "defaultFrom": [ 5.13694048, 1.89175785, -1.40289795 ], 30 | "defaultTo": [ 0.703276634, 1.02280307, 0.218072295 ] 31 | }, 32 | "ProfileSettings": { 33 | "exitWhenTimeEnds": true, 34 | "resultsFilename": "Sponza.csv", 35 | "warmUpFrames": 200, 36 | "durationFrames": 200 37 | }, 38 | "BenchmarkSettings": { 39 | "timeStep": 1, 40 | "timeStart": 0, 41 | "timeEnd": 10000, 42 | "exitWhenTimeEnds": true, 43 | "resultsFilename": "Sponza.csv", 44 | "warmUpFrames": 200, 45 | "sequence": { 46 | "timeStart": 0, 47 | "timeEnd": 2000, 48 | "keyFrames": [ 49 | { 50 | "time": 0, 51 | "from": [ 5.13694048, 1.89175785, -1.40289795 ], 52 | "to": [ 0.703276634, 1.02280307, 0.218072295 ], 53 | "screenShotName": "camera1.jpg" 54 | }, 55 | { 56 | "time": 1000, 57 | "from": [ -5.13694048, 1.89175785, -1.40289795 ], 58 | "to": [ 0.703276634, 1.02280307, 0.218072295 ], 59 | "screenShotName": "camera2.jpg" 60 | } 61 | ] 62 | } 63 | } 64 | }, 65 | { 66 | "name": "Sponza (much more complex)", 67 | "directory": "..\\media\\cauldron-media\\sponza-new\\", 68 | "filename": "scene.gltf", 69 | "TAA": false, 70 | "toneMapper": 0, 71 | "iblFactor": 0.36, 72 | "emmisiveFactor": 1, 73 | "intensity": 10, 74 | "exposure": 1, 75 | "activeCamera": -1, 76 | "camera": { 77 | "defaultFrom": [ 5.13694048, 1.89175785, -1.40289795 ], 78 | "defaultTo": [ 0.703276634, 1.02280307, 0.218072295 ] 79 | } 80 | }, 81 | { 82 | "name": "SanMiguel (local, need to add yourself)", 83 | "directory": "..\\media\\cauldron-media\\SanMiguel\\", 84 | "filename": "SanMiguel.gltf", 85 | "TAA": false, 86 | "toneMapper": 0, 87 | "iblFactor": 0.36, 88 | "emmisiveFactor": 1, 89 | "intensity": 10, 90 | "exposure": 1, 91 | "activeCamera": -1, 92 | "camera": { 93 | "defaultFrom": [ 5.13694048, 1.89175785, -1.40289795 ], 94 | "defaultTo": [ 0.703276634, 1.02280307, 0.218072295 ] 95 | } 96 | }, 97 | { 98 | "name": "Buggy (local, need to add yourself)", 99 | "directory": "..\\media\\cauldron-media\\Buggy\\glTF\\", 100 | "filename": "Buggy.gltf", 101 | "TAA": false, 102 | "toneMapper": 0, 103 | "iblFactor": 2, 104 | "emmisiveFactor": 1, 105 | "intensity": 50, 106 | "exposure": 1, 107 | "camera": { 108 | "defaultFrom": [ 150, 150, 150 ], 109 | "defaultTo": [ 0, 0, 0 ] 110 | } 111 | }, 112 | { 113 | "name": "BusterDrone (local, need to add yourself)", 114 | "directory": "..\\media\\cauldron-media\\buster_drone\\", 115 | "filename": "busterDrone.gltf", 116 | "TAA": false, 117 | "toneMapper": 0, 118 | "iblFactor": 1, 119 | "emmisiveFactor": 30, 120 | "intensity": 50, 121 | "exposure": 1, 122 | "camera": { 123 | "defaultFrom": [ 0, 0, 3.5 ], 124 | "defaultTo": [ 0, 0, 0 ] 125 | } 126 | }, 127 | { 128 | "name": "BoomBox", 129 | "directory": "..\\media\\cauldron-media\\BoomBox\\GLTF\\", 130 | "filename": "BoomBox.gltf", 131 | "TAA": false, 132 | "toneMapper": 0, 133 | "iblFactor": 1, 134 | "emmisiveFactor": 1, 135 | "intensity": 50, 136 | "exposure": 1, 137 | "camera": { 138 | "defaultFrom": [ 0, 0, 3.5 ], 139 | "defaultTo": [ 0, 0, 0 ] 140 | } 141 | }, 142 | { 143 | "name": "Box", 144 | "directory": "..\\media\\cauldron-media\\Box\\GLTF\\", 145 | "filename": "Box.gltf", 146 | "TAA": false, 147 | "toneMapper": 0, 148 | "iblFactor": 1, 149 | "emmisiveFactor": 1, 150 | "intensity": 50, 151 | "exposure": 1, 152 | "camera": { 153 | "defaultFrom": [ 0, 0, 3.5 ], 154 | "defaultTo": [ 0, 0, 0 ] 155 | } 156 | }, 157 | { 158 | "name": "SciFiHelmet", 159 | "directory": "..\\media\\cauldron-media\\SciFiHelmet\\GLTF\\", 160 | "filename": "SciFiHelmet.gltf", 161 | "TAA": false, 162 | "toneMapper": 0, 163 | "iblFactor": 1, 164 | "emmisiveFactor": 1, 165 | "intensity": 50, 166 | "exposure": 1, 167 | "camera": { 168 | "defaultFrom": [ 0, 0, 3.5 ], 169 | "defaultTo": [ 0, 0, 0 ] 170 | } 171 | }, 172 | { 173 | "name": "DamagedHelmet", 174 | "directory": "..\\media\\cauldron-media\\DamagedHelmet\\GLTF\\", 175 | "filename": "DamagedHelmet.gltf", 176 | "TAA": false, 177 | "toneMapper": 0, 178 | "iblFactor": 2, 179 | "emmisiveFactor": 1, 180 | "intensity": 50, 181 | "exposure": 1, 182 | "camera": { 183 | "defaultFrom": [ 0, 0, 3.5 ], 184 | "defaultTo": [ 0, 0, 0 ] 185 | } 186 | }, 187 | { 188 | "name": "DragonAttenuation", 189 | "directory": "D:\\Sample-Models-glTF\\2.0\\DragonAttenuation\\glTF\\", 190 | "filename": "DragonAttenuation.gltf", 191 | "TAA": false, 192 | "toneMapper": 0, 193 | "iblFactor": 2, 194 | "emmisiveFactor": 1, 195 | "intensity": 50, 196 | "exposure": 1, 197 | "camera": { 198 | "defaultFrom": [ 0, 0, 3.5 ], 199 | "defaultTo": [ 0, 0, 0 ] 200 | } 201 | }, 202 | { 203 | "name": "GearboxAssy", 204 | "directory": "..\\media\\cauldron-media\\GearboxAssy\\glTF\\", 205 | "filename": "GearboxAssy.gltf", 206 | "TAA": false, 207 | "toneMapper": 0, 208 | "iblFactor": 2, 209 | "emmisiveFactor": 1, 210 | "intensity": 50, 211 | "exposure": 1, 212 | "camera": { 213 | "defaultFrom": [ 0, 0, 3.5 ], 214 | "defaultTo": [ 0, 0, 0 ] 215 | } 216 | }, 217 | { 218 | "name": "MetalRoughSpheres", 219 | "directory": "..\\media\\cauldron-media\\MetalRoughSpheres\\GLTF\\", 220 | "filename": "MetalRoughSpheres.gltf", 221 | "TAA": false, 222 | "iblFactor": 1, 223 | "emmisiveFactor": 1, 224 | "intensity": 50, 225 | "exposure": 1, 226 | "camera": { 227 | "defaultFrom": [ 0, 0, 20 ], 228 | "defaultTo": [ 0, 0, 0 ] 229 | } 230 | } 231 | ] 232 | } 233 | -------------------------------------------------------------------------------- /src/DX12/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(sources 2 | GLTFSample.cpp 3 | GLTFSample.h 4 | Renderer.cpp 5 | Renderer.h 6 | UI.cpp 7 | UI.h 8 | stdafx.cpp 9 | stdafx.h 10 | dpiawarescaling.manifest) 11 | 12 | source_group("Sources" FILES ${sources}) 13 | source_group("Icon" FILES ${icon_src}) # defined in top-level CMakeLists.txt 14 | 15 | add_executable(GLTFSample_DX12 WIN32 ${sources} ${common} ${icon_src}) 16 | target_link_libraries(GLTFSample_DX12 LINK_PUBLIC GLTFSample_Common Cauldron_DX12 ImGUI amd_ags d3dcompiler D3D12) 17 | 18 | set_target_properties(GLTFSample_DX12 PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" DEBUG_POSTFIX "d") 19 | -------------------------------------------------------------------------------- /src/DX12/GLTFSample.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2024 Advanced Micro Devices, Inc.All rights reserved. 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files(the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions : 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | // THE SOFTWARE. 19 | 20 | #include "stdafx.h" 21 | #include 22 | 23 | #include "GLTFSample.h" 24 | 25 | GLTFSample::GLTFSample(LPCSTR name) : FrameworkWindows(name) 26 | { 27 | m_time = 0; 28 | m_bPlay = false; 29 | 30 | m_pGltfLoader = NULL; 31 | } 32 | 33 | //-------------------------------------------------------------------------------------- 34 | // 35 | // OnParseCommandLine 36 | // 37 | //-------------------------------------------------------------------------------------- 38 | void GLTFSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight) 39 | { 40 | // set some default values 41 | *pWidth = 1920; 42 | *pHeight = 1080; 43 | m_activeScene = 0; //load the first one by default 44 | m_VsyncEnabled = false; 45 | m_bIsBenchmarking = false; 46 | m_bIsProfiling = false; 47 | m_fontSize = 13.f; // default value overridden by a json file if available 48 | 49 | // ADJUSTMENT: support z-buffer rasterizer custom parameters 50 | m_homogeneous = true; 51 | #if ENABLE_WORKGRAPHS 52 | m_algorithm = 5; 53 | #else 54 | m_algorithm = 2; 55 | #endif 56 | m_numberOfBins = 15; 57 | m_fixExpansion = true; 58 | m_threadLaunch = true; 59 | m_smoothing = true; 60 | 61 | #if _DEBUG 62 | m_isCpuValidationLayerEnabled = true; 63 | m_isGpuValidationLayerEnabled = true; 64 | #else 65 | m_isCpuValidationLayerEnabled = false; 66 | m_isGpuValidationLayerEnabled = false; 67 | #endif 68 | m_activeCamera = 0; 69 | m_stablePowerState = false; 70 | 71 | //read globals 72 | auto process = [&](json jData) 73 | { 74 | *pWidth = jData.value("width", *pWidth); 75 | *pHeight = jData.value("height", *pHeight); 76 | m_fullscreenMode = jData.value("presentationMode", m_fullscreenMode); 77 | m_activeScene = jData.value("activeScene", m_activeScene); 78 | m_activeCamera = jData.value("activeCamera", m_activeCamera); 79 | m_isCpuValidationLayerEnabled = jData.value("CpuValidationLayerEnabled", m_isCpuValidationLayerEnabled); 80 | m_isGpuValidationLayerEnabled = jData.value("GpuValidationLayerEnabled", m_isGpuValidationLayerEnabled); 81 | m_VsyncEnabled = jData.value("vsync", m_VsyncEnabled); 82 | m_FreesyncHDROptionEnabled = jData.value("FreesyncHDROptionEnabled", m_FreesyncHDROptionEnabled); 83 | m_bIsBenchmarking = jData.value("benchmark", m_bIsBenchmarking); 84 | m_bIsProfiling = jData.value("profile", m_bIsProfiling); 85 | m_stablePowerState = jData.value("stablePowerState", m_stablePowerState); 86 | m_fontSize = jData.value("fontsize", m_fontSize); 87 | 88 | // ADJUSTMENT: support z-buffer rasterizer custom parameters 89 | m_homogeneous = jData.value("homogeneous", m_homogeneous); 90 | m_algorithm = jData.value("algorithm", m_algorithm); 91 | m_numberOfBins = jData.value("bins", m_numberOfBins); 92 | m_fixExpansion = jData.value("fixedExpansion", m_fixExpansion); 93 | m_threadLaunch = jData.value("threadlaunch", m_threadLaunch); 94 | m_smoothing = jData.value("smoothing", m_bIsProfiling ? false : m_smoothing); 95 | }; 96 | 97 | // read config file 98 | // 99 | { 100 | std::ifstream f("GLTFSample.json"); 101 | if (!f) 102 | { 103 | MessageBox(NULL, "Config file not found!\n", "Cauldron Panic!", MB_ICONERROR); 104 | exit(0); 105 | } 106 | 107 | try 108 | { 109 | f >> m_jsonConfigFile; 110 | } 111 | catch (json::parse_error) 112 | { 113 | MessageBox(NULL, "Error parsing GLTFSample.json!\n", "Cauldron Panic!", MB_ICONERROR); 114 | exit(0); 115 | } 116 | } 117 | 118 | 119 | json globals = m_jsonConfigFile["globals"]; 120 | process(globals); 121 | 122 | // read json globals from commandline (and override values from config if so) 123 | // 124 | try 125 | { 126 | if (strlen(lpCmdLine) > 0) 127 | { 128 | m_jsonCommandLine = json::parse(lpCmdLine); 129 | process(m_jsonCommandLine); 130 | } 131 | } 132 | catch (json::parse_error) 133 | { 134 | Trace("Error parsing commandline\n"); 135 | exit(0); 136 | } 137 | 138 | // get the list of scenes 139 | for (const auto & scene : m_jsonConfigFile["scenes"]) 140 | m_sceneNames.push_back(scene["name"]); 141 | } 142 | 143 | //-------------------------------------------------------------------------------------- 144 | // 145 | // OnCreate 146 | // 147 | //-------------------------------------------------------------------------------------- 148 | void GLTFSample::OnCreate() 149 | { 150 | //init the shader compiler 151 | InitDirectXCompiler(); 152 | CreateShaderCache(); 153 | 154 | // Create a instance of the renderer and initialize it, we need to do that for each GPU 155 | m_pRenderer = new Renderer(); 156 | m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); 157 | 158 | // init GUI (non gfx stuff) 159 | ImGUI_Init((void *)m_windowHwnd); 160 | 161 | m_UIState.Initialize(); 162 | m_UIState.homogeneous = m_homogeneous; 163 | m_UIState.submissionMode = m_algorithm; 164 | m_UIState.numberOfBins = m_numberOfBins; 165 | m_UIState.fixedExpansion = m_fixExpansion; 166 | m_UIState.threadLaunch = m_threadLaunch; 167 | m_UIState.smoothing = m_smoothing; 168 | 169 | OnResize(true); 170 | OnUpdateDisplay(); 171 | 172 | // Init Camera, looking at the origin 173 | m_camera.LookAt(math::Vector4(0, 0, 5, 0), math::Vector4(0, 0, 0, 0)); 174 | } 175 | 176 | //-------------------------------------------------------------------------------------- 177 | // 178 | // OnDestroy 179 | // 180 | //-------------------------------------------------------------------------------------- 181 | void GLTFSample::OnDestroy() 182 | { 183 | ImGUI_Shutdown(); 184 | 185 | m_device.GPUFlush(); 186 | 187 | m_pRenderer->UnloadScene(); 188 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 189 | m_pRenderer->OnDestroy(); 190 | 191 | delete m_pRenderer; 192 | 193 | //shut down the shader compiler 194 | DestroyShaderCache(&m_device); 195 | 196 | if (m_pGltfLoader) 197 | { 198 | delete m_pGltfLoader; 199 | m_pGltfLoader = NULL; 200 | } 201 | } 202 | 203 | //-------------------------------------------------------------------------------------- 204 | // 205 | // OnEvent, win32 sends us events and we forward them to ImGUI 206 | // 207 | //-------------------------------------------------------------------------------------- 208 | bool GLTFSample::OnEvent(MSG msg) 209 | { 210 | if (ImGUI_WndProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam)) 211 | return true; 212 | 213 | // handle function keys (F1, F2...) here, rest of the input is handled 214 | // by imGUI later in HandleInput() function 215 | const WPARAM& KeyPressed = msg.wParam; 216 | switch (msg.message) 217 | { 218 | case WM_KEYUP: 219 | case WM_SYSKEYUP: 220 | /* WINDOW TOGGLES */ 221 | if (KeyPressed == VK_F1) m_UIState.bShowControlsWindow ^= 1; 222 | if (KeyPressed == VK_F2) m_UIState.bShowProfilerWindow ^= 1; 223 | break; 224 | } 225 | 226 | return true; 227 | } 228 | 229 | //-------------------------------------------------------------------------------------- 230 | // 231 | // OnResize 232 | // 233 | //-------------------------------------------------------------------------------------- 234 | void GLTFSample::OnResize(bool resizeRender) 235 | { 236 | // Destroy resources (if we are not minimized) 237 | if (resizeRender && m_Width && m_Height && m_pRenderer) 238 | { 239 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 240 | m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); 241 | } 242 | 243 | m_camera.SetFov(AMD_PI_OVER_4, m_Width, m_Height, 0.1f, 1000.0f); 244 | } 245 | 246 | //-------------------------------------------------------------------------------------- 247 | // 248 | // UpdateDisplay 249 | // 250 | //-------------------------------------------------------------------------------------- 251 | void GLTFSample::OnUpdateDisplay() 252 | { 253 | // Destroy resources (if we are not minimized) 254 | if (m_pRenderer) 255 | { 256 | m_pRenderer->OnUpdateDisplayDependentResources(&m_swapChain); 257 | } 258 | } 259 | 260 | //-------------------------------------------------------------------------------------- 261 | // 262 | // LoadScene 263 | // 264 | //-------------------------------------------------------------------------------------- 265 | void GLTFSample::LoadScene(int sceneIndex) 266 | { 267 | json parms = m_jsonCommandLine; 268 | json scene = m_jsonConfigFile["scenes"][sceneIndex]; 269 | 270 | // release everything and load the GLTF, just the light json data, the rest (textures and geometry) will be done in the main loop 271 | if (m_pGltfLoader != NULL) 272 | { 273 | m_pRenderer->UnloadScene(); 274 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 275 | m_pRenderer->OnDestroy(); 276 | m_pGltfLoader->Unload(); 277 | m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); 278 | m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); 279 | } 280 | 281 | delete(m_pGltfLoader); 282 | m_pGltfLoader = new GLTFCommon(); 283 | if (m_pGltfLoader->Load(scene["directory"], scene["filename"]) == false) 284 | { 285 | MessageBox(NULL, "The selected model couldn't be found, please check the documentation", "Cauldron Panic!", MB_ICONERROR); 286 | exit(0); 287 | } 288 | 289 | // Load the UI settings, and also some defaults cameras and lights, in case the GLTF has none 290 | { 291 | #define LOAD(j, key, val) val = j.value(key, val) 292 | 293 | // global settings 294 | LOAD(scene, "TAA", m_UIState.bUseTAA); 295 | LOAD(scene, "toneMapper", m_UIState.SelectedTonemapperIndex); 296 | LOAD(scene, "skyDomeType", m_UIState.SelectedSkydomeTypeIndex); 297 | LOAD(scene, "exposure", m_UIState.Exposure); 298 | LOAD(scene, "iblFactor", m_UIState.IBLFactor); 299 | LOAD(scene, "emmisiveFactor", m_UIState.EmissiveFactor); 300 | LOAD(scene, "skyDomeType", m_UIState.SelectedSkydomeTypeIndex); 301 | 302 | // ADJUSTMENT: always disable TAA for now 303 | m_UIState.bUseTAA = false; 304 | 305 | // Add a default light in case there are none 306 | if (m_pGltfLoader->m_lights.size() == 0) 307 | { 308 | tfNode n; 309 | n.m_tranform.LookAt(PolarToVector(AMD_PI_OVER_2, 0.58f) * 3.5f, math::Vector4(0, 0, 0, 0)); 310 | 311 | tfLight l; 312 | l.m_type = tfLight::LIGHT_SPOTLIGHT; 313 | l.m_intensity = scene.value("intensity", 1.0f); 314 | l.m_color = math::Vector4(1.0f, 1.0f, 1.0f, 0.0f); 315 | l.m_range = 15; 316 | l.m_outerConeAngle = AMD_PI_OVER_4; 317 | l.m_innerConeAngle = AMD_PI_OVER_4 * 0.9f; 318 | l.m_shadowResolution = 1024; 319 | 320 | m_pGltfLoader->AddLight(n, l); 321 | } 322 | 323 | // Allocate shadow information (if any) 324 | m_pRenderer->AllocateShadowMaps(m_pGltfLoader); 325 | 326 | // set default camera 327 | json camera = scene["camera"]; 328 | m_activeCamera = scene.value("activeCamera", m_activeCamera); 329 | math::Vector4 from = GetVector(GetElementJsonArray(camera, "defaultFrom", { 0.0, 0.0, 10.0 })); 330 | math::Vector4 to = GetVector(GetElementJsonArray(camera, "defaultTo", { 0.0, 0.0, 0.0 })); 331 | m_camera.LookAt(from, to); 332 | 333 | // set benchmarking state if enabled 334 | if (m_bIsBenchmarking) 335 | { 336 | std::string deviceName; 337 | std::string driverVersion; 338 | m_device.GetDeviceInfo(&deviceName, &driverVersion); 339 | BenchmarkConfig(scene["BenchmarkSettings"], m_activeCamera, m_pGltfLoader, deviceName, driverVersion); 340 | } 341 | 342 | // set profiling state if enabled 343 | else if (m_bIsProfiling) 344 | { 345 | std::string deviceName; 346 | std::string driverVersion; 347 | m_device.GetDeviceInfo(&deviceName, &driverVersion); 348 | ProfileConfig(parms["ProfileSettings"], m_activeCamera, m_pGltfLoader, deviceName, driverVersion); 349 | } 350 | 351 | // indicate the mainloop we started loading a GLTF and it needs to load the rest (textures and geometry) 352 | m_loadingScene = true; 353 | } 354 | } 355 | 356 | 357 | //-------------------------------------------------------------------------------------- 358 | // 359 | // OnUpdate 360 | // 361 | //-------------------------------------------------------------------------------------- 362 | void GLTFSample::OnUpdate() 363 | { 364 | ImGuiIO& io = ImGui::GetIO(); 365 | 366 | //If the mouse was not used by the GUI then it's for the camera 367 | if (io.WantCaptureMouse) 368 | { 369 | io.MouseDelta.x = 0; 370 | io.MouseDelta.y = 0; 371 | io.MouseWheel = 0; 372 | } 373 | 374 | // Update Camera 375 | UpdateCamera(m_camera, io); 376 | if (m_UIState.bUseTAA) 377 | { 378 | static uint32_t Seed; 379 | m_camera.SetProjectionJitter(m_Width, m_Height, Seed); 380 | } 381 | else 382 | m_camera.SetProjectionJitter(0.f, 0.f); 383 | 384 | // Keyboard & Mouse 385 | HandleInput(io); 386 | 387 | // Animation Update 388 | if (m_bPlay) 389 | m_time += (float)m_deltaTime / 1000.0f; // animation time in seconds 390 | 391 | if (m_pGltfLoader) 392 | { 393 | m_pGltfLoader->SetAnimationTime(0, m_time); 394 | m_pGltfLoader->TransformScene(0, math::Matrix4::identity()); 395 | } 396 | } 397 | void GLTFSample::HandleInput(const ImGuiIO& io) 398 | { 399 | auto fnIsKeyTriggered = [&io](char key) { return io.KeysDown[key] && io.KeysDownDuration[key] == 0.0f; }; 400 | 401 | // Handle Keyboard/Mouse input here 402 | 403 | /* MAGNIFIER CONTROLS */ 404 | if (fnIsKeyTriggered('L')) m_UIState.ToggleMagnifierLock(); 405 | if (fnIsKeyTriggered('M') || io.MouseClicked[2]) m_UIState.bUseMagnifier ^= 1; // middle mouse / M key toggles magnifier 406 | 407 | if (io.MouseClicked[1] && m_UIState.bUseMagnifier) // right mouse click 408 | m_UIState.ToggleMagnifierLock(); 409 | } 410 | void GLTFSample::UpdateCamera(Camera& cam, const ImGuiIO& io) 411 | { 412 | float yaw = cam.GetYaw(); 413 | float pitch = cam.GetPitch(); 414 | float distance = cam.GetDistance(); 415 | 416 | cam.UpdatePreviousMatrices(); // set previous view matrix 417 | 418 | // Sets Camera based on UI selection (WASD, Orbit or any of the GLTF cameras) 419 | if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) 420 | { 421 | yaw -= io.MouseDelta.x / 100.f; 422 | pitch += io.MouseDelta.y / 100.f; 423 | } 424 | 425 | // Choose camera movement depending on setting 426 | if (m_activeCamera == 0) 427 | { 428 | // If nothing has changed, don't calculate an update (we are getting micro changes in view causing bugs) 429 | if (!io.MouseWheel && (!io.MouseDown[0] || (!io.MouseDelta.x && !io.MouseDelta.y) )) 430 | return; 431 | 432 | // Orbiting 433 | distance -= (float)io.MouseWheel / 3.0f; 434 | distance = std::max(distance, 0.1f); 435 | 436 | bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); 437 | 438 | cam.UpdateCameraPolar(yaw, pitch, 439 | panning ? -io.MouseDelta.x / 100.0f : 0.0f, 440 | panning ? io.MouseDelta.y / 100.0f : 0.0f, 441 | distance); 442 | } 443 | else if (m_activeCamera == 1) 444 | { 445 | // WASD 446 | cam.UpdateCameraWASD(yaw, pitch, io.KeysDown, io.DeltaTime); 447 | } 448 | else if (m_activeCamera > 1) 449 | { 450 | // Use a camera from the GLTF 451 | m_pGltfLoader->GetCamera(m_activeCamera - 2, &cam); 452 | } 453 | } 454 | 455 | //-------------------------------------------------------------------------------------- 456 | // 457 | // OnRender 458 | // 459 | //-------------------------------------------------------------------------------------- 460 | void GLTFSample::OnRender() 461 | { 462 | // Do any start of frame necessities 463 | BeginFrame(); 464 | 465 | ImGUI_UpdateIO(); 466 | ImGui::NewFrame(); 467 | 468 | if (m_loadingScene) 469 | { 470 | // the scene loads in chunks, that way we can show a progress bar 471 | static int loadingStage = 0; 472 | loadingStage = m_pRenderer->LoadScene(m_pGltfLoader, loadingStage); 473 | if (loadingStage == 0) 474 | { 475 | m_time = 0; 476 | m_loadingScene = false; 477 | } 478 | } 479 | else if (m_pGltfLoader && m_bIsBenchmarking) 480 | { 481 | // Benchmarking takes control of the time, and exits the app when the animation is done 482 | std::vector timeStamps = m_pRenderer->GetTimingValues(); 483 | m_time = BenchmarkLoop(timeStamps, &m_camera, m_pRenderer->GetScreenshotFileName()); 484 | } 485 | else if (m_pGltfLoader && m_bIsProfiling) 486 | { 487 | // Benchmarking takes control of the time, and exits the app when the animation is done 488 | std::vector timeStamps = m_pRenderer->GetTimingValues(); 489 | m_time = ProfileLoop(timeStamps, &m_camera, m_pRenderer->GetScreenshotFileName()); 490 | } 491 | else 492 | { 493 | BuildUI(); // UI logic. Note that the rendering of the UI happens later. 494 | OnUpdate(); // Update camera, handle keyboard/mouse input 495 | } 496 | 497 | // Do Render frame using AFR 498 | m_pRenderer->OnRender(&m_UIState, m_camera, &m_swapChain); 499 | 500 | // Framework will handle Present and some other end of frame logic 501 | EndFrame(); 502 | 503 | // TENTATIVE: Workaround for hang 504 | Sleep(0); 505 | } 506 | 507 | #ifdef ENABLE_WORKGRAPHS 508 | // Configure Agility SDK version 509 | extern "C" { 510 | __declspec(dllexport) extern const UINT D3D12SDKVersion = 613; 511 | } 512 | // Configure Agility SDK path 513 | extern "C" { 514 | __declspec(dllexport) extern const char* D3D12SDKPath = ".\\d3d12\\"; 515 | } 516 | #endif 517 | 518 | //-------------------------------------------------------------------------------------- 519 | // 520 | // WinMain 521 | // 522 | //-------------------------------------------------------------------------------------- 523 | int WINAPI WinMain(HINSTANCE hInstance, 524 | HINSTANCE hPrevInstance, 525 | LPSTR lpCmdLine, 526 | int nCmdShow) 527 | { 528 | LPCSTR Name = "DX12 Work Graphs Compute Rasterizer Sample v1.1"; 529 | 530 | // create new DX sample 531 | return RunFramework(hInstance, lpCmdLine, nCmdShow, new GLTFSample(Name)); 532 | } 533 | -------------------------------------------------------------------------------- /src/DX12/GLTFSample.h: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2024 Advanced Micro Devices, Inc.All rights reserved. 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files(the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions : 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | // THE SOFTWARE. 19 | #pragma once 20 | 21 | #include "base/FrameworkWindows.h" 22 | #include "Renderer.h" 23 | #include "UI.h" 24 | 25 | // This class encapsulates the 'application' and is responsible for handling window events and scene updates (simulation) 26 | // Rendering and rendering resource management is done by the Renderer class 27 | 28 | class GLTFSample : public FrameworkWindows 29 | { 30 | public: 31 | GLTFSample(LPCSTR name); 32 | void OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight) override; 33 | void OnCreate() override; 34 | void OnDestroy() override; 35 | void OnRender() override; 36 | bool OnEvent(MSG msg) override; 37 | void OnResize(bool resizeRender) override; 38 | void OnUpdateDisplay() override; 39 | 40 | void BuildUI(); 41 | void LoadScene(int sceneIndex); 42 | 43 | void OnUpdate(); 44 | 45 | void HandleInput(const ImGuiIO& io); 46 | void UpdateCamera(Camera& cam, const ImGuiIO& io); 47 | 48 | private: 49 | 50 | bool m_bIsBenchmarking; 51 | bool m_bIsProfiling; 52 | 53 | // ADJUSTMENT: support z-buffer rasterizer custom parameters 54 | bool m_homogeneous; 55 | int m_algorithm; 56 | int m_numberOfBins; 57 | bool m_fixExpansion; 58 | bool m_threadLaunch; 59 | bool m_smoothing; 60 | 61 | GLTFCommon *m_pGltfLoader = NULL; 62 | bool m_loadingScene = false; 63 | 64 | Renderer* m_pRenderer = NULL; 65 | UIState m_UIState; 66 | float m_fontSize; 67 | Camera m_camera; 68 | 69 | float m_time; // Time accumulator in seconds, used for animation. 70 | 71 | // json config file 72 | json m_jsonCommandLine; 73 | json m_jsonConfigFile; 74 | std::vector m_sceneNames; 75 | int m_activeScene; 76 | int m_activeCamera; 77 | 78 | bool m_bPlay; 79 | }; 80 | -------------------------------------------------------------------------------- /src/DX12/Renderer.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2024 Advanced Micro Devices, Inc.All rights reserved. 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files(the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions : 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | // THE SOFTWARE. 19 | 20 | #include "Renderer.h" 21 | #include "UI.h" 22 | 23 | #include 24 | 25 | //-------------------------------------------------------------------------------------- 26 | // 27 | // OnCreate 28 | // 29 | //-------------------------------------------------------------------------------------- 30 | void Renderer::OnCreate(Device* pDevice, SwapChain *pSwapChain, float FontSize) 31 | { 32 | m_pDevice = pDevice; 33 | 34 | #ifdef ENABLE_WORKGRAPHS 35 | // Check work-graph support 36 | // 37 | D3D12_FEATURE_DATA_D3D12_OPTIONS21 Options; 38 | ThrowIfFailed(pDevice->GetDevice()->CheckFeatureSupport( 39 | D3D12_FEATURE_D3D12_OPTIONS21, &Options, sizeof(Options))); 40 | if (Options.WorkGraphsTier == D3D12_WORK_GRAPHS_TIER_NOT_SUPPORTED) { 41 | throw std::runtime_error("Device does not report support for work graphs"); 42 | } 43 | 44 | ThrowIfFailed(pDevice->GetDevice()->QueryInterface(IID_PPV_ARGS(&m_pDevice8Native))); 45 | #endif 46 | 47 | // Initialize helpers 48 | 49 | // Create all the heaps for the resources views 50 | const uint32_t cbvDescriptorCount = 4000; 51 | const uint32_t srvDescriptorCount = 8000; 52 | const uint32_t uavDescriptorCount = 10; 53 | const uint32_t dsvDescriptorCount = 10; 54 | const uint32_t rtvDescriptorCount = 60; 55 | const uint32_t samplerDescriptorCount = 20; 56 | m_ResourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, dsvDescriptorCount, rtvDescriptorCount, samplerDescriptorCount); 57 | 58 | // Create a commandlist ring for the Direct queue 59 | uint32_t commandListsPerBackBuffer = 8; 60 | m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer, pDevice->GetGraphicsQueue()->GetDesc()); 61 | 62 | // Create a 'dynamic' constant buffer 63 | const uint32_t constantBuffersMemSize = 200 * 1024 * 1024; 64 | m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, &m_ResourceViewHeaps); 65 | 66 | // Create a 'static' pool for vertices, indices and constant buffers 67 | const uint32_t staticGeometryMemSize = (5 * 128) * 1024 * 1024; 68 | m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, true, "StaticGeom"); 69 | 70 | // initialize the GPU time stamps module 71 | m_GPUTimer.OnCreate(pDevice, backBufferCount); 72 | 73 | // Quick helper to upload resources, it has it's own commandList and uses suballocation. 74 | const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024; 75 | m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results) 76 | 77 | // Create GBuffer and render passes 78 | // 79 | { 80 | m_GBuffer.OnCreate( 81 | pDevice, 82 | &m_ResourceViewHeaps, 83 | { 84 | { GBUFFER_DEPTH, DXGI_FORMAT_D32_FLOAT}, 85 | { GBUFFER_FORWARD, DXGI_FORMAT_R16G16B16A16_FLOAT}, 86 | { GBUFFER_MOTION_VECTORS, DXGI_FORMAT_R16G16_FLOAT}, 87 | }, 88 | 1 89 | ); 90 | 91 | GBufferFlags fullGBuffer = GBUFFER_DEPTH | GBUFFER_FORWARD | GBUFFER_MOTION_VECTORS; 92 | m_RenderPassFullGBuffer.OnCreate(&m_GBuffer, fullGBuffer); 93 | m_RenderPassJustDepthAndHdr.OnCreate(&m_GBuffer, GBUFFER_DEPTH | GBUFFER_FORWARD); 94 | } 95 | 96 | // Reserve visibility texture/buffer view for z-buffer rasterizer 97 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_VBufferSRV); 98 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor (1, &m_VBufferUAV); 99 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptorCPU(1, &m_VBufferUAVCPU); 100 | 101 | #if USE_SHADOWMASK 102 | m_shadowResolve.OnCreate(m_pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing); 103 | 104 | // Create the shadow mask descriptors 105 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_ShadowMaskUAV); 106 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_ShadowMaskSRV); 107 | #endif 108 | 109 | m_SkyDome.OnCreate(pDevice, &m_UploadHeap, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, "..\\media\\cauldron-media\\envmaps\\papermill\\diffuse.dds", "..\\media\\cauldron-media\\envmaps\\papermill\\specular.dds", DXGI_FORMAT_R16G16B16A16_FLOAT, 4); 110 | m_SkyDomeProc.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT, 1); 111 | m_Wireframe.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT, 1); 112 | m_WireframeBox.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool); 113 | m_DownSample.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); 114 | m_Bloom.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); 115 | m_TAA.OnCreate(pDevice, &m_ResourceViewHeaps, &m_VidMemBufferPool); 116 | m_MagnifierPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); 117 | m_Debug.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); 118 | 119 | // Create tonemapping pass 120 | m_ToneMappingPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); 121 | m_ToneMappingCS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing); 122 | m_ColorConversionPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); 123 | 124 | // Initialize UI rendering resources 125 | m_ImGUI.OnCreate(pDevice, &m_UploadHeap, &m_ResourceViewHeaps, &m_ConstantBufferRing, pSwapChain->GetFormat(), FontSize); 126 | 127 | // Make sure upload heap has finished uploading before continuing 128 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 129 | m_UploadHeap.FlushAndFinish(); 130 | } 131 | 132 | //-------------------------------------------------------------------------------------- 133 | // 134 | // OnDestroy 135 | // 136 | //-------------------------------------------------------------------------------------- 137 | void Renderer::OnDestroy() 138 | { 139 | m_AsyncPool.Flush(); 140 | 141 | m_ImGUI.OnDestroy(); 142 | m_ColorConversionPS.OnDestroy(); 143 | m_ToneMappingCS.OnDestroy(); 144 | m_ToneMappingPS.OnDestroy(); 145 | m_TAA.OnDestroy(); 146 | m_Bloom.OnDestroy(); 147 | m_DownSample.OnDestroy(); 148 | m_MagnifierPS.OnDestroy(); 149 | m_WireframeBox.OnDestroy(); 150 | m_Wireframe.OnDestroy(); 151 | m_SkyDomeProc.OnDestroy(); 152 | m_SkyDome.OnDestroy(); 153 | #if USE_SHADOWMASK 154 | m_shadowResolve.OnDestroy(); 155 | #endif 156 | m_GBuffer.OnDestroy(); 157 | m_Debug.OnDestroy(); 158 | 159 | m_UploadHeap.OnDestroy(); 160 | m_GPUTimer.OnDestroy(); 161 | m_VidMemBufferPool.OnDestroy(); 162 | m_ConstantBufferRing.OnDestroy(); 163 | m_ResourceViewHeaps.OnDestroy(); 164 | m_CommandListRing.OnDestroy(); 165 | 166 | #ifdef ENABLE_WORKGRAPHS 167 | m_pDevice8Native->Release(); 168 | #endif 169 | } 170 | 171 | //-------------------------------------------------------------------------------------- 172 | // 173 | // OnCreateWindowSizeDependentResources 174 | // 175 | //-------------------------------------------------------------------------------------- 176 | void Renderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height) 177 | { 178 | m_Width = Width; 179 | m_Height = Height; 180 | 181 | // Set the viewport & scissors rect 182 | m_Viewport = { 0.0f, 0.0f, static_cast(Width), static_cast(Height), 0.0f, 1.0f }; 183 | m_RectScissor = { 0, 0, (LONG)Width, (LONG)Height }; 184 | 185 | // Create visibility texture/buffer for z-buffer rasterizer 186 | // auto tex = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32G32_UINT, Width, Height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 187 | auto tex = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_UINT, Width, Height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 188 | m_VBuffer.InitRenderTarget(m_pDevice, "visibilitybuffer", &tex, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 189 | m_VBuffer.CreateSRV(0, &m_VBufferSRV); 190 | m_VBuffer.CreateUAV(0, &m_VBufferUAV); 191 | m_VBuffer.CreateUAV(0, &m_VBufferUAVCPU); 192 | 193 | #if USE_SHADOWMASK 194 | // Create shadow mask 195 | // 196 | auto tex = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, Width, Height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); 197 | m_ShadowMask.Init(m_pDevice, "shadowbuffer", &tex, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, NULL); 198 | m_ShadowMask.CreateUAV(0, &m_ShadowMaskUAV); 199 | m_ShadowMask.CreateSRV(0, &m_ShadowMaskSRV); 200 | #endif 201 | 202 | // Create GBuffer 203 | // 204 | m_GBuffer.OnCreateWindowSizeDependentResources(pSwapChain, Width, Height); 205 | m_RenderPassFullGBuffer.OnCreateWindowSizeDependentResources(Width, Height); 206 | m_RenderPassJustDepthAndHdr.OnCreateWindowSizeDependentResources(Width, Height); 207 | 208 | m_TAA.OnCreateWindowSizeDependentResources(Width, Height, &m_GBuffer); 209 | 210 | // update bloom and downscaling effect 211 | // 212 | m_DownSample.OnCreateWindowSizeDependentResources(m_Width, m_Height, &m_GBuffer.m_HDR, 5); //downsample the HDR texture 5 times 213 | m_Bloom.OnCreateWindowSizeDependentResources(m_Width / 2, m_Height / 2, m_DownSample.GetTexture(), 5, &m_GBuffer.m_HDR); 214 | m_MagnifierPS.OnCreateWindowSizeDependentResources(&m_GBuffer.m_HDR); 215 | } 216 | 217 | //-------------------------------------------------------------------------------------- 218 | // 219 | // OnDestroyWindowSizeDependentResources 220 | // 221 | //-------------------------------------------------------------------------------------- 222 | void Renderer::OnDestroyWindowSizeDependentResources() 223 | { 224 | m_Bloom.OnDestroyWindowSizeDependentResources(); 225 | m_DownSample.OnDestroyWindowSizeDependentResources(); 226 | 227 | m_GBuffer.OnDestroyWindowSizeDependentResources(); 228 | 229 | m_TAA.OnDestroyWindowSizeDependentResources(); 230 | 231 | m_MagnifierPS.OnDestroyWindowSizeDependentResources(); 232 | 233 | #if USE_SHADOWMASK 234 | m_ShadowMask.OnDestroy(); 235 | #endif 236 | 237 | // Destroy visibility texture/buffer for z-buffer rasterizer 238 | m_VBuffer.OnDestroy(); 239 | } 240 | 241 | void Renderer::OnUpdateDisplayDependentResources(SwapChain* pSwapChain) 242 | { 243 | // Update pipelines in case the format of the RTs changed (this happens when going HDR) 244 | // m_ColorConversionPS.UpdatePipelines(pSwapChain->GetFormat(), pSwapChain->GetDisplayMode()); 245 | // m_ToneMappingPS.UpdatePipelines(pSwapChain->GetFormat()); 246 | m_ImGUI.UpdatePipeline((pSwapChain->GetDisplayMode() == DISPLAYMODE_SDR) ? pSwapChain->GetFormat() : m_GBuffer.m_HDR.GetFormat()); 247 | } 248 | 249 | //-------------------------------------------------------------------------------------- 250 | // 251 | // LoadScene 252 | // 253 | //-------------------------------------------------------------------------------------- 254 | int Renderer::LoadScene(GLTFCommon *pGLTFCommon, int Stage) 255 | { 256 | // show loading progress 257 | // 258 | ImGui::OpenPopup("Loading"); 259 | if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 260 | { 261 | float progress = (float)Stage / 13.0f; 262 | ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL); 263 | ImGui::EndPopup(); 264 | } 265 | 266 | // use multi threading 267 | AsyncPool *pAsyncPool = &m_AsyncPool; 268 | 269 | // Loading stages 270 | // 271 | if (Stage == 0) 272 | { 273 | } 274 | else if (Stage == 5) 275 | { 276 | Profile p("m_pGltfLoader->Load"); 277 | 278 | m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers(); 279 | m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing); 280 | } 281 | else if (Stage == 6) 282 | { 283 | Profile p("LoadTextures"); 284 | 285 | // here we are loading onto the GPU all the textures and the inverse matrices 286 | // this data will be used to create the PBR and Depth passes 287 | m_pGLTFTexturesAndBuffers->LoadTextures(pAsyncPool); 288 | } 289 | else if (Stage == 7) 290 | { 291 | Profile p("m_GLTFDepth->OnCreate"); 292 | 293 | //create the glTF's textures, VBs, IBs, shaders and descriptors for this particular pass 294 | m_GLTFDepth = new GltfDepthPass(); 295 | m_GLTFDepth->OnCreate( 296 | m_pDevice, 297 | &m_UploadHeap, 298 | &m_ResourceViewHeaps, 299 | &m_ConstantBufferRing, 300 | &m_VidMemBufferPool, 301 | m_pGLTFTexturesAndBuffers, 302 | pAsyncPool 303 | ); 304 | } 305 | else if (Stage == 9) 306 | { 307 | Profile p("m_GLTFPBR->OnCreate"); 308 | 309 | // same thing as above but for the PBR pass 310 | m_GLTFPBR = new GltfPbrPass(); 311 | m_GLTFPBR->OnCreate( 312 | m_pDevice, 313 | &m_UploadHeap, 314 | &m_ResourceViewHeaps, 315 | &m_ConstantBufferRing, 316 | m_pGLTFTexturesAndBuffers, 317 | &m_SkyDome, 318 | false, // use a SSAO mask 319 | USE_SHADOWMASK, 320 | &m_RenderPassFullGBuffer, 321 | pAsyncPool 322 | ); 323 | 324 | } 325 | else if (Stage == 10) 326 | { 327 | Profile p("m_GLTFBBox->OnCreate"); 328 | 329 | // just a bounding box pass that will draw boundingboxes instead of the geometry itself 330 | m_GLTFBBox = new GltfBBoxPass(); 331 | m_GLTFBBox->OnCreate( 332 | m_pDevice, 333 | &m_UploadHeap, 334 | &m_ResourceViewHeaps, 335 | &m_ConstantBufferRing, 336 | &m_VidMemBufferPool, 337 | m_pGLTFTexturesAndBuffers, 338 | &m_Wireframe 339 | ); 340 | 341 | // we are borrowing the upload heap command list for uploading to the GPU the IBs and VBs 342 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 343 | 344 | } 345 | else if (Stage == 11) 346 | { 347 | Profile p("m_GLTFRasterizer->OnCreate"); 348 | 349 | // just a bounding box pass that will draw boundingboxes instead of the geometry itself 350 | m_GLTFRasterizer = new GltfRasterizerPass(); 351 | m_GLTFRasterizer->OnCreate( 352 | m_pDevice, 353 | &m_UploadHeap, 354 | &m_ResourceViewHeaps, 355 | &m_ConstantBufferRing, 356 | &m_VidMemBufferPool, 357 | m_pGLTFTexturesAndBuffers, 358 | &m_VBuffer, &m_VBufferUAV, &m_VBufferUAVCPU 359 | ); 360 | 361 | } 362 | else if (Stage == 12) 363 | { 364 | Profile p("Flush"); 365 | 366 | m_UploadHeap.FlushAndFinish(); 367 | 368 | //once everything is uploaded we dont need he upload heaps anymore 369 | m_VidMemBufferPool.FreeUploadHeap(); 370 | 371 | // tell caller that we are done loading the map 372 | return 0; 373 | } 374 | 375 | Stage++; 376 | return Stage; 377 | } 378 | 379 | //-------------------------------------------------------------------------------------- 380 | // 381 | // UnloadScene 382 | // 383 | //-------------------------------------------------------------------------------------- 384 | void Renderer::UnloadScene() 385 | { 386 | // wait for all the async loading operations to finish 387 | m_AsyncPool.Flush(); 388 | 389 | m_pDevice->GPUFlush(); 390 | 391 | if (m_GLTFRasterizer) 392 | { 393 | m_GLTFRasterizer->OnDestroy(); 394 | delete m_GLTFRasterizer; 395 | m_GLTFRasterizer = NULL; 396 | } 397 | 398 | if (m_GLTFPBR) 399 | { 400 | m_GLTFPBR->OnDestroy(); 401 | delete m_GLTFPBR; 402 | m_GLTFPBR = NULL; 403 | } 404 | 405 | if (m_GLTFDepth) 406 | { 407 | m_GLTFDepth->OnDestroy(); 408 | delete m_GLTFDepth; 409 | m_GLTFDepth = NULL; 410 | } 411 | 412 | if (m_GLTFBBox) 413 | { 414 | m_GLTFBBox->OnDestroy(); 415 | delete m_GLTFBBox; 416 | m_GLTFBBox = NULL; 417 | } 418 | 419 | if (m_pGLTFTexturesAndBuffers) 420 | { 421 | m_pGLTFTexturesAndBuffers->OnDestroy(); 422 | delete m_pGLTFTexturesAndBuffers; 423 | m_pGLTFTexturesAndBuffers = NULL; 424 | } 425 | 426 | while (!m_shadowMapPool.empty()) 427 | { 428 | m_shadowMapPool.back().ShadowMap.OnDestroy(); 429 | m_shadowMapPool.pop_back(); 430 | } 431 | } 432 | 433 | void Renderer::AllocateShadowMaps(GLTFCommon* pGLTFCommon) 434 | { 435 | // Go through the lights and allocate shadow information 436 | uint32_t NumShadows = 0; 437 | for (int i = 0; i < pGLTFCommon->m_lightInstances.size(); ++i) 438 | { 439 | const tfLight& lightData = pGLTFCommon->m_lights[pGLTFCommon->m_lightInstances[i].m_lightId]; 440 | if (lightData.m_shadowResolution) 441 | { 442 | SceneShadowInfo ShadowInfo; 443 | ShadowInfo.ShadowResolution = lightData.m_shadowResolution; 444 | ShadowInfo.ShadowIndex = NumShadows++; 445 | ShadowInfo.LightIndex = i; 446 | m_shadowMapPool.push_back(ShadowInfo); 447 | } 448 | } 449 | 450 | if (NumShadows > MaxShadowInstances) 451 | { 452 | Trace("Number of shadows has exceeded maximum supported. Please grow value in gltfCommon.h/perFrameStruct.h"); 453 | throw; 454 | } 455 | 456 | // If we had shadow information, allocate all required maps and bindings 457 | if (!m_shadowMapPool.empty()) 458 | { 459 | m_ResourceViewHeaps.AllocDSVDescriptor((uint32_t)m_shadowMapPool.size(), &m_ShadowMapPoolDSV); 460 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor((uint32_t)m_shadowMapPool.size(), &m_ShadowMapPoolSRV); 461 | 462 | std::vector::iterator CurrentShadow = m_shadowMapPool.begin(); 463 | for( uint32_t i = 0; CurrentShadow < m_shadowMapPool.end(); ++i, ++CurrentShadow) 464 | { 465 | auto tex = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, CurrentShadow->ShadowResolution, CurrentShadow->ShadowResolution, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL); 466 | 467 | CurrentShadow->ShadowMap.InitDepthStencil(m_pDevice, "m_pShadowMap", &tex); 468 | CurrentShadow->ShadowMap.CreateDSV(CurrentShadow->ShadowIndex, &m_ShadowMapPoolDSV); 469 | CurrentShadow->ShadowMap.CreateSRV(CurrentShadow->ShadowIndex, &m_ShadowMapPoolSRV); 470 | } 471 | } 472 | } 473 | 474 | //-------------------------------------------------------------------------------------- 475 | // 476 | // OnRender 477 | // 478 | //-------------------------------------------------------------------------------------- 479 | void Renderer::OnRender(const UIState* pState, const Camera& Cam, SwapChain* pSwapChain) 480 | { 481 | // Timing values 482 | UINT64 gpuTicksPerSecond; 483 | m_pDevice->GetGraphicsQueue()->GetTimestampFrequency(&gpuTicksPerSecond); 484 | 485 | // Let our resource managers do some house keeping 486 | m_CommandListRing.OnBeginFrame(); 487 | m_ConstantBufferRing.OnBeginFrame(); 488 | m_GPUTimer.OnBeginFrame(gpuTicksPerSecond, &m_TimeStamps, pState->smoothing); 489 | 490 | // Sets the perFrame data 491 | per_frame *pPerFrame = NULL; 492 | if (m_pGLTFTexturesAndBuffers) 493 | { 494 | // fill as much as possible using the GLTF (camera, lights, ...) 495 | pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(Cam); 496 | 497 | // Set some lighting factors 498 | pPerFrame->iblFactor = pState->IBLFactor; 499 | pPerFrame->emmisiveFactor = pState->EmissiveFactor; 500 | pPerFrame->invScreenResolution[0] = 1.0f / ((float)m_Width); 501 | pPerFrame->invScreenResolution[1] = 1.0f / ((float)m_Height); 502 | 503 | pPerFrame->wireframeOptions.setX(pState->WireframeColor[0]); 504 | pPerFrame->wireframeOptions.setY(pState->WireframeColor[1]); 505 | pPerFrame->wireframeOptions.setZ(pState->WireframeColor[2]); 506 | pPerFrame->wireframeOptions.setW(pState->WireframeMode == UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR ? 1.0f : 0.0f); 507 | pPerFrame->lodBias = 0.0f; 508 | m_pGLTFTexturesAndBuffers->SetPerFrameConstants(); 509 | m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons(); 510 | } 511 | 512 | // command buffer calls 513 | ID3D12GraphicsCommandList* pCmdLst1 = m_CommandListRing.GetNewCommandList(); 514 | 515 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Begin Frame"); 516 | 517 | { 518 | auto transition = CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET); 519 | pCmdLst1->ResourceBarrier(1, &transition); 520 | } 521 | 522 | // Render shadow maps 523 | std::vector ShadowReadBarriers; 524 | std::vector ShadowWriteBarriers; 525 | if (m_GLTFDepth && pPerFrame != NULL) 526 | { 527 | std::vector::iterator ShadowMap = m_shadowMapPool.begin(); 528 | while (ShadowMap < m_shadowMapPool.end()) 529 | { 530 | pCmdLst1->ClearDepthStencilView(m_ShadowMapPoolDSV.GetCPU(ShadowMap->ShadowIndex), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); 531 | ++ShadowMap; 532 | } 533 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Clear shadow maps"); 534 | 535 | // Render all shadows 536 | ShadowMap = m_shadowMapPool.begin(); 537 | while (ShadowMap < m_shadowMapPool.end()) 538 | { 539 | SetViewportAndScissor(pCmdLst1, 0, 0, ShadowMap->ShadowResolution, ShadowMap->ShadowResolution); 540 | 541 | auto handle = m_ShadowMapPoolDSV.GetCPU(ShadowMap->ShadowIndex); 542 | pCmdLst1->OMSetRenderTargets(0, NULL, false, &handle); 543 | 544 | per_frame* cbDepthPerFrame = m_GLTFDepth->SetPerFrameConstants(); 545 | cbDepthPerFrame->mCameraCurrViewProj = pPerFrame->lights[ShadowMap->LightIndex].mLightViewProj; 546 | cbDepthPerFrame->lodBias = 0.0f; 547 | 548 | m_GLTFDepth->Draw(pCmdLst1); 549 | 550 | // Push a barrier 551 | ShadowReadBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(ShadowMap->ShadowMap.GetResource(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); 552 | ShadowWriteBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(ShadowMap->ShadowMap.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); 553 | 554 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Shadow map"); 555 | ++ShadowMap; 556 | } 557 | 558 | // Transition all shadow map barriers 559 | pCmdLst1->ResourceBarrier((UINT)ShadowReadBarriers.size(), ShadowReadBarriers.data()); 560 | } 561 | 562 | // Shadow resolve --------------------------------------------------------------------------- 563 | #if USE_SHADOWMASK 564 | if (pPerFrame != NULL) 565 | { 566 | const D3D12_RESOURCE_BARRIER preShadowResolve[] = 567 | { 568 | CD3DX12_RESOURCE_BARRIER::Transition(m_ShadowMask.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS), 569 | CD3DX12_RESOURCE_BARRIER::Transition(m_MotionVectorsDepthMap.GetResource(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) 570 | }; 571 | pCmdLst1->ResourceBarrier(ARRAYSIZE(preShadowResolve), preShadowResolve); 572 | 573 | ShadowResolveFrame shadowResolveFrame; 574 | shadowResolveFrame.m_Width = m_Width; 575 | shadowResolveFrame.m_Height = m_Height; 576 | shadowResolveFrame.m_ShadowMapSRV = m_ShadowMapSRV; 577 | shadowResolveFrame.m_DepthBufferSRV = m_MotionVectorsDepthMapSRV; 578 | shadowResolveFrame.m_ShadowBufferUAV = m_ShadowMaskUAV; 579 | 580 | m_shadowResolve.Draw(pCmdLst1, m_pGLTFTexturesAndBuffers, &shadowResolveFrame); 581 | 582 | const D3D12_RESOURCE_BARRIER postShadowResolve[] = 583 | { 584 | CD3DX12_RESOURCE_BARRIER::Transition(m_ShadowMask.GetResource(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), 585 | CD3DX12_RESOURCE_BARRIER::Transition(m_MotionVectorsDepthMap.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE) 586 | }; 587 | pCmdLst1->ResourceBarrier(ARRAYSIZE(postShadowResolve), postShadowResolve); 588 | } 589 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Shadow resolve"); 590 | #endif 591 | 592 | // Rasterize Scene to the VBuffer --------------------------------------------- 593 | if (pPerFrame != NULL) 594 | { 595 | if (m_GLTFRasterizer && !pState->disable) 596 | { 597 | UINT clearValueI[4] = { 0x3F800000 /* 1.0f */, 0, 0, 0}; 598 | pCmdLst1->ClearUnorderedAccessViewUint(m_VBufferUAV.GetGPU(), m_VBufferUAVCPU.GetCPU(), m_VBuffer.GetResource(), clearValueI, 0, nullptr); 599 | 600 | m_GLTFRasterizer->ReCreate( 601 | pState->numberOfBins, pState->homogeneous, pState->showBins, pState->fixedExpansion, pState->threadLaunch, pState->feedback 602 | ); 603 | 604 | m_GLTFRasterizer->SetPerFrameSceneGraph(); 605 | *m_GLTFRasterizer->SetPerFrameConstants() = *pPerFrame; 606 | 607 | m_GLTFRasterizer->Draw(pCmdLst1, pState->submissionMode); 608 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Rasterize"); 609 | } 610 | } 611 | 612 | // Render Scene to the GBuffer ------------------------------------------------ 613 | if (pPerFrame != NULL) 614 | { 615 | pCmdLst1->RSSetViewports(1, &m_Viewport); 616 | pCmdLst1->RSSetScissorRects(1, &m_RectScissor); 617 | 618 | if (m_GLTFPBR) 619 | { 620 | const bool bWireframe = pState->WireframeMode != UIState::WireframeMode::WIREFRAME_MODE_OFF; 621 | 622 | std::vector opaque, transparent; 623 | m_GLTFPBR->BuildBatchLists(&opaque, &transparent, bWireframe); 624 | 625 | // Render opaque geometry 626 | { 627 | m_RenderPassFullGBuffer.BeginPass(pCmdLst1, true); 628 | #if USE_SHADOWMASK 629 | m_GLTFPBR->DrawBatchList(pCmdLst1, &m_ShadowMaskSRV, &solid, bWireframe); 630 | #else 631 | m_GLTFPBR->DrawBatchList(pCmdLst1, &m_ShadowMapPoolSRV, &opaque, bWireframe); 632 | #endif 633 | m_GPUTimer.GetTimeStamp(pCmdLst1, "PBR Opaque"); 634 | m_RenderPassFullGBuffer.EndPass(); 635 | } 636 | 637 | // draw skydome 638 | { 639 | m_RenderPassJustDepthAndHdr.BeginPass(pCmdLst1, false); 640 | 641 | // Render skydome 642 | if (pState->SelectedSkydomeTypeIndex == 1) 643 | { 644 | math::Matrix4 clipToView = math::inverse(pPerFrame->mCameraCurrViewProj); 645 | m_SkyDome.Draw(pCmdLst1, clipToView); 646 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Skydome cube"); 647 | } 648 | else if (pState->SelectedSkydomeTypeIndex == 0) 649 | { 650 | SkyDomeProc::Constants skyDomeConstants; 651 | skyDomeConstants.invViewProj = math::inverse(pPerFrame->mCameraCurrViewProj); 652 | skyDomeConstants.vSunDirection = math::Vector4(1.0f, 0.05f, 0.0f, 0.0f); 653 | skyDomeConstants.turbidity = 10.0f; 654 | skyDomeConstants.rayleigh = 2.0f; 655 | skyDomeConstants.mieCoefficient = 0.005f; 656 | skyDomeConstants.mieDirectionalG = 0.8f; 657 | skyDomeConstants.luminance = 1.0f; 658 | m_SkyDomeProc.Draw(pCmdLst1, skyDomeConstants); 659 | 660 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Skydome proc"); 661 | } 662 | 663 | m_RenderPassJustDepthAndHdr.EndPass(); 664 | } 665 | 666 | // draw transparent geometry 667 | { 668 | m_RenderPassFullGBuffer.BeginPass(pCmdLst1, false); 669 | 670 | std::sort(transparent.begin(), transparent.end()); 671 | m_GLTFPBR->DrawBatchList(pCmdLst1, &m_ShadowMapPoolSRV, &transparent, bWireframe); 672 | m_GPUTimer.GetTimeStamp(pCmdLst1, "PBR Transparent"); 673 | 674 | m_RenderPassFullGBuffer.EndPass(); 675 | } 676 | } 677 | 678 | // draw object's bounding boxes 679 | if (m_GLTFBBox && pPerFrame != NULL) 680 | { 681 | if (pState->bDrawBoundingBoxes) 682 | { 683 | m_GLTFBBox->Draw(pCmdLst1, pPerFrame->mCameraCurrViewProj); 684 | 685 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Bounding Box"); 686 | } 687 | } 688 | 689 | // draw light's frustums 690 | if (pState->bDrawLightFrustum && pPerFrame != NULL) 691 | { 692 | UserMarker marker(pCmdLst1, "light frustrums"); 693 | 694 | math::Vector4 vCenter = math::Vector4(0.0f, 0.0f, 0.5f, 0.0f); 695 | math::Vector4 vRadius = math::Vector4(1.0f, 1.0f, 0.5f, 0.0f); 696 | math::Vector4 vColor = math::Vector4(1.0f, 1.0f, 1.0f, 1.0f); 697 | for (uint32_t i = 0; i < pPerFrame->lightCount; i++) 698 | { 699 | math::Matrix4 spotlightMatrix = math::inverse(pPerFrame->lights[i].mLightViewProj); // XMMatrixInverse(NULL, pPerFrame->lights[i].mLightViewProj); 700 | math::Matrix4 worldMatrix = pPerFrame->mCameraCurrViewProj * spotlightMatrix; //spotlightMatrix * pPerFrame->mCameraCurrViewProj; 701 | m_WireframeBox.Draw(pCmdLst1, &m_Wireframe, worldMatrix, vCenter, vRadius, vColor); 702 | } 703 | 704 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Light's frustum"); 705 | } 706 | } 707 | 708 | // Debug-view for z-buffer rasterizer 709 | if (!pState->disable) 710 | { 711 | D3D12_RESOURCE_BARRIER preResolve[1] = { 712 | CD3DX12_RESOURCE_BARRIER::Transition(m_VBuffer.GetResource(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), 713 | }; 714 | pCmdLst1->ResourceBarrier(1, preResolve); 715 | 716 | m_Debug.Draw(pCmdLst1, &m_VBufferSRV, pState->showBins); 717 | 718 | D3D12_RESOURCE_BARRIER postResolve[1] = { 719 | CD3DX12_RESOURCE_BARRIER::Transition(m_VBuffer.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS), 720 | }; 721 | pCmdLst1->ResourceBarrier(1, postResolve); 722 | } 723 | 724 | if (ShadowWriteBarriers.size()) 725 | pCmdLst1->ResourceBarrier((UINT)ShadowWriteBarriers.size(), ShadowWriteBarriers.data()); 726 | 727 | D3D12_RESOURCE_BARRIER preResolve[1] = { 728 | CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), 729 | }; 730 | pCmdLst1->ResourceBarrier(1, preResolve); 731 | 732 | // Post proc--------------------------------------------------------------------------- 733 | 734 | // Bloom, takes HDR as input and applies bloom to it. 735 | { 736 | D3D12_CPU_DESCRIPTOR_HANDLE renderTargets[] = { m_GBuffer.m_HDRRTV.GetCPU() }; 737 | pCmdLst1->OMSetRenderTargets(ARRAYSIZE(renderTargets), renderTargets, false, NULL); 738 | 739 | m_DownSample.Draw(pCmdLst1); 740 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Downsample"); 741 | 742 | m_Bloom.Draw(pCmdLst1, &m_GBuffer.m_HDR); 743 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Bloom"); 744 | } 745 | 746 | // Apply TAA & Sharpen to m_HDR 747 | if (pState->bUseTAA) 748 | { 749 | m_TAA.Draw(pCmdLst1, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); 750 | m_GPUTimer.GetTimeStamp(pCmdLst1, "TAA"); 751 | } 752 | 753 | // Magnifier Pass: m_HDR as input, pass' own output 754 | if (pState->bUseMagnifier) 755 | { 756 | // Note: assumes m_GBuffer.HDR is in D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE 757 | m_MagnifierPS.Draw(pCmdLst1, pState->MagnifierParams, m_GBuffer.m_HDRSRV); 758 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Magnifier"); 759 | 760 | // Transition magnifier state to PIXEL_SHADER_RESOURCE, as it is going to be pRscCurrentInput replacing m_GBuffer.m_HDR which is in that state. 761 | auto transition = CD3DX12_RESOURCE_BARRIER::Transition(m_MagnifierPS.GetPassOutputResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); 762 | pCmdLst1->ResourceBarrier(1, &transition); 763 | } 764 | 765 | // Start tracking input/output resources at this point to handle HDR and SDR render paths 766 | ID3D12Resource* pRscCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputResource() : m_GBuffer.m_HDR.GetResource(); 767 | CBV_SRV_UAV SRVCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputSRV() : m_GBuffer.m_HDRSRV; 768 | D3D12_CPU_DESCRIPTOR_HANDLE RTVCurrentOutput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputRTV().GetCPU() : m_GBuffer.m_HDRRTV.GetCPU(); 769 | CBV_SRV_UAV UAVCurrentOutput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputUAV() : m_GBuffer.m_HDRUAV; 770 | 771 | // If using FreeSync HDR we need to do the tonemapping in-place and then apply the GUI, later we'll apply the color conversion into the swapchain 772 | const bool bHDR = pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR; 773 | if (bHDR) 774 | { 775 | // In place Tonemapping ------------------------------------------------------------------------ 776 | { 777 | D3D12_RESOURCE_BARRIER inputRscToUAV = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 778 | pCmdLst1->ResourceBarrier(1, &inputRscToUAV); 779 | 780 | m_ToneMappingCS.Draw(pCmdLst1, &UAVCurrentOutput, pState->Exposure, pState->SelectedTonemapperIndex, m_Width, m_Height); 781 | 782 | D3D12_RESOURCE_BARRIER inputRscToRTV = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RENDER_TARGET); 783 | pCmdLst1->ResourceBarrier(1, &inputRscToRTV); 784 | } 785 | 786 | // Render HUD ------------------------------------------------------------------------ 787 | { 788 | pCmdLst1->RSSetViewports(1, &m_Viewport); 789 | pCmdLst1->RSSetScissorRects(1, &m_RectScissor); 790 | pCmdLst1->OMSetRenderTargets(1, &RTVCurrentOutput, true, NULL); 791 | 792 | m_ImGUI.Draw(pCmdLst1); 793 | 794 | D3D12_RESOURCE_BARRIER hdrToSRV = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); 795 | pCmdLst1->ResourceBarrier(1, &hdrToSRV); 796 | 797 | m_GPUTimer.GetTimeStamp(pCmdLst1, "ImGUI Rendering"); 798 | } 799 | } 800 | 801 | // submit command buffer #1 802 | ThrowIfFailed(pCmdLst1->Close()); 803 | ID3D12CommandList* CmdListList1[] = { pCmdLst1 }; 804 | m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList1); 805 | 806 | // Wait for swapchain (we are going to render to it) ----------------------------------- 807 | pSwapChain->WaitForSwapChain(); 808 | 809 | // Keep tracking input/output resource views 810 | pRscCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputResource() : m_GBuffer.m_HDR.GetResource(); // these haven't changed, re-assign as sanity check 811 | SRVCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputSRV() : m_GBuffer.m_HDRSRV; // these haven't changed, re-assign as sanity check 812 | RTVCurrentOutput = *pSwapChain->GetCurrentBackBufferRTV(); 813 | UAVCurrentOutput = {}; // no BackBufferUAV. 814 | 815 | ID3D12GraphicsCommandList* pCmdLst2 = m_CommandListRing.GetNewCommandList(); 816 | 817 | pCmdLst2->RSSetViewports(1, &m_Viewport); 818 | pCmdLst2->RSSetScissorRects(1, &m_RectScissor); 819 | pCmdLst2->OMSetRenderTargets(1, pSwapChain->GetCurrentBackBufferRTV(), true, NULL); 820 | 821 | if (bHDR) 822 | { 823 | // FS HDR mode! Apply color conversion now. 824 | m_ColorConversionPS.Draw(pCmdLst2, &SRVCurrentInput); 825 | m_GPUTimer.GetTimeStamp(pCmdLst2, "Color conversion"); 826 | 827 | auto transition = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); 828 | pCmdLst2->ResourceBarrier(1, &transition); 829 | } 830 | else 831 | { 832 | // non FreeSync HDR mode, that is SDR, here we apply the tonemapping from the HDR into the swapchain and then we render the GUI 833 | 834 | // Tonemapping ------------------------------------------------------------------------ 835 | { 836 | m_ToneMappingPS.Draw(pCmdLst2, &SRVCurrentInput, pState->Exposure, pState->SelectedTonemapperIndex); 837 | m_GPUTimer.GetTimeStamp(pCmdLst2, "Tone mapping"); 838 | 839 | auto transition = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); 840 | pCmdLst2->ResourceBarrier(1, &transition); 841 | } 842 | 843 | // Render HUD ------------------------------------------------------------------------ 844 | { 845 | m_ImGUI.Draw(pCmdLst2); 846 | m_GPUTimer.GetTimeStamp(pCmdLst2, "ImGUI Rendering"); 847 | } 848 | } 849 | 850 | // If magnifier is used, make sure m_GBuffer.m_HDR which is not pRscCurrentInput gets reverted back to RT state. 851 | if (pState->bUseMagnifier) 852 | { 853 | auto transition = CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET); 854 | pCmdLst2->ResourceBarrier(1, &transition); 855 | } 856 | 857 | if (!m_pScreenShotName.empty()) 858 | { 859 | m_SaveTexture.CopyRenderTargetIntoStagingTexture(m_pDevice->GetDevice(), pCmdLst2, pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_RENDER_TARGET); 860 | } 861 | 862 | // Transition swapchain into present mode 863 | { 864 | auto transition = CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT); 865 | pCmdLst2->ResourceBarrier(1, &transition); 866 | } 867 | 868 | m_GPUTimer.OnEndFrame(); 869 | 870 | m_GPUTimer.CollectTimings(pCmdLst2); 871 | 872 | // Close & Submit the command list #2 ------------------------------------------------- 873 | ThrowIfFailed(pCmdLst2->Close()); 874 | 875 | ID3D12CommandList* CmdListList2[] = { pCmdLst2 }; 876 | m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList2); 877 | 878 | // Handle screenshot request 879 | if (!m_pScreenShotName.empty()) 880 | { 881 | m_SaveTexture.SaveStagingTextureAsJpeg(m_pDevice->GetDevice(), m_pDevice->GetGraphicsQueue(), m_pScreenShotName.c_str()); 882 | m_pScreenShotName.clear(); 883 | } 884 | } 885 | -------------------------------------------------------------------------------- /src/DX12/Renderer.h: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2024 Advanced Micro Devices, Inc.All rights reserved. 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files(the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions : 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | // THE SOFTWARE. 19 | #pragma once 20 | 21 | #include "stdafx.h" 22 | 23 | #include "base/GBuffer.h" 24 | #include "PostProc/MagnifierPS.h" 25 | #include "PostProc/Debug.h" 26 | 27 | struct UIState; 28 | 29 | // We are queuing (backBufferCount + 0.5) frames, so we need to triple buffer the resources that get modified each frame 30 | static const int backBufferCount = 3; 31 | 32 | #define USE_SHADOWMASK false 33 | 34 | using namespace CAULDRON_DX12; 35 | 36 | // 37 | // Renderer class is responsible for rendering resources management and recording command buffers. 38 | class Renderer 39 | { 40 | public: 41 | void OnCreate(Device* pDevice, SwapChain *pSwapChain, float FontSize); 42 | void OnDestroy(); 43 | 44 | void OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height); 45 | void OnDestroyWindowSizeDependentResources(); 46 | 47 | void OnUpdateDisplayDependentResources(SwapChain *pSwapChain); 48 | 49 | int LoadScene(GLTFCommon *pGLTFCommon, int Stage = 0); 50 | void UnloadScene(); 51 | 52 | void AllocateShadowMaps(GLTFCommon* pGLTFCommon); 53 | 54 | const std::vector& GetTimingValues() const { return m_TimeStamps; } 55 | std::string& GetScreenshotFileName() { return m_pScreenShotName; } 56 | 57 | void OnRender(const UIState* pState, const Camera& Cam, SwapChain* pSwapChain); 58 | 59 | private: 60 | Device *m_pDevice; 61 | 62 | uint32_t m_Width; 63 | uint32_t m_Height; 64 | D3D12_VIEWPORT m_Viewport; 65 | D3D12_RECT m_RectScissor; 66 | bool m_HasTAA = false; 67 | 68 | // Initialize helper classes 69 | ResourceViewHeaps m_ResourceViewHeaps; 70 | UploadHeap m_UploadHeap; 71 | DynamicBufferRing m_ConstantBufferRing; 72 | StaticBufferPool m_VidMemBufferPool; 73 | CommandListRing m_CommandListRing; 74 | GPUTimestamps m_GPUTimer; 75 | 76 | //gltf passes 77 | GltfPbrPass *m_GLTFPBR; 78 | GltfBBoxPass *m_GLTFBBox; 79 | GltfDepthPass *m_GLTFDepth; 80 | GltfRasterizerPass *m_GLTFRasterizer; 81 | GLTFTexturesAndBuffers *m_pGLTFTexturesAndBuffers; 82 | 83 | // effects 84 | Bloom m_Bloom; 85 | SkyDome m_SkyDome; 86 | DownSamplePS m_DownSample; 87 | SkyDomeProc m_SkyDomeProc; 88 | ToneMapping m_ToneMappingPS; 89 | ToneMappingCS m_ToneMappingCS; 90 | ColorConversionPS m_ColorConversionPS; 91 | TAA m_TAA; 92 | MagnifierPS m_MagnifierPS; 93 | Debug m_Debug; 94 | 95 | // GUI 96 | ImGUI m_ImGUI; 97 | 98 | // Temporary render targets 99 | GBuffer m_GBuffer; 100 | GBufferRenderPass m_RenderPassFullGBuffer; 101 | GBufferRenderPass m_RenderPassJustDepthAndHdr; 102 | 103 | Texture m_MotionVectorsDepthMap; 104 | DSV m_MotionVectorsDepthMapDSV; 105 | CBV_SRV_UAV m_MotionVectorsDepthMapSRV; 106 | 107 | Texture m_VBuffer; // visibility-buffer for z-buffer rasterizer 108 | CBV_SRV_UAV m_VBufferSRV; 109 | CBV_SRV_UAV m_VBufferUAV; 110 | CBV_SRV_UAV m_VBufferUAVCPU; 111 | 112 | #if USE_SHADOWMASK 113 | // shadow mask 114 | Texture m_ShadowMask; 115 | CBV_SRV_UAV m_ShadowMaskUAV; 116 | CBV_SRV_UAV m_ShadowMaskSRV; 117 | ShadowResolvePass m_shadowResolve; 118 | #endif 119 | 120 | // shadowmaps 121 | typedef struct { 122 | Texture ShadowMap; 123 | uint32_t ShadowIndex; 124 | uint32_t ShadowResolution; 125 | uint32_t LightIndex; 126 | } SceneShadowInfo; 127 | 128 | std::vector m_shadowMapPool; 129 | DSV m_ShadowMapPoolDSV; 130 | CBV_SRV_UAV m_ShadowMapPoolSRV; 131 | 132 | // widgets 133 | Wireframe m_Wireframe; 134 | WireframeBox m_WireframeBox; 135 | 136 | std::vector m_TimeStamps; 137 | 138 | // screen shot 139 | std::string m_pScreenShotName = ""; 140 | SaveTexture m_SaveTexture; 141 | AsyncPool m_AsyncPool; 142 | 143 | // native D3D12Device8 for work graphs 144 | ID3D12Device8 *m_pDevice8Native; 145 | }; 146 | -------------------------------------------------------------------------------- /src/DX12/UI.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2024 Advanced Micro Devices, Inc.All rights reserved. 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files(the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions : 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | // THE SOFTWARE. 19 | 20 | #include "UI.h" 21 | #include "GLTFSample.h" 22 | #include "imgui.h" 23 | #include "base/FrameworkWindows.h" 24 | 25 | // To use the 'disabled UI state' functionality (ImGuiItemFlags_Disabled), include internal header 26 | // https://github.com/ocornut/imgui/issues/211#issuecomment-339241929 27 | #include "imgui_internal.h" 28 | static void DisableUIStateBegin(const bool& bEnable) 29 | { 30 | if (!bEnable) 31 | { 32 | ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); 33 | ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); 34 | } 35 | }; 36 | static void DisableUIStateEnd(const bool& bEnable) 37 | { 38 | if (!bEnable) 39 | { 40 | ImGui::PopItemFlag(); 41 | ImGui::PopStyleVar(); 42 | } 43 | }; 44 | 45 | // Some constants and utility functions 46 | static constexpr float MAGNIFICATION_AMOUNT_MIN = 1.0f; 47 | static constexpr float MAGNIFICATION_AMOUNT_MAX = 32.0f; 48 | static constexpr float MAGNIFIER_RADIUS_MIN = 0.01f; 49 | static constexpr float MAGNIFIER_RADIUS_MAX = 0.85f; 50 | static constexpr float MAGNIFIER_BORDER_COLOR__LOCKED[3] = { 0.002f, 0.72f, 0.0f }; // G 51 | static constexpr float MAGNIFIER_BORDER_COLOR__FREE [3] = { 0.72f, 0.002f, 0.0f }; // R 52 | template static T clamped(const T& v, const T& min, const T& max) 53 | { 54 | if (v < min) return min; 55 | else if (v > max) return max; 56 | else return v; 57 | } 58 | 59 | 60 | 61 | void GLTFSample::BuildUI() 62 | { 63 | // if we haven't initialized GLTFLoader yet, don't draw UI. 64 | if (m_pGltfLoader == nullptr) 65 | { 66 | LoadScene(m_activeScene); 67 | return; 68 | } 69 | 70 | ImGuiIO& io = ImGui::GetIO(); 71 | ImGuiStyle& style = ImGui::GetStyle(); 72 | style.FrameBorderSize = 1.0f; 73 | 74 | const uint32_t W = this->GetWidth(); 75 | const uint32_t H = this->GetHeight(); 76 | 77 | const uint32_t PROFILER_WINDOW_PADDIG_X = 10; 78 | const uint32_t PROFILER_WINDOW_PADDIG_Y = 10; 79 | const uint32_t PROFILER_WINDOW_SIZE_X = 330; 80 | const uint32_t PROFILER_WINDOW_SIZE_Y = 450; 81 | const uint32_t PROFILER_WINDOW_POS_X = W - PROFILER_WINDOW_PADDIG_X - PROFILER_WINDOW_SIZE_X; 82 | const uint32_t PROFILER_WINDOW_POS_Y = PROFILER_WINDOW_PADDIG_Y; 83 | 84 | const uint32_t CONTROLS_WINDOW_POS_X = 10; 85 | const uint32_t CONTROLS_WINDOW_POS_Y = 10; 86 | const uint32_t CONTROLW_WINDOW_SIZE_X = 350; 87 | const uint32_t CONTROLW_WINDOW_SIZE_Y = 780; // assuming > 720p 88 | 89 | // Render CONTROLS window 90 | // 91 | ImGui::SetNextWindowPos(ImVec2(CONTROLS_WINDOW_POS_X, CONTROLS_WINDOW_POS_Y), ImGuiCond_FirstUseEver); 92 | ImGui::SetNextWindowSize(ImVec2(CONTROLW_WINDOW_SIZE_X, CONTROLW_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); 93 | 94 | if (m_UIState.bShowControlsWindow) 95 | { 96 | ImGui::Begin("CONTROLS (F1)", &m_UIState.bShowControlsWindow); 97 | if (ImGui::CollapsingHeader("Animation", 0)) 98 | { 99 | ImGui::Checkbox("Play", &m_bPlay); 100 | ImGui::SliderFloat("Time", &m_time, 0, 30); 101 | } 102 | 103 | ImGui::Spacing(); 104 | ImGui::Spacing(); 105 | 106 | if (ImGui::CollapsingHeader("Scene", ImGuiTreeNodeFlags_DefaultOpen)) 107 | { 108 | const char* cameraControl[] = { "Orbit", "WASD", "cam #0", "cam #1", "cam #2", "cam #3" , "cam #4", "cam #5" }; 109 | 110 | if (m_activeCamera >= m_pGltfLoader->m_cameras.size() + 2) 111 | m_activeCamera = 0; 112 | ImGui::Combo("Camera", &m_activeCamera, cameraControl, min((int)(m_pGltfLoader->m_cameras.size() + 2), _countof(cameraControl))); 113 | 114 | auto getterLambda = [](void* data, int idx, const char** out_str)->bool { *out_str = ((std::vector *)data)->at(idx).c_str(); return true; }; 115 | if (ImGui::Combo("Model", &m_activeScene, getterLambda, &m_sceneNames, (int)m_sceneNames.size())) 116 | { 117 | // Note: 118 | // probably queueing this as an event and handling it at the end/beginning 119 | // of frame is a better idea rather than in the middle of drawing UI. 120 | LoadScene(m_activeScene); 121 | 122 | //bail out as we need to reload everything 123 | ImGui::End(); 124 | ImGui::EndFrame(); 125 | ImGui::NewFrame(); 126 | return; 127 | } 128 | 129 | ImGui::SliderFloat("Emissive Intensity", &m_UIState.EmissiveFactor, 1.0f, 1000.0f, NULL, 1.0f); 130 | 131 | const char* skyDomeType[] = { "Procedural Sky", "Environment Map", "Clear" }; 132 | ImGui::Combo("Skydome", &m_UIState.SelectedSkydomeTypeIndex, skyDomeType, _countof(skyDomeType)); 133 | 134 | ImGui::SliderFloat("IBL Factor", &m_UIState.IBLFactor, 0.0f, 3.0f); 135 | for (int i = 0; i < m_pGltfLoader->m_lights.size(); i++) 136 | { 137 | ImGui::SliderFloat(format("Light %i Intensity", i).c_str(), &m_pGltfLoader->m_lights[i].m_intensity, 0.0f, 50.0f); 138 | } 139 | if (ImGui::Button("Set Spot Light 0 to Camera's View")) 140 | { 141 | int idx = m_pGltfLoader->m_lightInstances[0].m_nodeIndex; 142 | m_pGltfLoader->m_nodes[idx].m_tranform.LookAt(m_camera.GetPosition(), m_camera.GetPosition() - m_camera.GetDirection()); 143 | m_pGltfLoader->m_animatedMats[idx] = m_pGltfLoader->m_nodes[idx].m_tranform.GetWorldMat(); 144 | } 145 | } 146 | 147 | ImGui::Spacing(); 148 | ImGui::Spacing(); 149 | 150 | if (ImGui::CollapsingHeader("PostProcessing", 0)) 151 | { 152 | const char* tonemappers[] = { "AMD Tonemapper", "DX11DSK", "Reinhard", "Uncharted2Tonemap", "ACES", "No tonemapper" }; 153 | ImGui::Combo("Tonemapper", &m_UIState.SelectedTonemapperIndex, tonemappers, _countof(tonemappers)); 154 | 155 | ImGui::SliderFloat("Exposure", &m_UIState.Exposure, 0.0f, 4.0f); 156 | 157 | ImGui::Checkbox("TAA", &m_UIState.bUseTAA); 158 | } 159 | 160 | ImGui::Spacing(); 161 | ImGui::Spacing(); 162 | 163 | if (ImGui::CollapsingHeader("Magnifier", 0)) 164 | { 165 | // read in Magnifier pass parameters from the UI & app state 166 | MagnifierPS::PassParameters& params = m_UIState.MagnifierParams; 167 | params.uImageHeight = m_Height; 168 | params.uImageWidth = m_Width; 169 | params.iMousePos[0] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionX : static_cast(io.MousePos.x); 170 | params.iMousePos[1] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionY : static_cast(io.MousePos.y); 171 | 172 | ImGui::Checkbox("Show Magnifier (M)", &m_UIState.bUseMagnifier); 173 | 174 | DisableUIStateBegin(m_UIState.bUseMagnifier); 175 | { 176 | // Use a local bool state here to track locked state through the UI widget, 177 | // and then call ToggleMagnifierLockedState() to update the persistent state (m_UIstate). 178 | // The keyboard input for toggling lock directly operates on the persistent state. 179 | const bool bIsMagnifierCurrentlyLocked = m_UIState.bLockMagnifierPosition; 180 | bool bMagnifierToggle = bIsMagnifierCurrentlyLocked; 181 | ImGui::Checkbox("Lock Position (L)", &bMagnifierToggle); 182 | 183 | if (bMagnifierToggle != bIsMagnifierCurrentlyLocked) 184 | m_UIState.ToggleMagnifierLock(); 185 | 186 | ImGui::SliderFloat("Screen Size", ¶ms.fMagnifierScreenRadius, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); 187 | ImGui::SliderFloat("Magnification", ¶ms.fMagnificationAmount, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); 188 | ImGui::SliderInt("OffsetX", ¶ms.iMagnifierOffset[0], -m_Width, m_Width); 189 | ImGui::SliderInt("OffsetY", ¶ms.iMagnifierOffset[1], -m_Height, m_Height); 190 | } 191 | DisableUIStateEnd(m_UIState.bUseMagnifier); 192 | } 193 | 194 | ImGui::Spacing(); 195 | ImGui::Spacing(); 196 | 197 | if (ImGui::CollapsingHeader("Debug", 0)) 198 | { 199 | ImGui::Checkbox("Show Bounding Boxes", &m_UIState.bDrawBoundingBoxes); 200 | ImGui::Checkbox("Show Light Frustum", &m_UIState.bDrawLightFrustum); 201 | 202 | ImGui::Text("Wireframe"); 203 | ImGui::SameLine(); ImGui::RadioButton("Off", (int*)&m_UIState.WireframeMode, (int)UIState::WireframeMode::WIREFRAME_MODE_OFF); 204 | ImGui::SameLine(); ImGui::RadioButton("Shaded", (int*)&m_UIState.WireframeMode, (int)UIState::WireframeMode::WIREFRAME_MODE_SHADED); 205 | ImGui::SameLine(); ImGui::RadioButton("Solid color", (int*)&m_UIState.WireframeMode, (int)UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR); 206 | if (m_UIState.WireframeMode == UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR) 207 | ImGui::ColorEdit3("Wire solid color", m_UIState.WireframeColor, ImGuiColorEditFlags_NoAlpha); 208 | } 209 | 210 | ImGui::Spacing(); 211 | ImGui::Spacing(); 212 | 213 | if (ImGui::CollapsingHeader("Presentation Mode", ImGuiTreeNodeFlags_DefaultOpen)) 214 | { 215 | const char* fullscreenModes[] = { "Windowed", "BorderlessFullscreen", "ExclusiveFullscreen" }; 216 | if (ImGui::Combo("Fullscreen Mode", (int*)&m_fullscreenMode, fullscreenModes, _countof(fullscreenModes))) 217 | { 218 | if (m_previousFullscreenMode != m_fullscreenMode) 219 | { 220 | HandleFullScreen(); 221 | m_previousFullscreenMode = m_fullscreenMode; 222 | } 223 | } 224 | } 225 | 226 | ImGui::Spacing(); 227 | ImGui::Spacing(); 228 | 229 | if (ImGui::CollapsingHeader("Work submission", ImGuiTreeNodeFlags_DefaultOpen)) 230 | { 231 | const char* submissionModes[] = { 232 | "N-Dispatch (single-pass)", 233 | "1-ExecuteIndirect (single-pass)", 234 | "3-ExecuteIndirect (multi-pass)", 235 | #ifdef ENABLE_WORKGRAPHS 236 | "N-DispatchGrid", 237 | "N-DispatchGrid (batched)", 238 | "1-DispatchGrid (indirect node)" 239 | #endif 240 | }; 241 | ImGui::Checkbox("Homogeneous Rast.", &m_UIState.homogeneous); 242 | ImGui::Combo("Execution Mode", (int*)&m_UIState.submissionMode, submissionModes, _countof(submissionModes)); 243 | ImGui::Checkbox("Fixed Exp. Split", &m_UIState.fixedExpansion); 244 | ImGui::Checkbox("Thread launch", &m_UIState.threadLaunch); 245 | ImGui::SliderInt("No. of bins", &m_UIState.numberOfBins, 1, 15); 246 | ImGui::Checkbox("Show bins", &m_UIState.showBins); 247 | ImGui::Checkbox("Smooth timings", &m_UIState.smoothing); 248 | ImGui::Checkbox("Disable rasterizer", &m_UIState.disable); 249 | 250 | ImGui::Text(" "); 251 | ImGui::Text("Objects : %i", m_UIState.feedback[0]); 252 | ImGui::Text("Triangles : %i", m_UIState.feedback[1]); 253 | #ifdef ENABLE_WORKGRAPHS 254 | ImGui::Text("Backing Store : %.3f / %.3f KiB", 1.0f / 1000 * m_UIState.feedback[2], 1.0f / 1000 * m_UIState.feedback[3]); 255 | #endif 256 | ImGui::Text("Multi-Pass Store : %.3f tris / %.3f KiB", 1.0f / 1000 * m_UIState.feedback[4], 1.0f / 1000 * m_UIState.feedback[5]); 257 | } 258 | 259 | ImGui::Spacing(); 260 | ImGui::Spacing(); 261 | 262 | if (m_FreesyncHDROptionEnabled && ImGui::CollapsingHeader("FreeSync HDR", ImGuiTreeNodeFlags_DefaultOpen)) 263 | { 264 | static bool openWarning = false; 265 | const char** displayModeNames = &m_displayModesNamesAvailable[0]; 266 | if (ImGui::Combo("Display Mode", (int*)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) 267 | { 268 | if (m_fullscreenMode != PRESENTATIONMODE_WINDOWED) 269 | { 270 | UpdateDisplay(m_disableLocalDimming); 271 | m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; 272 | } 273 | else if (CheckIfWindowModeHdrOn() && 274 | (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_SDR || 275 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_2084 || 276 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_SCRGB)) 277 | { 278 | UpdateDisplay(m_disableLocalDimming); 279 | m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; 280 | } 281 | else 282 | { 283 | openWarning = true; 284 | m_currentDisplayModeNamesIndex = m_previousDisplayModeNamesIndex; 285 | } 286 | } 287 | 288 | if (openWarning) 289 | { 290 | ImGui::OpenPopup("Display Modes Warning"); 291 | ImGui::BeginPopupModal("Display Modes Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize); 292 | ImGui::Text("\nChanging display modes is only available either using HDR toggle in windows display setting for HDR10 modes or in fullscreen for FS HDR modes\n\n"); 293 | if (ImGui::Button("Cancel", ImVec2(120, 0))) { openWarning = false; ImGui::CloseCurrentPopup(); } 294 | ImGui::EndPopup(); 295 | } 296 | 297 | if (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_Gamma22 || 298 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_SCRGB) 299 | { 300 | static bool selectedDisableLocaldimmingSetting = false; 301 | if (ImGui::Checkbox("Disable Local Dimming", &selectedDisableLocaldimmingSetting)) 302 | UpdateDisplay(selectedDisableLocaldimmingSetting); 303 | } 304 | } 305 | 306 | ImGui::End(); // CONTROLS 307 | } 308 | 309 | 310 | // Render PROFILER window 311 | // 312 | if (m_UIState.bShowProfilerWindow) 313 | { 314 | constexpr size_t NUM_FRAMES = 128; 315 | static float FRAME_TIME_ARRAY[NUM_FRAMES] = { 0 }; 316 | 317 | // track highest frame rate and determine the max value of the graph based on the measured highest value 318 | static float RECENT_HIGHEST_FRAME_TIME = 0.0f; 319 | constexpr int FRAME_TIME_GRAPH_MAX_FPS[] = { 800, 240, 120, 90, 60, 45, 30, 15, 10, 5, 4, 3, 2, 1 }; 320 | static float FRAME_TIME_GRAPH_MAX_VALUES[_countof(FRAME_TIME_GRAPH_MAX_FPS)] = { 0 }; // us 321 | for (int i = 0; i < _countof(FRAME_TIME_GRAPH_MAX_FPS); ++i) { FRAME_TIME_GRAPH_MAX_VALUES[i] = 1000000.f / FRAME_TIME_GRAPH_MAX_FPS[i]; } 322 | 323 | //scrolling data and average FPS computing 324 | const std::vector& timeStamps = m_pRenderer->GetTimingValues(); 325 | const bool bTimeStampsAvailable = timeStamps.size() > 0; 326 | if (bTimeStampsAvailable) 327 | { 328 | RECENT_HIGHEST_FRAME_TIME = 0; 329 | FRAME_TIME_ARRAY[NUM_FRAMES - 1] = timeStamps.back().m_microseconds; 330 | for (uint32_t i = 0; i < NUM_FRAMES - 1; i++) 331 | { 332 | FRAME_TIME_ARRAY[i] = FRAME_TIME_ARRAY[i + 1]; 333 | } 334 | RECENT_HIGHEST_FRAME_TIME = max(RECENT_HIGHEST_FRAME_TIME, FRAME_TIME_ARRAY[NUM_FRAMES - 1]); 335 | } 336 | const float& frameTime_us = FRAME_TIME_ARRAY[NUM_FRAMES - 1]; 337 | const float frameTime_ms = frameTime_us * 0.001f; 338 | const int fps = bTimeStampsAvailable ? static_cast(1000000.0f / frameTime_us) : 0; 339 | 340 | // UI 341 | ImGui::SetNextWindowPos(ImVec2((float)PROFILER_WINDOW_POS_X, (float)PROFILER_WINDOW_POS_Y), ImGuiCond_FirstUseEver); 342 | ImGui::SetNextWindowSize(ImVec2(PROFILER_WINDOW_SIZE_X, PROFILER_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); 343 | ImGui::Begin("PROFILER (F2)", &m_UIState.bShowProfilerWindow); 344 | 345 | ImGui::Text("Resolution : %ix%i", m_Width, m_Height); 346 | ImGui::Text("API : %s", m_systemInfo.mGfxAPI.c_str()); 347 | ImGui::Text("GPU : %s", m_systemInfo.mGPUName.c_str()); 348 | ImGui::Text("CPU : %s", m_systemInfo.mCPUName.c_str()); 349 | ImGui::Text("FPS : %d (%.2f ms)", fps, frameTime_ms); 350 | 351 | if (ImGui::CollapsingHeader("GPU Timings", ImGuiTreeNodeFlags_DefaultOpen)) 352 | { 353 | std::string msOrUsButtonText = m_UIState.bShowMilliseconds ? "Switch to microseconds" : "Switch to milliseconds"; 354 | if (ImGui::Button(msOrUsButtonText.c_str())) { 355 | m_UIState.bShowMilliseconds = !m_UIState.bShowMilliseconds; 356 | } 357 | ImGui::Spacing(); 358 | 359 | if (m_isCpuValidationLayerEnabled || m_isGpuValidationLayerEnabled) 360 | { 361 | ImGui::TextColored(ImVec4(1,1,0,1), "WARNING: Validation layer is switched on"); 362 | ImGui::Text("Performance numbers may be inaccurate!"); 363 | } 364 | 365 | // find the index of the FrameTimeGraphMaxValue as the next higher-than-recent-highest-frame-time in the pre-determined value list 366 | size_t iFrameTimeGraphMaxValue = 0; 367 | for (int i = 0; i < _countof(FRAME_TIME_GRAPH_MAX_VALUES); ++i) 368 | { 369 | if (RECENT_HIGHEST_FRAME_TIME < FRAME_TIME_GRAPH_MAX_VALUES[i]) // FRAME_TIME_GRAPH_MAX_VALUES are in increasing order 370 | { 371 | iFrameTimeGraphMaxValue = min(_countof(FRAME_TIME_GRAPH_MAX_VALUES) - 1, i + 1); 372 | break; 373 | } 374 | } 375 | ImGui::PlotLines("", FRAME_TIME_ARRAY, NUM_FRAMES, 0, "GPU frame time (us)", 0.0f, FRAME_TIME_GRAPH_MAX_VALUES[iFrameTimeGraphMaxValue], ImVec2(0, 80)); 376 | 377 | for (uint32_t i = 0; i < timeStamps.size(); i++) 378 | { 379 | float value = m_UIState.bShowMilliseconds ? timeStamps[i].m_microseconds / 1000.0f : timeStamps[i].m_microseconds; 380 | const char* pStrUnit = m_UIState.bShowMilliseconds ? "ms" : "us"; 381 | ImGui::Text("%-18s: %7.2f %s", timeStamps[i].m_label.c_str(), value, pStrUnit); 382 | } 383 | } 384 | ImGui::End(); // PROFILER 385 | } 386 | } 387 | 388 | void UIState::Initialize() 389 | { 390 | // init magnifier params 391 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; // start at 'free' state 392 | 393 | // init GUI state 394 | this->SelectedTonemapperIndex = 0; 395 | this->bUseTAA = false; 396 | this->bUseMagnifier = false; 397 | this->bLockMagnifierPosition = this->bLockMagnifierPositionHistory = false; 398 | this->SelectedSkydomeTypeIndex = 0; 399 | this->Exposure = 1.0f; 400 | this->IBLFactor = 2.0f; 401 | this->EmissiveFactor = 1.0f; 402 | this->bDrawLightFrustum = false; 403 | this->bDrawBoundingBoxes = false; 404 | this->submissionMode = 0; 405 | this->numberOfBins = 12; 406 | this->homogeneous = true; 407 | this->showBins = true; 408 | this->fixedExpansion = false; 409 | this->threadLaunch = true; 410 | this->smoothing = false; 411 | this->disable = false; 412 | this->WireframeMode = WireframeMode::WIREFRAME_MODE_OFF; 413 | this->WireframeColor[0] = 0.0f; 414 | this->WireframeColor[1] = 1.0f; 415 | this->WireframeColor[2] = 0.0f; 416 | this->bShowControlsWindow = true; 417 | this->bShowProfilerWindow = true; 418 | } 419 | 420 | 421 | 422 | // 423 | // Magnifier UI Controls 424 | // 425 | void UIState::ToggleMagnifierLock() 426 | { 427 | if (this->bUseMagnifier) 428 | { 429 | this->bLockMagnifierPositionHistory = this->bLockMagnifierPosition; // record histroy 430 | this->bLockMagnifierPosition = !this->bLockMagnifierPosition; // flip state 431 | const bool bLockSwitchedOn = !this->bLockMagnifierPositionHistory && this->bLockMagnifierPosition; 432 | const bool bLockSwitchedOff = this->bLockMagnifierPositionHistory && !this->bLockMagnifierPosition; 433 | if (bLockSwitchedOn) 434 | { 435 | const ImGuiIO& io = ImGui::GetIO(); 436 | this->LockedMagnifiedScreenPositionX = static_cast(io.MousePos.x); 437 | this->LockedMagnifiedScreenPositionY = static_cast(io.MousePos.y); 438 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__LOCKED[ch]; 439 | } 440 | else if (bLockSwitchedOff) 441 | { 442 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; 443 | } 444 | } 445 | } 446 | 447 | // These are currently not bound to any mouse input and are here for convenience/reference. 448 | // Mouse scroll is currently wired up to camera for panning and moving in the local Z direction. 449 | // Any application that would prefer otherwise can utilize these for easily controlling the magnifier parameters through the desired input. 450 | void UIState::AdjustMagnifierSize (float increment /*= 0.05f*/){ MagnifierParams.fMagnifierScreenRadius = clamped(MagnifierParams.fMagnifierScreenRadius + increment, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); } 451 | void UIState::AdjustMagnifierMagnification(float increment /*= 1.00f*/){ MagnifierParams.fMagnificationAmount = clamped(MagnifierParams.fMagnificationAmount + increment, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); } 452 | -------------------------------------------------------------------------------- /src/DX12/UI.h: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2024 Advanced Micro Devices, Inc.All rights reserved. 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files(the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions : 10 | // The above copyright notice and this permission notice shall be included in 11 | // all copies or substantial portions of the Software. 12 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 13 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 14 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 15 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 16 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 18 | // THE SOFTWARE. 19 | 20 | #pragma once 21 | 22 | #include "PostProc/MagnifierPS.h" 23 | #include 24 | 25 | struct UIState 26 | { 27 | // 28 | // WINDOW MANAGEMENT 29 | // 30 | bool bShowControlsWindow; 31 | bool bShowProfilerWindow; 32 | 33 | // EXECUTION MANAGEMENT 34 | int submissionMode; 35 | int numberOfBins; 36 | bool homogeneous; 37 | bool showBins; 38 | bool fixedExpansion; 39 | bool threadLaunch; 40 | bool smoothing; 41 | bool disable; 42 | 43 | mutable int feedback[6]; 44 | 45 | // 46 | // POST PROCESS CONTROLS 47 | // 48 | int SelectedTonemapperIndex; 49 | float Exposure; 50 | 51 | bool bUseTAA; 52 | 53 | bool bUseMagnifier; 54 | bool bLockMagnifierPosition; 55 | bool bLockMagnifierPositionHistory; 56 | int LockedMagnifiedScreenPositionX; 57 | int LockedMagnifiedScreenPositionY; 58 | CAULDRON_DX12::MagnifierPS::PassParameters MagnifierParams; 59 | 60 | 61 | // 62 | // APP/SCENE CONTROLS 63 | // 64 | float IBLFactor; 65 | float EmissiveFactor; 66 | 67 | int SelectedSkydomeTypeIndex; 68 | bool bDrawBoundingBoxes; 69 | bool bDrawLightFrustum; 70 | 71 | enum class WireframeMode : int 72 | { 73 | WIREFRAME_MODE_OFF = 0, 74 | WIREFRAME_MODE_SHADED = 1, 75 | WIREFRAME_MODE_SOLID_COLOR = 2, 76 | }; 77 | 78 | WireframeMode WireframeMode; 79 | float WireframeColor[3]; 80 | 81 | // 82 | // PROFILER CONTROLS 83 | // 84 | bool bShowMilliseconds; 85 | 86 | // ----------------------------------------------- 87 | 88 | void Initialize(); 89 | 90 | void ToggleMagnifierLock(); 91 | void AdjustMagnifierSize(float increment = 0.05f); 92 | void AdjustMagnifierMagnification(float increment = 1.00f); 93 | }; -------------------------------------------------------------------------------- /src/DX12/dpiawarescaling.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true/PM 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/DX12/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // SampleD3D12.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /src/DX12/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | #pragma once 6 | 7 | #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 8 | 9 | // Windows Header Files: 10 | #include 11 | #include 12 | 13 | // C RunTime Header Files 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #ifdef ENABLE_WORKGRAPHS 21 | #include "../../libs/d3d12/d3d12.h" 22 | #include "../../libs/d3d12x/d3dx12.h" 23 | #else 24 | #include 25 | #include 26 | #endif 27 | 28 | // Pull in math library 29 | #include "../../libs/vectormath/vectormath.hpp" 30 | 31 | // TODO: reference additional headers your program requires here 32 | #include "Base/Imgui.h" 33 | #include "Base/ImguiHelper.h" 34 | #include "Base/Fence.h" 35 | #include "Base/Helper.h" 36 | #include "Base/Device.h" 37 | #include "Base/Texture.h" 38 | #include "Base/FrameworkWindows.h" 39 | #include "Base/FreeSyncHDR.h" 40 | #include "Base/SwapChain.h" 41 | #include "Base/UploadHeap.h" 42 | #include "Base/SaveTexture.h" 43 | #include "Base/UserMarkers.h" 44 | #include "Base/GPUTimestamps.h" 45 | #include "Base/CommandListRing.h" 46 | #include "Base/StaticBufferPool.h" 47 | #include "Base/DynamicBufferRing.h" 48 | #include "Base/ResourceViewHeaps.h" 49 | #include "Base/ShaderCompilerCache.h" 50 | #include "Base/ShaderCompilerHelper.h" 51 | #include "Base/StaticConstantBufferPool.h" 52 | 53 | #include "GLTF/GltfPbrPass.h" 54 | #include "GLTF/GltfBBoxPass.h" 55 | #include "GLTF/GltfDepthPass.h" 56 | #include "GLTF/GltfRasterizerPass.h" // z-buffer rasterizer 57 | #include "GLTF/GltfMotionVectorsPass.h" 58 | 59 | #include "Misc/Misc.h" 60 | #include "Misc/Error.h" 61 | #include "Misc/Camera.h" 62 | 63 | #include "PostProc/TAA.h" 64 | #include "PostProc/Bloom.h" 65 | #include "PostProc/BlurPS.h" 66 | #include "PostProc/SkyDome.h" 67 | #include "PostProc/SkyDomeProc.h" 68 | #include "PostProc/PostProcCS.h" 69 | #include "PostProc/ToneMapping.h" 70 | #include "PostProc/ToneMappingCS.h" 71 | #include "PostProc/ColorConversionPS.h" 72 | #include "PostProc/DownSamplePS.h" 73 | #include "PostProc/ShadowResolvePass.h" 74 | 75 | #include "Widgets/wireframe.h" 76 | 77 | 78 | using namespace CAULDRON_DX12; 79 | --------------------------------------------------------------------------------