├── .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 └── VK ├── CMakeLists.txt ├── GLTFSample.cpp ├── GLTFSample.h ├── Renderer.cpp ├── Renderer.h ├── UI.cpp ├── UI.h ├── dpiawarescaling.manifest ├── stdafx.cpp └── stdafx.h /.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 | # Visual Studio 2015/2017 cache/options directory 34 | .vs/ 35 | # Uncomment if you have tasks that create the project's static files in wwwroot 36 | #wwwroot/ 37 | 38 | # Visual Studio 2017 auto generated files 39 | Generated\ Files/ 40 | 41 | # Visual Studio 2019 Open Folder 42 | out/ 43 | CMakeSettings.json 44 | 45 | # MSTest test Results 46 | [Tt]est[Rr]esult*/ 47 | [Bb]uild[Ll]og.* 48 | 49 | # NUnit 50 | *.VisualState.xml 51 | TestResult.xml 52 | nunit-*.xml 53 | 54 | # Build Results of an ATL Project 55 | [Dd]ebugPS/ 56 | [Rr]eleasePS/ 57 | dlldata.c 58 | 59 | # Benchmark Results 60 | BenchmarkDotNet.Artifacts/ 61 | 62 | # .NET Core 63 | project.lock.json 64 | project.fragment.lock.json 65 | artifacts/ 66 | 67 | # StyleCop 68 | StyleCopReport.xml 69 | 70 | # Files built by Visual Studio 71 | *_i.c 72 | *_p.c 73 | *_h.h 74 | *.ilk 75 | *.meta 76 | *.obj 77 | *.iobj 78 | *.pch 79 | *.pdb 80 | *.ipdb 81 | *.pgc 82 | *.pgd 83 | *.rsp 84 | *.sbr 85 | *.tlb 86 | *.tli 87 | *.tlh 88 | *.tmp 89 | *.tmp_proj 90 | *_wpftmp.csproj 91 | *.log 92 | *.vspscc 93 | *.vssscc 94 | .builds 95 | *.pidb 96 | *.svclog 97 | *.scc 98 | 99 | # Chutzpah Test files 100 | _Chutzpah* 101 | 102 | # Visual C++ cache files 103 | ipch/ 104 | *.aps 105 | *.ncb 106 | *.opendb 107 | *.opensdf 108 | *.sdf 109 | *.cachefile 110 | *.VC.db 111 | *.VC.VC.opendb 112 | 113 | # Visual Studio profiler 114 | *.psess 115 | *.vsp 116 | *.vspx 117 | *.sap 118 | 119 | # Visual Studio Trace Files 120 | *.e2e 121 | 122 | # TFS 2012 Local Workspace 123 | $tf/ 124 | 125 | # Guidance Automation Toolkit 126 | *.gpState 127 | 128 | # ReSharper is a .NET coding add-in 129 | _ReSharper*/ 130 | *.[Rr]e[Ss]harper 131 | *.DotSettings.user 132 | 133 | # JustCode is a .NET coding add-in 134 | .JustCode 135 | 136 | # TeamCity is a build add-in 137 | _TeamCity* 138 | 139 | # DotCover is a Code Coverage Tool 140 | *.dotCover 141 | 142 | # AxoCover is a Code Coverage Tool 143 | .axoCover/* 144 | !.axoCover/settings.json 145 | 146 | # Visual Studio code coverage results 147 | *.coverage 148 | *.coveragexml 149 | 150 | # NCrunch 151 | _NCrunch_* 152 | .*crunch*.local.xml 153 | nCrunchTemp_* 154 | 155 | # MightyMoose 156 | *.mm.* 157 | AutoTest.Net/ 158 | 159 | # Web workbench (sass) 160 | .sass-cache/ 161 | 162 | # Installshield output folder 163 | [Ee]xpress/ 164 | 165 | # DocProject is a documentation generator add-in 166 | DocProject/buildhelp/ 167 | DocProject/Help/*.HxT 168 | DocProject/Help/*.HxC 169 | DocProject/Help/*.hhc 170 | DocProject/Help/*.hhk 171 | DocProject/Help/*.hhp 172 | DocProject/Help/Html2 173 | DocProject/Help/html 174 | 175 | # Click-Once directory 176 | publish/ 177 | 178 | # Publish Web Output 179 | *.[Pp]ublish.xml 180 | *.azurePubxml 181 | # Note: Comment the next line if you want to checkin your web deploy settings, 182 | # but database connection strings (with potential passwords) will be unencrypted 183 | *.pubxml 184 | *.publishproj 185 | 186 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 187 | # checkin your Azure Web App publish settings, but sensitive information contained 188 | # in these scripts will be unencrypted 189 | PublishScripts/ 190 | 191 | # NuGet Packages 192 | *.nupkg 193 | # NuGet Symbol Packages 194 | *.snupkg 195 | # The packages folder can be ignored because of Package Restore 196 | **/[Pp]ackages/* 197 | # except build/, which is used as an MSBuild target. 198 | !**/[Pp]ackages/build/ 199 | # Uncomment if necessary however generally it will be regenerated when needed 200 | #!**/[Pp]ackages/repositories.config 201 | # NuGet v3's project.json files produces more ignorable files 202 | *.nuget.props 203 | *.nuget.targets 204 | 205 | # Microsoft Azure Build Output 206 | csx/ 207 | *.build.csdef 208 | 209 | # Microsoft Azure Emulator 210 | ecf/ 211 | rcf/ 212 | 213 | # Windows Store app package directories and files 214 | AppPackages/ 215 | BundleArtifacts/ 216 | Package.StoreAssociation.xml 217 | _pkginfo.txt 218 | *.appx 219 | *.appxbundle 220 | *.appxupload 221 | 222 | # Visual Studio cache files 223 | # files ending in .cache can be ignored 224 | *.[Cc]ache 225 | # but keep track of directories ending in .cache 226 | !?*.[Cc]ache/ 227 | 228 | # Others 229 | ClientBin/ 230 | ~$* 231 | *~ 232 | *.dbmdl 233 | *.dbproj.schemaview 234 | *.jfm 235 | *.pfx 236 | *.publishsettings 237 | orleans.codegen.cs 238 | 239 | # Including strong name files can present a security risk 240 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 241 | #*.snk 242 | 243 | # Since there are multiple workflows, uncomment next line to ignore bower_components 244 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 245 | #bower_components/ 246 | 247 | # RIA/Silverlight projects 248 | Generated_Code/ 249 | 250 | # Backup & report files from converting an old project file 251 | # to a newer Visual Studio version. Backup files are not needed, 252 | # because we have git ;-) 253 | _UpgradeReport_Files/ 254 | Backup*/ 255 | UpgradeLog*.XML 256 | UpgradeLog*.htm 257 | ServiceFabricBackup/ 258 | *.rptproj.bak 259 | 260 | # SQL Server files 261 | *.mdf 262 | *.ldf 263 | *.ndf 264 | 265 | # Business Intelligence projects 266 | *.rdl.data 267 | *.bim.layout 268 | *.bim_*.settings 269 | *.rptproj.rsuser 270 | *- [Bb]ackup.rdl 271 | *- [Bb]ackup ([0-9]).rdl 272 | *- [Bb]ackup ([0-9][0-9]).rdl 273 | 274 | # Microsoft Fakes 275 | FakesAssemblies/ 276 | 277 | # GhostDoc plugin setting file 278 | *.GhostDoc.xml 279 | 280 | # Node.js Tools for Visual Studio 281 | .ntvs_analysis.dat 282 | node_modules/ 283 | 284 | # Visual Studio 6 build log 285 | *.plg 286 | 287 | # Visual Studio 6 workspace options file 288 | *.opt 289 | 290 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 291 | *.vbw 292 | 293 | # Visual Studio LightSwitch build output 294 | **/*.HTMLClient/GeneratedArtifacts 295 | **/*.DesktopClient/GeneratedArtifacts 296 | **/*.DesktopClient/ModelManifest.xml 297 | **/*.Server/GeneratedArtifacts 298 | **/*.Server/ModelManifest.xml 299 | _Pvt_Extensions 300 | 301 | # Paket dependency manager 302 | .paket/paket.exe 303 | paket-files/ 304 | 305 | # FAKE - F# Make 306 | .fake/ 307 | 308 | # CodeRush personal settings 309 | .cr/personal 310 | 311 | # Python Tools for Visual Studio (PTVS) 312 | __pycache__/ 313 | *.pyc 314 | 315 | # Cake - Uncomment if you are using it 316 | # tools/** 317 | # !tools/packages.config 318 | 319 | # Tabs Studio 320 | *.tss 321 | 322 | # Telerik's JustMock configuration file 323 | *.jmconfig 324 | 325 | # BizTalk build output 326 | *.btp.cs 327 | *.btm.cs 328 | *.odx.cs 329 | *.xsd.cs 330 | 331 | # OpenCover UI analysis results 332 | OpenCover/ 333 | 334 | # Azure Stream Analytics local run output 335 | ASALocalRun/ 336 | 337 | # MSBuild Binary and Structured Log 338 | *.binlog 339 | 340 | # NVidia Nsight GPU debugger configuration file 341 | *.nvuser 342 | 343 | # MFractors (Xamarin productivity tool) working folder 344 | .mfractor/ 345 | 346 | # Local History for Visual Studio 347 | .localhistory/ 348 | 349 | # BeatPulse healthcheck temp database 350 | healthchecksdb 351 | 352 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 353 | MigrationBackup/ -------------------------------------------------------------------------------- /.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 | build_vk: 23 | tags: 24 | - windows 25 | - amd64 26 | stage: build 27 | artifacts: 28 | paths: 29 | - bin/ 30 | script: 31 | - 'cmake -S . -B build/Vk -DGFX_API=VK %CMakeConfig%' 32 | - 'cmake --build build/Vk --config Release' 33 | 34 | package_sample: 35 | tags: 36 | - windows 37 | - amd64 38 | stage: deploy 39 | dependencies: 40 | - build_dx12 41 | - build_vk 42 | script: 43 | - copy %VULKAN_SDK%\Bin\glslc.exe bin 44 | - echo cd .\bin\ > %SampleName%_VK.bat 45 | - echo start %SampleName%_VK.exe >> %SampleName%_VK.bat 46 | - echo cd .\bin\ > %SampleName%_DX12.bat 47 | - echo start %SampleName%_DX12.exe >> %SampleName%_DX12.bat 48 | artifacts: 49 | name: "%SampleName%-%CI_COMMIT_TAG%-%CI_COMMIT_REF_NAME%-%CI_COMMIT_SHORT_SHA%" 50 | paths: 51 | - "bin/" 52 | - "license.txt" 53 | - "media/cauldron-media/" 54 | - "%SampleName%_VK.bat" 55 | - "%SampleName%_DX12.bat" 56 | - "readme.md" 57 | - "screenshot.png" 58 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "libs/cauldron"] 2 | path = libs/cauldron 3 | url = ../Cauldron.git 4 | [submodule "media/Cauldron-Media"] 5 | path = media/Cauldron-Media 6 | url = ../Cauldron-Media.git 7 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6) 2 | 3 | option (GFX_API_DX12 "Build with DX12" ON) 4 | option (GFX_API_VK "Build with Vulkan" ON) 5 | 6 | if(NOT DEFINED GFX_API) 7 | project (GLTFSample) 8 | else() 9 | project (GLTFSample_${GFX_API}) 10 | 11 | set_property(DIRECTORY ${CMAKE_PROJECT_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) 12 | 13 | if(GFX_API STREQUAL DX12) 14 | set(GFX_API_DX12 ON) 15 | set(GFX_API_VK OFF) 16 | elseif(GFX_API STREQUAL VK) 17 | set(GFX_API_DX12 OFF) 18 | set(GFX_API_VK ON) 19 | else() 20 | message(STATUS "----------------------------------------------------------------------------------------") 21 | message(STATUS "") 22 | message(STATUS "** Almost there!!") 23 | message(STATUS "") 24 | message(STATUS " This framework supports DX12 and VULKAN, you need to invoke cmake in one of these ways:") 25 | message(STATUS "") 26 | message(STATUS " Examples:") 27 | message(STATUS " Generate selected one:") 28 | message(STATUS " cmake -DGFX_API=DX12") 29 | message(STATUS " cmake -DGFX_API=VK") 30 | message(STATUS " Generate with switches (Default is ON):") 31 | message(STATUS " cmake [-DGFX_API_DX12=ON|OFF] [-DGFX_API_VK=ON|OFF]") 32 | message(STATUS "") 33 | message(STATUS "----------------------------------------------------------------------------------------") 34 | message(FATAL_ERROR "") 35 | endif() 36 | endif() 37 | 38 | # Check MSVC toolset version, Visual Studio 2019 required 39 | if(MSVC_TOOLSET_VERSION VERSION_LESS 142) 40 | message(FATAL_ERROR "Cannot find MSVC toolset version 142 or greater. Please make sure Visual Studio 2019 or newer installed") 41 | endif() 42 | 43 | # ouput exe to bin directory 44 | SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin) 45 | foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) 46 | string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG ) 47 | set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_HOME_DIRECTORY}/bin ) 48 | endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) 49 | 50 | add_compile_options(/MP) 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_VK) 64 | find_package(Vulkan REQUIRED) 65 | add_subdirectory(src/VK) 66 | endif() 67 | if(GFX_API_DX12) 68 | add_subdirectory(src/DX12) 69 | endif() 70 | 71 | set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/Cauldron_Common.rc PROPERTIES VS_TOOL_OVERRIDE "Resource compiler") 72 | set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/GPUOpenChip.ico PROPERTIES VS_TOOL_OVERRIDE "Image") -------------------------------------------------------------------------------- /build/.gitignore: -------------------------------------------------------------------------------- 1 | DX12/ 2 | VK/ -------------------------------------------------------------------------------- /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 | :: Check if VULKAN_SDK is installed but don't bail out 43 | if "%VULKAN_SDK%"=="" ( 44 | echo Vulkan SDK is not installed -Environment variable VULKAN_SDK is not defined- : Please install the latest Vulkan SDK from LunarG. 45 | ) else ( 46 | echo Vulkan SDK - Ready : %VULKAN_SDK% 47 | ) 48 | 49 | 50 | :: Call CMake 51 | mkdir DX12 52 | cd DX12 53 | cmake -A x64 ..\.. -DGFX_API=DX12 54 | cd .. 55 | 56 | mkdir VK 57 | cd VK 58 | cmake -A x64 ..\.. -DGFX_API=VK 59 | cd .. -------------------------------------------------------------------------------- /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 | # glTFSample 2 | 3 | A simple but cute demo to show off the capabilities of 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 glTFSample, you must first install the following tools: 12 | 13 | - [CMake 3.16](https://cmake.org/download/) 14 | - [Visual Studio 2017](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 | - [Vulkan SDK 1.2.131.2](https://www.lunarg.com/vulkan-sdk/) 17 | 18 | Then follow the next steps: 19 | 20 | 1) Clone the repo with its submodules: 21 | ``` 22 | > git clone https://github.com/GPUOpen-LibrariesAndSDKs/glTFSample.git --recurse-submodules 23 | ``` 24 | 25 | 2) Generate the solutions: 26 | ``` 27 | > cd glTFSample\build 28 | > GenerateSolutions.bat 29 | ``` 30 | 31 | 3) Open the solutions in the VK or DX12 directories, compile and run. 32 | 33 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/GPUOpen-LibrariesAndSDKs/glTFSample/cfec7c01cab53127abd78c10aee297dd966cf0b0/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": 1, 9 | "benchmark": false, 10 | "vsync": false, 11 | "stablePowerState": false, 12 | "FreesyncHDROptionEnabled": false, 13 | "fontsize": 13 14 | }, 15 | "scenes": [ 16 | { 17 | "name": "Sponza", 18 | "directory": "..\\media\\cauldron-media\\sponza\\GLTF\\", 19 | "filename": "sponza.gltf", 20 | "TAA": false, 21 | "toneMapper": 0, 22 | "iblFactor": 0.36, 23 | "emmisiveFactor": 1, 24 | "intensity": 10, 25 | "exposure": 1, 26 | "activeCamera": -1, 27 | "camera": { 28 | "defaultFrom": [ 5.13694048, 1.89175785, -1.40289795 ], 29 | "defaultTo": [ 0.703276634, 1.02280307, 0.218072295 ] 30 | }, 31 | "BenchmarkSettings": { 32 | "timeStep": 1, 33 | "timeStart": 0, 34 | "timeEnd": 10000, 35 | "exitWhenTimeEnds": true, 36 | "resultsFilename": "Sponza.csv", 37 | "warmUpFrames": 200, 38 | "sequence": { 39 | "timeStart": 0, 40 | "timeEnd": 2000, 41 | "keyFrames": [ 42 | { 43 | "time": 0, 44 | "from": [ 5.13694048, 1.89175785, -1.40289795 ], 45 | "to": [ 0.703276634, 1.02280307, 0.218072295 ], 46 | "screenShotName": "camera1.jpg" 47 | }, 48 | { 49 | "time": 1000, 50 | "from": [ -5.13694048, 1.89175785, -1.40289795 ], 51 | "to": [ 0.703276634, 1.02280307, 0.218072295 ], 52 | "screenShotName": "camera2.jpg" 53 | } 54 | ] 55 | } 56 | } 57 | }, 58 | { 59 | "name": "BusterDrone", 60 | "directory": "..\\media\\cauldron-media\\buster_drone\\", 61 | "filename": "busterDrone.gltf", 62 | "TAA": true, 63 | "toneMapper": 0, 64 | "iblFactor": 1, 65 | "emmisiveFactor": 30, 66 | "intensity": 50, 67 | "exposure": 1, 68 | "camera": { 69 | "defaultFrom": [ 0, 0, 3.5 ], 70 | "defaultTo": [ 0, 0, 0 ] 71 | } 72 | }, 73 | { 74 | "name": "BoomBox", 75 | "directory": "..\\media\\cauldron-media\\BoomBox\\GLTF\\", 76 | "filename": "BoomBox.gltf", 77 | "TAA": true, 78 | "toneMapper": 0, 79 | "iblFactor": 1, 80 | "emmisiveFactor": 1, 81 | "intensity": 50, 82 | "exposure": 1, 83 | "camera": { 84 | "defaultFrom": [ 0, 0, 3.5 ], 85 | "defaultTo": [ 0, 0, 0 ] 86 | } 87 | }, 88 | { 89 | "name": "SciFiHelmet", 90 | "directory": "..\\media\\cauldron-media\\SciFiHelmet\\GLTF\\", 91 | "filename": "SciFiHelmet.gltf", 92 | "TAA": true, 93 | "toneMapper": 0, 94 | "iblFactor": 1, 95 | "emmisiveFactor": 1, 96 | "intensity": 50, 97 | "exposure": 1, 98 | "camera": { 99 | "defaultFrom": [ 0, 0, 3.5 ], 100 | "defaultTo": [ 0, 0, 0 ] 101 | } 102 | }, 103 | { 104 | "name": "DamagedHelmet", 105 | "directory": "..\\media\\cauldron-media\\DamagedHelmet\\GLTF\\", 106 | "filename": "DamagedHelmet.gltf", 107 | "TAA": true, 108 | "toneMapper": 0, 109 | "iblFactor": 2, 110 | "emmisiveFactor": 1, 111 | "intensity": 50, 112 | "exposure": 1, 113 | "camera": { 114 | "defaultFrom": [ 0, 0, 3.5 ], 115 | "defaultTo": [ 0, 0, 0 ] 116 | } 117 | }, 118 | { 119 | "name": "MetalRoughSpheres", 120 | "directory": "..\\media\\cauldron-media\\MetalRoughSpheres\\GLTF\\", 121 | "filename": "MetalRoughSpheres.gltf", 122 | "TAA": true, 123 | "iblFactor": 1, 124 | "emmisiveFactor": 1, 125 | "intensity": 50, 126 | "exposure": 1, 127 | "camera": { 128 | "defaultFrom": [ 0, 0, 20 ], 129 | "defaultTo": [ 0, 0, 0 ] 130 | } 131 | } 132 | ] 133 | } 134 | -------------------------------------------------------------------------------- /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) 2020 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 = true; 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_fontSize = 13.f; // default value overridden by a json file if available 47 | m_isCpuValidationLayerEnabled = false; 48 | m_isGpuValidationLayerEnabled = false; 49 | m_activeCamera = 0; 50 | m_stablePowerState = false; 51 | 52 | //read globals 53 | auto process = [&](json jData) 54 | { 55 | *pWidth = jData.value("width", *pWidth); 56 | *pHeight = jData.value("height", *pHeight); 57 | m_fullscreenMode = jData.value("presentationMode", m_fullscreenMode); 58 | m_activeScene = jData.value("activeScene", m_activeScene); 59 | m_activeCamera = jData.value("activeCamera", m_activeCamera); 60 | m_isCpuValidationLayerEnabled = jData.value("CpuValidationLayerEnabled", m_isCpuValidationLayerEnabled); 61 | m_isGpuValidationLayerEnabled = jData.value("GpuValidationLayerEnabled", m_isGpuValidationLayerEnabled); 62 | m_VsyncEnabled = jData.value("vsync", m_VsyncEnabled); 63 | m_FreesyncHDROptionEnabled = jData.value("FreesyncHDROptionEnabled", m_FreesyncHDROptionEnabled); 64 | m_bIsBenchmarking = jData.value("benchmark", m_bIsBenchmarking); 65 | m_stablePowerState = jData.value("stablePowerState", m_stablePowerState); 66 | m_fontSize = jData.value("fontsize", m_fontSize); 67 | }; 68 | 69 | //read json globals from commandline 70 | // 71 | try 72 | { 73 | if (strlen(lpCmdLine) > 0) 74 | { 75 | auto j3 = json::parse(lpCmdLine); 76 | process(j3); 77 | } 78 | } 79 | catch (json::parse_error) 80 | { 81 | Trace("Error parsing commandline\n"); 82 | exit(0); 83 | } 84 | 85 | // read config file (and override values from commandline if so) 86 | // 87 | { 88 | std::ifstream f("GLTFSample.json"); 89 | if (!f) 90 | { 91 | MessageBox(NULL, "Config file not found!\n", "Cauldron Panic!", MB_ICONERROR); 92 | exit(0); 93 | } 94 | 95 | try 96 | { 97 | f >> m_jsonConfigFile; 98 | } 99 | catch (json::parse_error) 100 | { 101 | MessageBox(NULL, "Error parsing GLTFSample.json!\n", "Cauldron Panic!", MB_ICONERROR); 102 | exit(0); 103 | } 104 | } 105 | 106 | 107 | json globals = m_jsonConfigFile["globals"]; 108 | process(globals); 109 | 110 | // get the list of scenes 111 | for (const auto & scene : m_jsonConfigFile["scenes"]) 112 | m_sceneNames.push_back(scene["name"]); 113 | } 114 | 115 | //-------------------------------------------------------------------------------------- 116 | // 117 | // OnCreate 118 | // 119 | //-------------------------------------------------------------------------------------- 120 | void GLTFSample::OnCreate() 121 | { 122 | //init the shader compiler 123 | InitDirectXCompiler(); 124 | CreateShaderCache(); 125 | 126 | // Create a instance of the renderer and initialize it, we need to do that for each GPU 127 | m_pRenderer = new Renderer(); 128 | m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); 129 | 130 | // init GUI (non gfx stuff) 131 | ImGUI_Init((void *)m_windowHwnd); 132 | m_UIState.Initialize(); 133 | 134 | OnResize(true); 135 | OnUpdateDisplay(); 136 | 137 | // Init Camera, looking at the origin 138 | m_camera.LookAt(math::Vector4(0, 0, 5, 0), math::Vector4(0, 0, 0, 0)); 139 | } 140 | 141 | //-------------------------------------------------------------------------------------- 142 | // 143 | // OnDestroy 144 | // 145 | //-------------------------------------------------------------------------------------- 146 | void GLTFSample::OnDestroy() 147 | { 148 | ImGUI_Shutdown(); 149 | 150 | m_device.GPUFlush(); 151 | 152 | m_pRenderer->UnloadScene(); 153 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 154 | m_pRenderer->OnDestroy(); 155 | 156 | delete m_pRenderer; 157 | 158 | //shut down the shader compiler 159 | DestroyShaderCache(&m_device); 160 | 161 | if (m_pGltfLoader) 162 | { 163 | delete m_pGltfLoader; 164 | m_pGltfLoader = NULL; 165 | } 166 | } 167 | 168 | //-------------------------------------------------------------------------------------- 169 | // 170 | // OnEvent, win32 sends us events and we forward them to ImGUI 171 | // 172 | //-------------------------------------------------------------------------------------- 173 | bool GLTFSample::OnEvent(MSG msg) 174 | { 175 | if (ImGUI_WndProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam)) 176 | return true; 177 | 178 | // handle function keys (F1, F2...) here, rest of the input is handled 179 | // by imGUI later in HandleInput() function 180 | const WPARAM& KeyPressed = msg.wParam; 181 | switch (msg.message) 182 | { 183 | case WM_KEYUP: 184 | case WM_SYSKEYUP: 185 | /* WINDOW TOGGLES */ 186 | if (KeyPressed == VK_F1) m_UIState.bShowControlsWindow ^= 1; 187 | if (KeyPressed == VK_F2) m_UIState.bShowProfilerWindow ^= 1; 188 | break; 189 | } 190 | 191 | return true; 192 | } 193 | 194 | //-------------------------------------------------------------------------------------- 195 | // 196 | // OnResize 197 | // 198 | //-------------------------------------------------------------------------------------- 199 | void GLTFSample::OnResize(bool resizeRender) 200 | { 201 | // Destroy resources (if we are not minimized) 202 | if (resizeRender && m_Width && m_Height && m_pRenderer) 203 | { 204 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 205 | m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); 206 | } 207 | 208 | m_camera.SetFov(AMD_PI_OVER_4, m_Width, m_Height, 0.1f, 1000.0f); 209 | } 210 | 211 | //-------------------------------------------------------------------------------------- 212 | // 213 | // UpdateDisplay 214 | // 215 | //-------------------------------------------------------------------------------------- 216 | void GLTFSample::OnUpdateDisplay() 217 | { 218 | // Destroy resources (if we are not minimized) 219 | if (m_pRenderer) 220 | { 221 | m_pRenderer->OnUpdateDisplayDependentResources(&m_swapChain); 222 | } 223 | } 224 | 225 | //-------------------------------------------------------------------------------------- 226 | // 227 | // LoadScene 228 | // 229 | //-------------------------------------------------------------------------------------- 230 | void GLTFSample::LoadScene(int sceneIndex) 231 | { 232 | json scene = m_jsonConfigFile["scenes"][sceneIndex]; 233 | 234 | // release everything and load the GLTF, just the light json data, the rest (textures and geometry) will be done in the main loop 235 | if (m_pGltfLoader != NULL) 236 | { 237 | m_pRenderer->UnloadScene(); 238 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 239 | m_pRenderer->OnDestroy(); 240 | m_pGltfLoader->Unload(); 241 | m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); 242 | m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); 243 | } 244 | 245 | delete(m_pGltfLoader); 246 | m_pGltfLoader = new GLTFCommon(); 247 | if (m_pGltfLoader->Load(scene["directory"], scene["filename"]) == false) 248 | { 249 | MessageBox(NULL, "The selected model couldn't be found, please check the documentation", "Cauldron Panic!", MB_ICONERROR); 250 | exit(0); 251 | } 252 | 253 | // Load the UI settings, and also some defaults cameras and lights, in case the GLTF has none 254 | { 255 | #define LOAD(j, key, val) val = j.value(key, val) 256 | 257 | // global settings 258 | LOAD(scene, "TAA", m_UIState.bUseTAA); 259 | LOAD(scene, "toneMapper", m_UIState.SelectedTonemapperIndex); 260 | LOAD(scene, "skyDomeType", m_UIState.SelectedSkydomeTypeIndex); 261 | LOAD(scene, "exposure", m_UIState.Exposure); 262 | LOAD(scene, "iblFactor", m_UIState.IBLFactor); 263 | LOAD(scene, "emmisiveFactor", m_UIState.EmissiveFactor); 264 | LOAD(scene, "skyDomeType", m_UIState.SelectedSkydomeTypeIndex); 265 | 266 | // Add a default light in case there are none 267 | if (m_pGltfLoader->m_lights.size() == 0) 268 | { 269 | tfNode n; 270 | n.m_tranform.LookAt(PolarToVector(AMD_PI_OVER_2, 0.58f) * 3.5f, math::Vector4(0, 0, 0, 0)); 271 | 272 | tfLight l; 273 | l.m_type = tfLight::LIGHT_SPOTLIGHT; 274 | l.m_intensity = scene.value("intensity", 1.0f); 275 | l.m_color = math::Vector4(1.0f, 1.0f, 1.0f, 0.0f); 276 | l.m_range = 15; 277 | l.m_outerConeAngle = AMD_PI_OVER_4; 278 | l.m_innerConeAngle = AMD_PI_OVER_4 * 0.9f; 279 | l.m_shadowResolution = 1024; 280 | 281 | m_pGltfLoader->AddLight(n, l); 282 | } 283 | 284 | // Allocate shadow information (if any) 285 | m_pRenderer->AllocateShadowMaps(m_pGltfLoader); 286 | 287 | // set default camera 288 | json camera = scene["camera"]; 289 | m_activeCamera = scene.value("activeCamera", m_activeCamera); 290 | math::Vector4 from = GetVector(GetElementJsonArray(camera, "defaultFrom", { 0.0, 0.0, 10.0 })); 291 | math::Vector4 to = GetVector(GetElementJsonArray(camera, "defaultTo", { 0.0, 0.0, 0.0 })); 292 | m_camera.LookAt(from, to); 293 | 294 | // set benchmarking state if enabled 295 | if (m_bIsBenchmarking) 296 | { 297 | std::string deviceName; 298 | std::string driverVersion; 299 | m_device.GetDeviceInfo(&deviceName, &driverVersion); 300 | BenchmarkConfig(scene["BenchmarkSettings"], m_activeCamera, m_pGltfLoader, deviceName, driverVersion); 301 | } 302 | 303 | // indicate the mainloop we started loading a GLTF and it needs to load the rest (textures and geometry) 304 | m_loadingScene = true; 305 | } 306 | } 307 | 308 | 309 | //-------------------------------------------------------------------------------------- 310 | // 311 | // OnUpdate 312 | // 313 | //-------------------------------------------------------------------------------------- 314 | void GLTFSample::OnUpdate() 315 | { 316 | ImGuiIO& io = ImGui::GetIO(); 317 | 318 | //If the mouse was not used by the GUI then it's for the camera 319 | if (io.WantCaptureMouse) 320 | { 321 | io.MouseDelta.x = 0; 322 | io.MouseDelta.y = 0; 323 | io.MouseWheel = 0; 324 | } 325 | 326 | // Update Camera 327 | UpdateCamera(m_camera, io); 328 | if (m_UIState.bUseTAA) 329 | { 330 | static uint32_t Seed; 331 | m_camera.SetProjectionJitter(m_Width, m_Height, Seed); 332 | } 333 | else 334 | m_camera.SetProjectionJitter(0.f, 0.f); 335 | 336 | // Keyboard & Mouse 337 | HandleInput(io); 338 | 339 | // Animation Update 340 | if (m_bPlay) 341 | m_time += (float)m_deltaTime / 1000.0f; // animation time in seconds 342 | 343 | if (m_pGltfLoader) 344 | { 345 | m_pGltfLoader->SetAnimationTime(0, m_time); 346 | m_pGltfLoader->TransformScene(0, math::Matrix4::identity()); 347 | } 348 | } 349 | void GLTFSample::HandleInput(const ImGuiIO& io) 350 | { 351 | auto fnIsKeyTriggered = [&io](char key) { return io.KeysDown[key] && io.KeysDownDuration[key] == 0.0f; }; 352 | 353 | // Handle Keyboard/Mouse input here 354 | 355 | /* MAGNIFIER CONTROLS */ 356 | if (fnIsKeyTriggered('L')) m_UIState.ToggleMagnifierLock(); 357 | if (fnIsKeyTriggered('M') || io.MouseClicked[2]) m_UIState.bUseMagnifier ^= 1; // middle mouse / M key toggles magnifier 358 | 359 | if (io.MouseClicked[1] && m_UIState.bUseMagnifier) // right mouse click 360 | m_UIState.ToggleMagnifierLock(); 361 | } 362 | void GLTFSample::UpdateCamera(Camera& cam, const ImGuiIO& io) 363 | { 364 | float yaw = cam.GetYaw(); 365 | float pitch = cam.GetPitch(); 366 | float distance = cam.GetDistance(); 367 | 368 | cam.UpdatePreviousMatrices(); // set previous view matrix 369 | 370 | // Sets Camera based on UI selection (WASD, Orbit or any of the GLTF cameras) 371 | if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) 372 | { 373 | yaw -= io.MouseDelta.x / 100.f; 374 | pitch += io.MouseDelta.y / 100.f; 375 | } 376 | 377 | // Choose camera movement depending on setting 378 | if (m_activeCamera == 0) 379 | { 380 | // If nothing has changed, don't calculate an update (we are getting micro changes in view causing bugs) 381 | if (!io.MouseWheel && (!io.MouseDown[0] || (!io.MouseDelta.x && !io.MouseDelta.y) )) 382 | return; 383 | 384 | // Orbiting 385 | distance -= (float)io.MouseWheel / 3.0f; 386 | distance = std::max(distance, 0.1f); 387 | 388 | bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); 389 | 390 | cam.UpdateCameraPolar(yaw, pitch, 391 | panning ? -io.MouseDelta.x / 100.0f : 0.0f, 392 | panning ? io.MouseDelta.y / 100.0f : 0.0f, 393 | distance); 394 | } 395 | else if (m_activeCamera == 1) 396 | { 397 | // WASD 398 | cam.UpdateCameraWASD(yaw, pitch, io.KeysDown, io.DeltaTime); 399 | } 400 | else if (m_activeCamera > 1) 401 | { 402 | // Use a camera from the GLTF 403 | m_pGltfLoader->GetCamera(m_activeCamera - 2, &cam); 404 | } 405 | } 406 | 407 | //-------------------------------------------------------------------------------------- 408 | // 409 | // OnRender 410 | // 411 | //-------------------------------------------------------------------------------------- 412 | void GLTFSample::OnRender() 413 | { 414 | // Do any start of frame necessities 415 | BeginFrame(); 416 | 417 | ImGUI_UpdateIO(); 418 | ImGui::NewFrame(); 419 | 420 | if (m_loadingScene) 421 | { 422 | // the scene loads in chunks, that way we can show a progress bar 423 | static int loadingStage = 0; 424 | loadingStage = m_pRenderer->LoadScene(m_pGltfLoader, loadingStage); 425 | if (loadingStage == 0) 426 | { 427 | m_time = 0; 428 | m_loadingScene = false; 429 | } 430 | } 431 | else if (m_pGltfLoader && m_bIsBenchmarking) 432 | { 433 | // Benchmarking takes control of the time, and exits the app when the animation is done 434 | std::vector timeStamps = m_pRenderer->GetTimingValues(); 435 | m_time = BenchmarkLoop(timeStamps, &m_camera, m_pRenderer->GetScreenshotFileName()); 436 | } 437 | else 438 | { 439 | BuildUI(); // UI logic. Note that the rendering of the UI happens later. 440 | OnUpdate(); // Update camera, handle keyboard/mouse input 441 | } 442 | 443 | // Do Render frame using AFR 444 | m_pRenderer->OnRender(&m_UIState, m_camera, &m_swapChain); 445 | 446 | // Framework will handle Present and some other end of frame logic 447 | EndFrame(); 448 | } 449 | 450 | 451 | //-------------------------------------------------------------------------------------- 452 | // 453 | // WinMain 454 | // 455 | //-------------------------------------------------------------------------------------- 456 | int WINAPI WinMain(HINSTANCE hInstance, 457 | HINSTANCE hPrevInstance, 458 | LPSTR lpCmdLine, 459 | int nCmdShow) 460 | { 461 | LPCSTR Name = "SampleDX12 v1.4.1"; 462 | 463 | // create new DX sample 464 | return RunFramework(hInstance, lpCmdLine, nCmdShow, new GLTFSample(Name)); 465 | } 466 | -------------------------------------------------------------------------------- /src/DX12/GLTFSample.h: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2020 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 | 52 | GLTFCommon *m_pGltfLoader = NULL; 53 | bool m_loadingScene = false; 54 | 55 | Renderer* m_pRenderer = NULL; 56 | UIState m_UIState; 57 | float m_fontSize; 58 | Camera m_camera; 59 | 60 | float m_time; // Time accumulator in seconds, used for animation. 61 | 62 | // json config file 63 | json m_jsonConfigFile; 64 | std::vector m_sceneNames; 65 | int m_activeScene; 66 | int m_activeCamera; 67 | 68 | bool m_bPlay; 69 | }; 70 | -------------------------------------------------------------------------------- /src/DX12/Renderer.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2020 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 | // Initialize helpers 35 | 36 | // Create all the heaps for the resources views 37 | const uint32_t cbvDescriptorCount = 4000; 38 | const uint32_t srvDescriptorCount = 8000; 39 | const uint32_t uavDescriptorCount = 10; 40 | const uint32_t dsvDescriptorCount = 10; 41 | const uint32_t rtvDescriptorCount = 60; 42 | const uint32_t samplerDescriptorCount = 20; 43 | m_ResourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, dsvDescriptorCount, rtvDescriptorCount, samplerDescriptorCount); 44 | 45 | // Create a commandlist ring for the Direct queue 46 | uint32_t commandListsPerBackBuffer = 8; 47 | m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer, pDevice->GetGraphicsQueue()->GetDesc()); 48 | 49 | // Create a 'dynamic' constant buffer 50 | const uint32_t constantBuffersMemSize = 200 * 1024 * 1024; 51 | m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, &m_ResourceViewHeaps); 52 | 53 | // Create a 'static' pool for vertices, indices and constant buffers 54 | const uint32_t staticGeometryMemSize = (5 * 128) * 1024 * 1024; 55 | m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, true, "StaticGeom"); 56 | 57 | // initialize the GPU time stamps module 58 | m_GPUTimer.OnCreate(pDevice, backBufferCount); 59 | 60 | // Quick helper to upload resources, it has it's own commandList and uses suballocation. 61 | const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024; 62 | m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results) 63 | 64 | // Create GBuffer and render passes 65 | // 66 | { 67 | m_GBuffer.OnCreate( 68 | pDevice, 69 | &m_ResourceViewHeaps, 70 | { 71 | { GBUFFER_DEPTH, DXGI_FORMAT_D32_FLOAT}, 72 | { GBUFFER_FORWARD, DXGI_FORMAT_R16G16B16A16_FLOAT}, 73 | { GBUFFER_MOTION_VECTORS, DXGI_FORMAT_R16G16_FLOAT}, 74 | }, 75 | 1 76 | ); 77 | 78 | GBufferFlags fullGBuffer = GBUFFER_DEPTH | GBUFFER_FORWARD | GBUFFER_MOTION_VECTORS; 79 | m_RenderPassFullGBuffer.OnCreate(&m_GBuffer, fullGBuffer); 80 | m_RenderPassJustDepthAndHdr.OnCreate(&m_GBuffer, GBUFFER_DEPTH | GBUFFER_FORWARD); 81 | } 82 | 83 | #if USE_SHADOWMASK 84 | m_shadowResolve.OnCreate(m_pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing); 85 | 86 | // Create the shadow mask descriptors 87 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_ShadowMaskUAV); 88 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_ShadowMaskSRV); 89 | #endif 90 | 91 | 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); 92 | m_SkyDomeProc.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT, 1); 93 | m_Wireframe.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT, 1); 94 | m_WireframeBox.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool); 95 | m_DownSample.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); 96 | m_Bloom.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); 97 | m_TAA.OnCreate(pDevice, &m_ResourceViewHeaps, &m_VidMemBufferPool); 98 | m_MagnifierPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); 99 | 100 | // Create tonemapping pass 101 | m_ToneMappingPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); 102 | m_ToneMappingCS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing); 103 | m_ColorConversionPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); 104 | 105 | // Initialize UI rendering resources 106 | m_ImGUI.OnCreate(pDevice, &m_UploadHeap, &m_ResourceViewHeaps, &m_ConstantBufferRing, pSwapChain->GetFormat(), FontSize); 107 | 108 | // Make sure upload heap has finished uploading before continuing 109 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 110 | m_UploadHeap.FlushAndFinish(); 111 | } 112 | 113 | //-------------------------------------------------------------------------------------- 114 | // 115 | // OnDestroy 116 | // 117 | //-------------------------------------------------------------------------------------- 118 | void Renderer::OnDestroy() 119 | { 120 | m_AsyncPool.Flush(); 121 | 122 | m_ImGUI.OnDestroy(); 123 | m_ColorConversionPS.OnDestroy(); 124 | m_ToneMappingCS.OnDestroy(); 125 | m_ToneMappingPS.OnDestroy(); 126 | m_TAA.OnDestroy(); 127 | m_Bloom.OnDestroy(); 128 | m_DownSample.OnDestroy(); 129 | m_MagnifierPS.OnDestroy(); 130 | m_WireframeBox.OnDestroy(); 131 | m_Wireframe.OnDestroy(); 132 | m_SkyDomeProc.OnDestroy(); 133 | m_SkyDome.OnDestroy(); 134 | #if USE_SHADOWMASK 135 | m_shadowResolve.OnDestroy(); 136 | #endif 137 | m_GBuffer.OnDestroy(); 138 | 139 | m_UploadHeap.OnDestroy(); 140 | m_GPUTimer.OnDestroy(); 141 | m_VidMemBufferPool.OnDestroy(); 142 | m_ConstantBufferRing.OnDestroy(); 143 | m_ResourceViewHeaps.OnDestroy(); 144 | m_CommandListRing.OnDestroy(); 145 | } 146 | 147 | //-------------------------------------------------------------------------------------- 148 | // 149 | // OnCreateWindowSizeDependentResources 150 | // 151 | //-------------------------------------------------------------------------------------- 152 | void Renderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height) 153 | { 154 | m_Width = Width; 155 | m_Height = Height; 156 | 157 | // Set the viewport & scissors rect 158 | m_Viewport = { 0.0f, 0.0f, static_cast(Width), static_cast(Height), 0.0f, 1.0f }; 159 | m_RectScissor = { 0, 0, (LONG)Width, (LONG)Height }; 160 | 161 | #if USE_SHADOWMASK 162 | // Create shadow mask 163 | // 164 | m_ShadowMask.Init(m_pDevice, "shadowbuffer", &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R8G8B8A8_UNORM, Width, Height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, NULL); 165 | m_ShadowMask.CreateUAV(0, &m_ShadowMaskUAV); 166 | m_ShadowMask.CreateSRV(0, &m_ShadowMaskSRV); 167 | #endif 168 | 169 | // Create GBuffer 170 | // 171 | m_GBuffer.OnCreateWindowSizeDependentResources(pSwapChain, Width, Height); 172 | m_RenderPassFullGBuffer.OnCreateWindowSizeDependentResources(Width, Height); 173 | m_RenderPassJustDepthAndHdr.OnCreateWindowSizeDependentResources(Width, Height); 174 | 175 | m_TAA.OnCreateWindowSizeDependentResources(Width, Height, &m_GBuffer); 176 | 177 | // update bloom and downscaling effect 178 | // 179 | m_DownSample.OnCreateWindowSizeDependentResources(m_Width, m_Height, &m_GBuffer.m_HDR, 5); //downsample the HDR texture 5 times 180 | m_Bloom.OnCreateWindowSizeDependentResources(m_Width / 2, m_Height / 2, m_DownSample.GetTexture(), 5, &m_GBuffer.m_HDR); 181 | m_MagnifierPS.OnCreateWindowSizeDependentResources(&m_GBuffer.m_HDR); 182 | } 183 | 184 | //-------------------------------------------------------------------------------------- 185 | // 186 | // OnDestroyWindowSizeDependentResources 187 | // 188 | //-------------------------------------------------------------------------------------- 189 | void Renderer::OnDestroyWindowSizeDependentResources() 190 | { 191 | m_Bloom.OnDestroyWindowSizeDependentResources(); 192 | m_DownSample.OnDestroyWindowSizeDependentResources(); 193 | 194 | m_GBuffer.OnDestroyWindowSizeDependentResources(); 195 | 196 | m_TAA.OnDestroyWindowSizeDependentResources(); 197 | 198 | m_MagnifierPS.OnDestroyWindowSizeDependentResources(); 199 | 200 | #if USE_SHADOWMASK 201 | m_ShadowMask.OnDestroy(); 202 | #endif 203 | 204 | } 205 | 206 | void Renderer::OnUpdateDisplayDependentResources(SwapChain* pSwapChain) 207 | { 208 | // Update pipelines in case the format of the RTs changed (this happens when going HDR) 209 | m_ColorConversionPS.UpdatePipelines(pSwapChain->GetFormat(), pSwapChain->GetDisplayMode()); 210 | m_ToneMappingPS.UpdatePipelines(pSwapChain->GetFormat()); 211 | m_ImGUI.UpdatePipeline((pSwapChain->GetDisplayMode() == DISPLAYMODE_SDR) ? pSwapChain->GetFormat() : m_GBuffer.m_HDR.GetFormat()); 212 | } 213 | 214 | //-------------------------------------------------------------------------------------- 215 | // 216 | // LoadScene 217 | // 218 | //-------------------------------------------------------------------------------------- 219 | int Renderer::LoadScene(GLTFCommon *pGLTFCommon, int Stage) 220 | { 221 | // show loading progress 222 | // 223 | ImGui::OpenPopup("Loading"); 224 | if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 225 | { 226 | float progress = (float)Stage / 13.0f; 227 | ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL); 228 | ImGui::EndPopup(); 229 | } 230 | 231 | // use multi threading 232 | AsyncPool *pAsyncPool = &m_AsyncPool; 233 | 234 | // Loading stages 235 | // 236 | if (Stage == 0) 237 | { 238 | } 239 | else if (Stage == 5) 240 | { 241 | Profile p("m_pGltfLoader->Load"); 242 | 243 | m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers(); 244 | m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing); 245 | } 246 | else if (Stage == 6) 247 | { 248 | Profile p("LoadTextures"); 249 | 250 | // here we are loading onto the GPU all the textures and the inverse matrices 251 | // this data will be used to create the PBR and Depth passes 252 | m_pGLTFTexturesAndBuffers->LoadTextures(pAsyncPool); 253 | } 254 | else if (Stage == 7) 255 | { 256 | Profile p("m_GLTFDepth->OnCreate"); 257 | 258 | //create the glTF's textures, VBs, IBs, shaders and descriptors for this particular pass 259 | m_GLTFDepth = new GltfDepthPass(); 260 | m_GLTFDepth->OnCreate( 261 | m_pDevice, 262 | &m_UploadHeap, 263 | &m_ResourceViewHeaps, 264 | &m_ConstantBufferRing, 265 | &m_VidMemBufferPool, 266 | m_pGLTFTexturesAndBuffers, 267 | pAsyncPool 268 | ); 269 | } 270 | else if (Stage == 9) 271 | { 272 | Profile p("m_GLTFPBR->OnCreate"); 273 | 274 | // same thing as above but for the PBR pass 275 | m_GLTFPBR = new GltfPbrPass(); 276 | m_GLTFPBR->OnCreate( 277 | m_pDevice, 278 | &m_UploadHeap, 279 | &m_ResourceViewHeaps, 280 | &m_ConstantBufferRing, 281 | m_pGLTFTexturesAndBuffers, 282 | &m_SkyDome, 283 | false, // use a SSAO mask 284 | USE_SHADOWMASK, 285 | &m_RenderPassFullGBuffer, 286 | pAsyncPool 287 | ); 288 | 289 | } 290 | else if (Stage == 10) 291 | { 292 | Profile p("m_GLTFBBox->OnCreate"); 293 | 294 | // just a bounding box pass that will draw boundingboxes instead of the geometry itself 295 | m_GLTFBBox = new GltfBBoxPass(); 296 | m_GLTFBBox->OnCreate( 297 | m_pDevice, 298 | &m_UploadHeap, 299 | &m_ResourceViewHeaps, 300 | &m_ConstantBufferRing, 301 | &m_VidMemBufferPool, 302 | m_pGLTFTexturesAndBuffers, 303 | &m_Wireframe 304 | ); 305 | 306 | // we are borrowing the upload heap command list for uploading to the GPU the IBs and VBs 307 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 308 | 309 | } 310 | else if (Stage == 11) 311 | { 312 | Profile p("Flush"); 313 | 314 | m_UploadHeap.FlushAndFinish(); 315 | 316 | //once everything is uploaded we dont need he upload heaps anymore 317 | m_VidMemBufferPool.FreeUploadHeap(); 318 | 319 | // tell caller that we are done loading the map 320 | return 0; 321 | } 322 | 323 | Stage++; 324 | return Stage; 325 | } 326 | 327 | //-------------------------------------------------------------------------------------- 328 | // 329 | // UnloadScene 330 | // 331 | //-------------------------------------------------------------------------------------- 332 | void Renderer::UnloadScene() 333 | { 334 | // wait for all the async loading operations to finish 335 | m_AsyncPool.Flush(); 336 | 337 | m_pDevice->GPUFlush(); 338 | 339 | if (m_GLTFPBR) 340 | { 341 | m_GLTFPBR->OnDestroy(); 342 | delete m_GLTFPBR; 343 | m_GLTFPBR = NULL; 344 | } 345 | 346 | if (m_GLTFDepth) 347 | { 348 | m_GLTFDepth->OnDestroy(); 349 | delete m_GLTFDepth; 350 | m_GLTFDepth = NULL; 351 | } 352 | 353 | if (m_GLTFBBox) 354 | { 355 | m_GLTFBBox->OnDestroy(); 356 | delete m_GLTFBBox; 357 | m_GLTFBBox = NULL; 358 | } 359 | 360 | if (m_pGLTFTexturesAndBuffers) 361 | { 362 | m_pGLTFTexturesAndBuffers->OnDestroy(); 363 | delete m_pGLTFTexturesAndBuffers; 364 | m_pGLTFTexturesAndBuffers = NULL; 365 | } 366 | 367 | while (!m_shadowMapPool.empty()) 368 | { 369 | m_shadowMapPool.back().ShadowMap.OnDestroy(); 370 | m_shadowMapPool.pop_back(); 371 | } 372 | } 373 | 374 | void Renderer::AllocateShadowMaps(GLTFCommon* pGLTFCommon) 375 | { 376 | // Go through the lights and allocate shadow information 377 | uint32_t NumShadows = 0; 378 | for (int i = 0; i < pGLTFCommon->m_lightInstances.size(); ++i) 379 | { 380 | const tfLight& lightData = pGLTFCommon->m_lights[pGLTFCommon->m_lightInstances[i].m_lightId]; 381 | if (lightData.m_shadowResolution) 382 | { 383 | SceneShadowInfo ShadowInfo; 384 | ShadowInfo.ShadowResolution = lightData.m_shadowResolution; 385 | ShadowInfo.ShadowIndex = NumShadows++; 386 | ShadowInfo.LightIndex = i; 387 | m_shadowMapPool.push_back(ShadowInfo); 388 | } 389 | } 390 | 391 | if (NumShadows > MaxShadowInstances) 392 | { 393 | Trace("Number of shadows has exceeded maximum supported. Please grow value in gltfCommon.h/perFrameStruct.h"); 394 | throw; 395 | } 396 | 397 | // If we had shadow information, allocate all required maps and bindings 398 | if (!m_shadowMapPool.empty()) 399 | { 400 | m_ResourceViewHeaps.AllocDSVDescriptor((uint32_t)m_shadowMapPool.size(), &m_ShadowMapPoolDSV); 401 | m_ResourceViewHeaps.AllocCBV_SRV_UAVDescriptor((uint32_t)m_shadowMapPool.size(), &m_ShadowMapPoolSRV); 402 | 403 | std::vector::iterator CurrentShadow = m_shadowMapPool.begin(); 404 | for( uint32_t i = 0; CurrentShadow < m_shadowMapPool.end(); ++i, ++CurrentShadow) 405 | { 406 | CurrentShadow->ShadowMap.InitDepthStencil(m_pDevice, "m_pShadowMap", &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_D32_FLOAT, CurrentShadow->ShadowResolution, CurrentShadow->ShadowResolution, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)); 407 | CurrentShadow->ShadowMap.CreateDSV(CurrentShadow->ShadowIndex, &m_ShadowMapPoolDSV); 408 | CurrentShadow->ShadowMap.CreateSRV(CurrentShadow->ShadowIndex, &m_ShadowMapPoolSRV); 409 | } 410 | } 411 | } 412 | 413 | //-------------------------------------------------------------------------------------- 414 | // 415 | // OnRender 416 | // 417 | //-------------------------------------------------------------------------------------- 418 | void Renderer::OnRender(const UIState* pState, const Camera& Cam, SwapChain* pSwapChain) 419 | { 420 | // Timing values 421 | UINT64 gpuTicksPerSecond; 422 | m_pDevice->GetGraphicsQueue()->GetTimestampFrequency(&gpuTicksPerSecond); 423 | 424 | // Let our resource managers do some house keeping 425 | m_CommandListRing.OnBeginFrame(); 426 | m_ConstantBufferRing.OnBeginFrame(); 427 | m_GPUTimer.OnBeginFrame(gpuTicksPerSecond, &m_TimeStamps); 428 | 429 | // Sets the perFrame data 430 | per_frame *pPerFrame = NULL; 431 | if (m_pGLTFTexturesAndBuffers) 432 | { 433 | // fill as much as possible using the GLTF (camera, lights, ...) 434 | pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(Cam); 435 | 436 | // Set some lighting factors 437 | pPerFrame->iblFactor = pState->IBLFactor; 438 | pPerFrame->emmisiveFactor = pState->EmissiveFactor; 439 | pPerFrame->invScreenResolution[0] = 1.0f / ((float)m_Width); 440 | pPerFrame->invScreenResolution[1] = 1.0f / ((float)m_Height); 441 | 442 | pPerFrame->wireframeOptions.setX(pState->WireframeColor[0]); 443 | pPerFrame->wireframeOptions.setY(pState->WireframeColor[1]); 444 | pPerFrame->wireframeOptions.setZ(pState->WireframeColor[2]); 445 | pPerFrame->wireframeOptions.setW(pState->WireframeMode == UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR ? 1.0f : 0.0f); 446 | pPerFrame->lodBias = 0.0f; 447 | m_pGLTFTexturesAndBuffers->SetPerFrameConstants(); 448 | m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons(); 449 | } 450 | 451 | // command buffer calls 452 | ID3D12GraphicsCommandList* pCmdLst1 = m_CommandListRing.GetNewCommandList(); 453 | 454 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Begin Frame"); 455 | 456 | pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); 457 | 458 | // Render shadow maps 459 | std::vector ShadowReadBarriers; 460 | std::vector ShadowWriteBarriers; 461 | if (m_GLTFDepth && pPerFrame != NULL) 462 | { 463 | std::vector::iterator ShadowMap = m_shadowMapPool.begin(); 464 | while (ShadowMap < m_shadowMapPool.end()) 465 | { 466 | pCmdLst1->ClearDepthStencilView(m_ShadowMapPoolDSV.GetCPU(ShadowMap->ShadowIndex), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); 467 | ++ShadowMap; 468 | } 469 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Clear shadow maps"); 470 | 471 | // Render all shadows 472 | ShadowMap = m_shadowMapPool.begin(); 473 | while (ShadowMap < m_shadowMapPool.end()) 474 | { 475 | SetViewportAndScissor(pCmdLst1, 0, 0, ShadowMap->ShadowResolution, ShadowMap->ShadowResolution); 476 | pCmdLst1->OMSetRenderTargets(0, NULL, false, &m_ShadowMapPoolDSV.GetCPU(ShadowMap->ShadowIndex)); 477 | 478 | per_frame* cbDepthPerFrame = m_GLTFDepth->SetPerFrameConstants(); 479 | cbDepthPerFrame->mCameraCurrViewProj = pPerFrame->lights[ShadowMap->LightIndex].mLightViewProj; 480 | cbDepthPerFrame->lodBias = 0.0f; 481 | 482 | m_GLTFDepth->Draw(pCmdLst1); 483 | 484 | // Push a barrier 485 | ShadowReadBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(ShadowMap->ShadowMap.GetResource(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); 486 | ShadowWriteBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(ShadowMap->ShadowMap.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); 487 | 488 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Shadow map"); 489 | ++ShadowMap; 490 | } 491 | 492 | // Transition all shadow map barriers 493 | pCmdLst1->ResourceBarrier((UINT)ShadowReadBarriers.size(), ShadowReadBarriers.data()); 494 | } 495 | 496 | // Shadow resolve --------------------------------------------------------------------------- 497 | #if USE_SHADOWMASK 498 | if (pPerFrame != NULL) 499 | { 500 | const D3D12_RESOURCE_BARRIER preShadowResolve[] = 501 | { 502 | CD3DX12_RESOURCE_BARRIER::Transition(m_ShadowMask.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS), 503 | CD3DX12_RESOURCE_BARRIER::Transition(m_MotionVectorsDepthMap.GetResource(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE) 504 | }; 505 | pCmdLst1->ResourceBarrier(ARRAYSIZE(preShadowResolve), preShadowResolve); 506 | 507 | ShadowResolveFrame shadowResolveFrame; 508 | shadowResolveFrame.m_Width = m_Width; 509 | shadowResolveFrame.m_Height = m_Height; 510 | shadowResolveFrame.m_ShadowMapSRV = m_ShadowMapSRV; 511 | shadowResolveFrame.m_DepthBufferSRV = m_MotionVectorsDepthMapSRV; 512 | shadowResolveFrame.m_ShadowBufferUAV = m_ShadowMaskUAV; 513 | 514 | m_shadowResolve.Draw(pCmdLst1, m_pGLTFTexturesAndBuffers, &shadowResolveFrame); 515 | 516 | const D3D12_RESOURCE_BARRIER postShadowResolve[] = 517 | { 518 | CD3DX12_RESOURCE_BARRIER::Transition(m_ShadowMask.GetResource(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), 519 | CD3DX12_RESOURCE_BARRIER::Transition(m_MotionVectorsDepthMap.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE) 520 | }; 521 | pCmdLst1->ResourceBarrier(ARRAYSIZE(postShadowResolve), postShadowResolve); 522 | } 523 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Shadow resolve"); 524 | #endif 525 | 526 | // Render Scene to the GBuffer ------------------------------------------------ 527 | if (pPerFrame != NULL) 528 | { 529 | pCmdLst1->RSSetViewports(1, &m_Viewport); 530 | pCmdLst1->RSSetScissorRects(1, &m_RectScissor); 531 | 532 | if (m_GLTFPBR) 533 | { 534 | const bool bWireframe = pState->WireframeMode != UIState::WireframeMode::WIREFRAME_MODE_OFF; 535 | 536 | std::vector opaque, transparent; 537 | m_GLTFPBR->BuildBatchLists(&opaque, &transparent, bWireframe); 538 | 539 | // Render opaque geometry 540 | { 541 | m_RenderPassFullGBuffer.BeginPass(pCmdLst1, true); 542 | #if USE_SHADOWMASK 543 | m_GLTFPBR->DrawBatchList(pCmdLst1, &m_ShadowMaskSRV, &solid, bWireframe); 544 | #else 545 | m_GLTFPBR->DrawBatchList(pCmdLst1, &m_ShadowMapPoolSRV, &opaque, bWireframe); 546 | #endif 547 | m_GPUTimer.GetTimeStamp(pCmdLst1, "PBR Opaque"); 548 | m_RenderPassFullGBuffer.EndPass(); 549 | } 550 | 551 | // draw skydome 552 | { 553 | m_RenderPassJustDepthAndHdr.BeginPass(pCmdLst1, false); 554 | 555 | // Render skydome 556 | if (pState->SelectedSkydomeTypeIndex == 1) 557 | { 558 | math::Matrix4 clipToView = math::inverse(pPerFrame->mCameraCurrViewProj); 559 | m_SkyDome.Draw(pCmdLst1, clipToView); 560 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Skydome cube"); 561 | } 562 | else if (pState->SelectedSkydomeTypeIndex == 0) 563 | { 564 | SkyDomeProc::Constants skyDomeConstants; 565 | skyDomeConstants.invViewProj = math::inverse(pPerFrame->mCameraCurrViewProj); 566 | skyDomeConstants.vSunDirection = math::Vector4(1.0f, 0.05f, 0.0f, 0.0f); 567 | skyDomeConstants.turbidity = 10.0f; 568 | skyDomeConstants.rayleigh = 2.0f; 569 | skyDomeConstants.mieCoefficient = 0.005f; 570 | skyDomeConstants.mieDirectionalG = 0.8f; 571 | skyDomeConstants.luminance = 1.0f; 572 | m_SkyDomeProc.Draw(pCmdLst1, skyDomeConstants); 573 | 574 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Skydome proc"); 575 | } 576 | 577 | m_RenderPassJustDepthAndHdr.EndPass(); 578 | } 579 | 580 | // draw transparent geometry 581 | { 582 | m_RenderPassFullGBuffer.BeginPass(pCmdLst1, false); 583 | 584 | std::sort(transparent.begin(), transparent.end()); 585 | m_GLTFPBR->DrawBatchList(pCmdLst1, &m_ShadowMapPoolSRV, &transparent, bWireframe); 586 | m_GPUTimer.GetTimeStamp(pCmdLst1, "PBR Transparent"); 587 | 588 | m_RenderPassFullGBuffer.EndPass(); 589 | } 590 | } 591 | 592 | // draw object's bounding boxes 593 | if (m_GLTFBBox && pPerFrame != NULL) 594 | { 595 | if (pState->bDrawBoundingBoxes) 596 | { 597 | m_GLTFBBox->Draw(pCmdLst1, pPerFrame->mCameraCurrViewProj); 598 | 599 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Bounding Box"); 600 | } 601 | } 602 | 603 | // draw light's frustums 604 | if (pState->bDrawLightFrustum && pPerFrame != NULL) 605 | { 606 | UserMarker marker(pCmdLst1, "light frustrums"); 607 | 608 | math::Vector4 vCenter = math::Vector4(0.0f, 0.0f, 0.5f, 0.0f); 609 | math::Vector4 vRadius = math::Vector4(1.0f, 1.0f, 0.5f, 0.0f); 610 | math::Vector4 vColor = math::Vector4(1.0f, 1.0f, 1.0f, 1.0f); 611 | for (uint32_t i = 0; i < pPerFrame->lightCount; i++) 612 | { 613 | math::Matrix4 spotlightMatrix = math::inverse(pPerFrame->lights[i].mLightViewProj); // XMMatrixInverse(NULL, pPerFrame->lights[i].mLightViewProj); 614 | math::Matrix4 worldMatrix = pPerFrame->mCameraCurrViewProj * spotlightMatrix; //spotlightMatrix * pPerFrame->mCameraCurrViewProj; 615 | m_WireframeBox.Draw(pCmdLst1, &m_Wireframe, worldMatrix, vCenter, vRadius, vColor); 616 | } 617 | 618 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Light's frustum"); 619 | } 620 | } 621 | 622 | if (ShadowWriteBarriers.size()) 623 | pCmdLst1->ResourceBarrier((UINT)ShadowWriteBarriers.size(), ShadowWriteBarriers.data()); 624 | 625 | D3D12_RESOURCE_BARRIER preResolve[1] = { 626 | CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), 627 | }; 628 | pCmdLst1->ResourceBarrier(1, preResolve); 629 | 630 | // Post proc--------------------------------------------------------------------------- 631 | 632 | // Bloom, takes HDR as input and applies bloom to it. 633 | { 634 | D3D12_CPU_DESCRIPTOR_HANDLE renderTargets[] = { m_GBuffer.m_HDRRTV.GetCPU() }; 635 | pCmdLst1->OMSetRenderTargets(ARRAYSIZE(renderTargets), renderTargets, false, NULL); 636 | 637 | m_DownSample.Draw(pCmdLst1); 638 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Downsample"); 639 | 640 | m_Bloom.Draw(pCmdLst1, &m_GBuffer.m_HDR); 641 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Bloom"); 642 | } 643 | 644 | // Apply TAA & Sharpen to m_HDR 645 | if (pState->bUseTAA) 646 | { 647 | m_TAA.Draw(pCmdLst1, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); 648 | m_GPUTimer.GetTimeStamp(pCmdLst1, "TAA"); 649 | } 650 | 651 | // Magnifier Pass: m_HDR as input, pass' own output 652 | if (pState->bUseMagnifier) 653 | { 654 | // Note: assumes m_GBuffer.HDR is in D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE 655 | m_MagnifierPS.Draw(pCmdLst1, pState->MagnifierParams, m_GBuffer.m_HDRSRV); 656 | m_GPUTimer.GetTimeStamp(pCmdLst1, "Magnifier"); 657 | 658 | // Transition magnifier state to PIXEL_SHADER_RESOURCE, as it is going to be pRscCurrentInput replacing m_GBuffer.m_HDR which is in that state. 659 | pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_MagnifierPS.GetPassOutputResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); 660 | } 661 | 662 | // Start tracking input/output resources at this point to handle HDR and SDR render paths 663 | ID3D12Resource* pRscCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputResource() : m_GBuffer.m_HDR.GetResource(); 664 | CBV_SRV_UAV SRVCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputSRV() : m_GBuffer.m_HDRSRV; 665 | D3D12_CPU_DESCRIPTOR_HANDLE RTVCurrentOutput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputRTV().GetCPU() : m_GBuffer.m_HDRRTV.GetCPU(); 666 | CBV_SRV_UAV UAVCurrentOutput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputUAV() : m_GBuffer.m_HDRUAV; 667 | 668 | 669 | // 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 670 | const bool bHDR = pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR; 671 | if (bHDR) 672 | { 673 | // In place Tonemapping ------------------------------------------------------------------------ 674 | { 675 | D3D12_RESOURCE_BARRIER inputRscToUAV = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); 676 | pCmdLst1->ResourceBarrier(1, &inputRscToUAV); 677 | 678 | m_ToneMappingCS.Draw(pCmdLst1, &UAVCurrentOutput, pState->Exposure, pState->SelectedTonemapperIndex, m_Width, m_Height); 679 | 680 | D3D12_RESOURCE_BARRIER inputRscToRTV = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RENDER_TARGET); 681 | pCmdLst1->ResourceBarrier(1, &inputRscToRTV); 682 | } 683 | 684 | // Render HUD ------------------------------------------------------------------------ 685 | { 686 | pCmdLst1->RSSetViewports(1, &m_Viewport); 687 | pCmdLst1->RSSetScissorRects(1, &m_RectScissor); 688 | pCmdLst1->OMSetRenderTargets(1, &RTVCurrentOutput, true, NULL); 689 | 690 | m_ImGUI.Draw(pCmdLst1); 691 | 692 | D3D12_RESOURCE_BARRIER hdrToSRV = CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); 693 | pCmdLst1->ResourceBarrier(1, &hdrToSRV); 694 | 695 | m_GPUTimer.GetTimeStamp(pCmdLst1, "ImGUI Rendering"); 696 | } 697 | } 698 | 699 | // submit command buffer #1 700 | ThrowIfFailed(pCmdLst1->Close()); 701 | ID3D12CommandList* CmdListList1[] = { pCmdLst1 }; 702 | m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList1); 703 | 704 | // Wait for swapchain (we are going to render to it) ----------------------------------- 705 | pSwapChain->WaitForSwapChain(); 706 | 707 | // Keep tracking input/output resource views 708 | pRscCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputResource() : m_GBuffer.m_HDR.GetResource(); // these haven't changed, re-assign as sanity check 709 | SRVCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputSRV() : m_GBuffer.m_HDRSRV; // these haven't changed, re-assign as sanity check 710 | RTVCurrentOutput = *pSwapChain->GetCurrentBackBufferRTV(); 711 | UAVCurrentOutput = {}; // no BackBufferUAV. 712 | 713 | 714 | ID3D12GraphicsCommandList* pCmdLst2 = m_CommandListRing.GetNewCommandList(); 715 | 716 | pCmdLst2->RSSetViewports(1, &m_Viewport); 717 | pCmdLst2->RSSetScissorRects(1, &m_RectScissor); 718 | pCmdLst2->OMSetRenderTargets(1, pSwapChain->GetCurrentBackBufferRTV(), true, NULL); 719 | 720 | if (bHDR) 721 | { 722 | // FS HDR mode! Apply color conversion now. 723 | m_ColorConversionPS.Draw(pCmdLst2, &SRVCurrentInput); 724 | m_GPUTimer.GetTimeStamp(pCmdLst2, "Color conversion"); 725 | 726 | pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); 727 | } 728 | else 729 | { 730 | // non FreeSync HDR mode, that is SDR, here we apply the tonemapping from the HDR into the swapchain and then we render the GUI 731 | 732 | // Tonemapping ------------------------------------------------------------------------ 733 | { 734 | m_ToneMappingPS.Draw(pCmdLst2, &SRVCurrentInput, pState->Exposure, pState->SelectedTonemapperIndex); 735 | m_GPUTimer.GetTimeStamp(pCmdLst2, "Tone mapping"); 736 | 737 | pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pRscCurrentInput, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); 738 | } 739 | 740 | // Render HUD ------------------------------------------------------------------------ 741 | { 742 | m_ImGUI.Draw(pCmdLst2); 743 | m_GPUTimer.GetTimeStamp(pCmdLst2, "ImGUI Rendering"); 744 | } 745 | } 746 | 747 | // If magnifier is used, make sure m_GBuffer.m_HDR which is not pRscCurrentInput gets reverted back to RT state. 748 | if (pState->bUseMagnifier) 749 | pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); 750 | 751 | if (!m_pScreenShotName.empty()) 752 | { 753 | m_SaveTexture.CopyRenderTargetIntoStagingTexture(m_pDevice->GetDevice(), pCmdLst2, pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_RENDER_TARGET); 754 | } 755 | 756 | // Transition swapchain into present mode 757 | 758 | pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); 759 | 760 | m_GPUTimer.OnEndFrame(); 761 | 762 | m_GPUTimer.CollectTimings(pCmdLst2); 763 | 764 | // Close & Submit the command list #2 ------------------------------------------------- 765 | ThrowIfFailed(pCmdLst2->Close()); 766 | 767 | ID3D12CommandList* CmdListList2[] = { pCmdLst2 }; 768 | m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList2); 769 | 770 | // Handle screenshot request 771 | if (!m_pScreenShotName.empty()) 772 | { 773 | m_SaveTexture.SaveStagingTextureAsJpeg(m_pDevice->GetDevice(), m_pDevice->GetGraphicsQueue(), m_pScreenShotName.c_str()); 774 | m_pScreenShotName.clear(); 775 | } 776 | } 777 | -------------------------------------------------------------------------------- /src/DX12/Renderer.h: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2020 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 | 26 | struct UIState; 27 | 28 | // We are queuing (backBufferCount + 0.5) frames, so we need to triple buffer the resources that get modified each frame 29 | static const int backBufferCount = 3; 30 | 31 | #define USE_SHADOWMASK false 32 | 33 | using namespace CAULDRON_DX12; 34 | 35 | // 36 | // Renderer class is responsible for rendering resources management and recording command buffers. 37 | class Renderer 38 | { 39 | public: 40 | void OnCreate(Device* pDevice, SwapChain *pSwapChain, float FontSize); 41 | void OnDestroy(); 42 | 43 | void OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height); 44 | void OnDestroyWindowSizeDependentResources(); 45 | 46 | void OnUpdateDisplayDependentResources(SwapChain *pSwapChain); 47 | 48 | int LoadScene(GLTFCommon *pGLTFCommon, int Stage = 0); 49 | void UnloadScene(); 50 | 51 | void AllocateShadowMaps(GLTFCommon* pGLTFCommon); 52 | 53 | const std::vector& GetTimingValues() const { return m_TimeStamps; } 54 | std::string& GetScreenshotFileName() { return m_pScreenShotName; } 55 | 56 | void OnRender(const UIState* pState, const Camera& Cam, SwapChain* pSwapChain); 57 | 58 | private: 59 | Device *m_pDevice; 60 | 61 | uint32_t m_Width; 62 | uint32_t m_Height; 63 | D3D12_VIEWPORT m_Viewport; 64 | D3D12_RECT m_RectScissor; 65 | bool m_HasTAA = false; 66 | 67 | // Initialize helper classes 68 | ResourceViewHeaps m_ResourceViewHeaps; 69 | UploadHeap m_UploadHeap; 70 | DynamicBufferRing m_ConstantBufferRing; 71 | StaticBufferPool m_VidMemBufferPool; 72 | CommandListRing m_CommandListRing; 73 | GPUTimestamps m_GPUTimer; 74 | 75 | //gltf passes 76 | GltfPbrPass *m_GLTFPBR; 77 | GltfBBoxPass *m_GLTFBBox; 78 | GltfDepthPass *m_GLTFDepth; 79 | GLTFTexturesAndBuffers *m_pGLTFTexturesAndBuffers; 80 | 81 | // effects 82 | Bloom m_Bloom; 83 | SkyDome m_SkyDome; 84 | DownSamplePS m_DownSample; 85 | SkyDomeProc m_SkyDomeProc; 86 | ToneMapping m_ToneMappingPS; 87 | ToneMappingCS m_ToneMappingCS; 88 | ColorConversionPS m_ColorConversionPS; 89 | TAA m_TAA; 90 | MagnifierPS m_MagnifierPS; 91 | 92 | // GUI 93 | ImGUI m_ImGUI; 94 | 95 | // Temporary render targets 96 | GBuffer m_GBuffer; 97 | GBufferRenderPass m_RenderPassFullGBuffer; 98 | GBufferRenderPass m_RenderPassJustDepthAndHdr; 99 | 100 | Texture m_MotionVectorsDepthMap; 101 | DSV m_MotionVectorsDepthMapDSV; 102 | CBV_SRV_UAV m_MotionVectorsDepthMapSRV; 103 | 104 | #if USE_SHADOWMASK 105 | // shadow mask 106 | Texture m_ShadowMask; 107 | CBV_SRV_UAV m_ShadowMaskUAV; 108 | CBV_SRV_UAV m_ShadowMaskSRV; 109 | ShadowResolvePass m_shadowResolve; 110 | #endif 111 | 112 | // shadowmaps 113 | typedef struct { 114 | Texture ShadowMap; 115 | uint32_t ShadowIndex; 116 | uint32_t ShadowResolution; 117 | uint32_t LightIndex; 118 | } SceneShadowInfo; 119 | 120 | std::vector m_shadowMapPool; 121 | DSV m_ShadowMapPoolDSV; 122 | CBV_SRV_UAV m_ShadowMapPoolSRV; 123 | 124 | // widgets 125 | Wireframe m_Wireframe; 126 | WireframeBox m_WireframeBox; 127 | 128 | std::vector m_TimeStamps; 129 | 130 | // screen shot 131 | std::string m_pScreenShotName = ""; 132 | SaveTexture m_SaveTexture; 133 | AsyncPool m_AsyncPool; 134 | }; 135 | -------------------------------------------------------------------------------- /src/DX12/UI.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2020 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", ImGuiTreeNodeFlags_DefaultOpen)) 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 | 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", ImGuiTreeNodeFlags_DefaultOpen)) 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", ImGuiTreeNodeFlags_DefaultOpen)) 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", ImGuiTreeNodeFlags_DefaultOpen)) 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", "ExclusiveFulscreen" }; 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 (m_FreesyncHDROptionEnabled && ImGui::CollapsingHeader("FreeSync HDR", ImGuiTreeNodeFlags_DefaultOpen)) 230 | { 231 | static bool openWarning = false; 232 | const char** displayModeNames = &m_displayModesNamesAvailable[0]; 233 | if (ImGui::Combo("Display Mode", (int*)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) 234 | { 235 | if (m_fullscreenMode != PRESENTATIONMODE_WINDOWED) 236 | { 237 | UpdateDisplay(m_disableLocalDimming); 238 | m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; 239 | } 240 | else if (CheckIfWindowModeHdrOn() && 241 | (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_SDR || 242 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_2084 || 243 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_SCRGB)) 244 | { 245 | UpdateDisplay(m_disableLocalDimming); 246 | m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; 247 | } 248 | else 249 | { 250 | openWarning = true; 251 | m_currentDisplayModeNamesIndex = m_previousDisplayModeNamesIndex; 252 | } 253 | } 254 | 255 | if (openWarning) 256 | { 257 | ImGui::OpenPopup("Display Modes Warning"); 258 | ImGui::BeginPopupModal("Display Modes Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize); 259 | 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"); 260 | if (ImGui::Button("Cancel", ImVec2(120, 0))) { openWarning = false; ImGui::CloseCurrentPopup(); } 261 | ImGui::EndPopup(); 262 | } 263 | 264 | if (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_Gamma22 || 265 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_SCRGB) 266 | { 267 | static bool selectedDisableLocaldimmingSetting = false; 268 | if (ImGui::Checkbox("Disable Local Dimming", &selectedDisableLocaldimmingSetting)) 269 | UpdateDisplay(selectedDisableLocaldimmingSetting); 270 | } 271 | } 272 | 273 | ImGui::End(); // CONTROLS 274 | } 275 | 276 | 277 | // Render PROFILER window 278 | // 279 | if (m_UIState.bShowProfilerWindow) 280 | { 281 | constexpr size_t NUM_FRAMES = 128; 282 | static float FRAME_TIME_ARRAY[NUM_FRAMES] = { 0 }; 283 | 284 | // track highest frame rate and determine the max value of the graph based on the measured highest value 285 | static float RECENT_HIGHEST_FRAME_TIME = 0.0f; 286 | constexpr int FRAME_TIME_GRAPH_MAX_FPS[] = { 800, 240, 120, 90, 60, 45, 30, 15, 10, 5, 4, 3, 2, 1 }; 287 | static float FRAME_TIME_GRAPH_MAX_VALUES[_countof(FRAME_TIME_GRAPH_MAX_FPS)] = { 0 }; // us 288 | 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]; } 289 | 290 | //scrolling data and average FPS computing 291 | const std::vector& timeStamps = m_pRenderer->GetTimingValues(); 292 | const bool bTimeStampsAvailable = timeStamps.size() > 0; 293 | if (bTimeStampsAvailable) 294 | { 295 | RECENT_HIGHEST_FRAME_TIME = 0; 296 | FRAME_TIME_ARRAY[NUM_FRAMES - 1] = timeStamps.back().m_microseconds; 297 | for (uint32_t i = 0; i < NUM_FRAMES - 1; i++) 298 | { 299 | FRAME_TIME_ARRAY[i] = FRAME_TIME_ARRAY[i + 1]; 300 | } 301 | RECENT_HIGHEST_FRAME_TIME = max(RECENT_HIGHEST_FRAME_TIME, FRAME_TIME_ARRAY[NUM_FRAMES - 1]); 302 | } 303 | const float& frameTime_us = FRAME_TIME_ARRAY[NUM_FRAMES - 1]; 304 | const float frameTime_ms = frameTime_us * 0.001f; 305 | const int fps = bTimeStampsAvailable ? static_cast(1000000.0f / frameTime_us) : 0; 306 | 307 | // UI 308 | ImGui::SetNextWindowPos(ImVec2((float)PROFILER_WINDOW_POS_X, (float)PROFILER_WINDOW_POS_Y), ImGuiCond_FirstUseEver); 309 | ImGui::SetNextWindowSize(ImVec2(PROFILER_WINDOW_SIZE_X, PROFILER_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); 310 | ImGui::Begin("PROFILER (F2)", &m_UIState.bShowProfilerWindow); 311 | 312 | ImGui::Text("Resolution : %ix%i", m_Width, m_Height); 313 | ImGui::Text("API : %s", m_systemInfo.mGfxAPI.c_str()); 314 | ImGui::Text("GPU : %s", m_systemInfo.mGPUName.c_str()); 315 | ImGui::Text("CPU : %s", m_systemInfo.mCPUName.c_str()); 316 | ImGui::Text("FPS : %d (%.2f ms)", fps, frameTime_ms); 317 | 318 | if (ImGui::CollapsingHeader("GPU Timings", ImGuiTreeNodeFlags_DefaultOpen)) 319 | { 320 | std::string msOrUsButtonText = m_UIState.bShowMilliseconds ? "Switch to microseconds" : "Switch to milliseconds"; 321 | if (ImGui::Button(msOrUsButtonText.c_str())) { 322 | m_UIState.bShowMilliseconds = !m_UIState.bShowMilliseconds; 323 | } 324 | ImGui::Spacing(); 325 | 326 | if (m_isCpuValidationLayerEnabled || m_isGpuValidationLayerEnabled) 327 | { 328 | ImGui::TextColored(ImVec4(1,1,0,1), "WARNING: Validation layer is switched on"); 329 | ImGui::Text("Performance numbers may be inaccurate!"); 330 | } 331 | 332 | // find the index of the FrameTimeGraphMaxValue as the next higher-than-recent-highest-frame-time in the pre-determined value list 333 | size_t iFrameTimeGraphMaxValue = 0; 334 | for (int i = 0; i < _countof(FRAME_TIME_GRAPH_MAX_VALUES); ++i) 335 | { 336 | if (RECENT_HIGHEST_FRAME_TIME < FRAME_TIME_GRAPH_MAX_VALUES[i]) // FRAME_TIME_GRAPH_MAX_VALUES are in increasing order 337 | { 338 | iFrameTimeGraphMaxValue = min(_countof(FRAME_TIME_GRAPH_MAX_VALUES) - 1, i + 1); 339 | break; 340 | } 341 | } 342 | ImGui::PlotLines("", FRAME_TIME_ARRAY, NUM_FRAMES, 0, "GPU frame time (us)", 0.0f, FRAME_TIME_GRAPH_MAX_VALUES[iFrameTimeGraphMaxValue], ImVec2(0, 80)); 343 | 344 | for (uint32_t i = 0; i < timeStamps.size(); i++) 345 | { 346 | float value = m_UIState.bShowMilliseconds ? timeStamps[i].m_microseconds / 1000.0f : timeStamps[i].m_microseconds; 347 | const char* pStrUnit = m_UIState.bShowMilliseconds ? "ms" : "us"; 348 | ImGui::Text("%-18s: %7.2f %s", timeStamps[i].m_label.c_str(), value, pStrUnit); 349 | } 350 | } 351 | ImGui::End(); // PROFILER 352 | } 353 | } 354 | 355 | void UIState::Initialize() 356 | { 357 | // init magnifier params 358 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; // start at 'free' state 359 | 360 | // init GUI state 361 | this->SelectedTonemapperIndex = 0; 362 | this->bUseTAA = true; 363 | this->bUseMagnifier = false; 364 | this->bLockMagnifierPosition = this->bLockMagnifierPositionHistory = false; 365 | this->SelectedSkydomeTypeIndex = 0; 366 | this->Exposure = 1.0f; 367 | this->IBLFactor = 2.0f; 368 | this->EmissiveFactor = 1.0f; 369 | this->bDrawLightFrustum = false; 370 | this->bDrawBoundingBoxes = false; 371 | this->WireframeMode = WireframeMode::WIREFRAME_MODE_OFF; 372 | this->WireframeColor[0] = 0.0f; 373 | this->WireframeColor[1] = 1.0f; 374 | this->WireframeColor[2] = 0.0f; 375 | this->bShowControlsWindow = true; 376 | this->bShowProfilerWindow = true; 377 | } 378 | 379 | 380 | 381 | // 382 | // Magnifier UI Controls 383 | // 384 | void UIState::ToggleMagnifierLock() 385 | { 386 | if (this->bUseMagnifier) 387 | { 388 | this->bLockMagnifierPositionHistory = this->bLockMagnifierPosition; // record histroy 389 | this->bLockMagnifierPosition = !this->bLockMagnifierPosition; // flip state 390 | const bool bLockSwitchedOn = !this->bLockMagnifierPositionHistory && this->bLockMagnifierPosition; 391 | const bool bLockSwitchedOff = this->bLockMagnifierPositionHistory && !this->bLockMagnifierPosition; 392 | if (bLockSwitchedOn) 393 | { 394 | const ImGuiIO& io = ImGui::GetIO(); 395 | this->LockedMagnifiedScreenPositionX = static_cast(io.MousePos.x); 396 | this->LockedMagnifiedScreenPositionY = static_cast(io.MousePos.y); 397 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__LOCKED[ch]; 398 | } 399 | else if (bLockSwitchedOff) 400 | { 401 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; 402 | } 403 | } 404 | } 405 | 406 | // These are currently not bound to any mouse input and are here for convenience/reference. 407 | // Mouse scroll is currently wired up to camera for panning and moving in the local Z direction. 408 | // Any application that would prefer otherwise can utilize these for easily controlling the magnifier parameters through the desired input. 409 | void UIState::AdjustMagnifierSize (float increment /*= 0.05f*/){ MagnifierParams.fMagnifierScreenRadius = clamped(MagnifierParams.fMagnifierScreenRadius + increment, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); } 410 | void UIState::AdjustMagnifierMagnification(float increment /*= 1.00f*/){ MagnifierParams.fMagnificationAmount = clamped(MagnifierParams.fMagnificationAmount + increment, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); } 411 | -------------------------------------------------------------------------------- /src/DX12/UI.h: -------------------------------------------------------------------------------- 1 | // AMD SampleDX12 sample code 2 | // 3 | // Copyright(c) 2020 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 | // 34 | // POST PROCESS CONTROLS 35 | // 36 | int SelectedTonemapperIndex; 37 | float Exposure; 38 | 39 | bool bUseTAA; 40 | 41 | bool bUseMagnifier; 42 | bool bLockMagnifierPosition; 43 | bool bLockMagnifierPositionHistory; 44 | int LockedMagnifiedScreenPositionX; 45 | int LockedMagnifiedScreenPositionY; 46 | CAULDRON_DX12::MagnifierPS::PassParameters MagnifierParams; 47 | 48 | 49 | // 50 | // APP/SCENE CONTROLS 51 | // 52 | float IBLFactor; 53 | float EmissiveFactor; 54 | 55 | int SelectedSkydomeTypeIndex; 56 | bool bDrawBoundingBoxes; 57 | bool bDrawLightFrustum; 58 | 59 | enum class WireframeMode : int 60 | { 61 | WIREFRAME_MODE_OFF = 0, 62 | WIREFRAME_MODE_SHADED = 1, 63 | WIREFRAME_MODE_SOLID_COLOR = 2, 64 | }; 65 | 66 | WireframeMode WireframeMode; 67 | float WireframeColor[3]; 68 | 69 | // 70 | // PROFILER CONTROLS 71 | // 72 | bool bShowMilliseconds; 73 | 74 | // ----------------------------------------------- 75 | 76 | void Initialize(); 77 | 78 | void ToggleMagnifierLock(); 79 | void AdjustMagnifierSize(float increment = 0.05f); 80 | void AdjustMagnifierMagnification(float increment = 1.00f); 81 | }; -------------------------------------------------------------------------------- /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 | // Windows Header Files: 9 | #include 10 | #include 11 | 12 | // C RunTime Header Files 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "../../libs/d3d12x/d3dx12.h" 20 | 21 | // Pull in math library 22 | #include "../../libs/vectormath/vectormath.hpp" 23 | 24 | // TODO: reference additional headers your program requires here 25 | #include "Base/Imgui.h" 26 | #include "Base/ImguiHelper.h" 27 | #include "Base/Fence.h" 28 | #include "Base/Helper.h" 29 | #include "Base/Device.h" 30 | #include "Base/Texture.h" 31 | #include "Base/FrameworkWindows.h" 32 | #include "Base/FreeSyncHDR.h" 33 | #include "Base/SwapChain.h" 34 | #include "Base/UploadHeap.h" 35 | #include "Base/SaveTexture.h" 36 | #include "Base/UserMarkers.h" 37 | #include "Base/GPUTimestamps.h" 38 | #include "Base/CommandListRing.h" 39 | #include "Base/StaticBufferPool.h" 40 | #include "Base/DynamicBufferRing.h" 41 | #include "Base/ResourceViewHeaps.h" 42 | #include "Base/ShaderCompilerCache.h" 43 | #include "Base/ShaderCompilerHelper.h" 44 | #include "Base/StaticConstantBufferPool.h" 45 | 46 | #include "GLTF/GltfPbrPass.h" 47 | #include "GLTF/GltfBBoxPass.h" 48 | #include "GLTF/GltfDepthPass.h" 49 | #include "GLTF/GltfMotionVectorsPass.h" 50 | 51 | #include "Misc/Misc.h" 52 | #include "Misc/Error.h" 53 | #include "Misc/Camera.h" 54 | 55 | #include "PostProc/TAA.h" 56 | #include "PostProc/Bloom.h" 57 | #include "PostProc/BlurPS.h" 58 | #include "PostProc/SkyDome.h" 59 | #include "PostProc/SkyDomeProc.h" 60 | #include "PostProc/PostProcCS.h" 61 | #include "PostProc/ToneMapping.h" 62 | #include "PostProc/ToneMappingCS.h" 63 | #include "PostProc/ColorConversionPS.h" 64 | #include "PostProc/DownSamplePS.h" 65 | #include "PostProc/ShadowResolvePass.h" 66 | 67 | #include "Widgets/wireframe.h" 68 | 69 | 70 | using namespace CAULDRON_DX12; 71 | -------------------------------------------------------------------------------- /src/VK/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_VK WIN32 ${sources} ${icon_src}) 16 | 17 | target_link_libraries(GLTFSample_VK LINK_PUBLIC GLTFSample_Common Cauldron_VK ImGUI Vulkan::Vulkan) 18 | 19 | set_target_properties(GLTFSample_VK PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin" DEBUG_POSTFIX "d") 20 | -------------------------------------------------------------------------------- /src/VK/GLTFSample.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleVK sample code 2 | // 3 | // Copyright(c) 2020 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 | #include "GLTFSample.h" 23 | 24 | GLTFSample::GLTFSample(LPCSTR name) : FrameworkWindows(name) 25 | { 26 | m_time = 0; 27 | m_bPlay = true; 28 | 29 | m_pGltfLoader = NULL; 30 | } 31 | 32 | //-------------------------------------------------------------------------------------- 33 | // 34 | // OnParseCommandLine 35 | // 36 | //-------------------------------------------------------------------------------------- 37 | void GLTFSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight) 38 | { 39 | // set some default values 40 | *pWidth = 1920; 41 | *pHeight = 1080; 42 | m_activeScene = 0; //load the first one by default 43 | m_bIsBenchmarking = false; 44 | m_VsyncEnabled = false; 45 | m_fontSize = 13.f; 46 | m_activeCamera = 0; 47 | 48 | // read globals 49 | auto process = [&](json jData) 50 | { 51 | *pWidth = jData.value("width", *pWidth); 52 | *pHeight = jData.value("height", *pHeight); 53 | m_fullscreenMode = jData.value("presentationMode", m_fullscreenMode); 54 | m_activeScene = jData.value("activeScene", m_activeScene); 55 | m_activeCamera = jData.value("activeCamera", m_activeCamera); 56 | m_isCpuValidationLayerEnabled = jData.value("CpuValidationLayerEnabled", m_isCpuValidationLayerEnabled); 57 | m_isGpuValidationLayerEnabled = jData.value("GpuValidationLayerEnabled", m_isGpuValidationLayerEnabled); 58 | m_VsyncEnabled = jData.value("vsync", m_VsyncEnabled); 59 | m_FreesyncHDROptionEnabled = jData.value("FreesyncHDROptionEnabled", m_FreesyncHDROptionEnabled); 60 | m_bIsBenchmarking = jData.value("benchmark", m_bIsBenchmarking); 61 | m_fontSize = jData.value("fontsize", m_fontSize); 62 | }; 63 | 64 | //read json globals from commandline 65 | // 66 | try 67 | { 68 | if (strlen(lpCmdLine) > 0) 69 | { 70 | auto j3 = json::parse(lpCmdLine); 71 | process(j3); 72 | } 73 | } 74 | catch (json::parse_error) 75 | { 76 | Trace("Error parsing commandline\n"); 77 | exit(0); 78 | } 79 | 80 | // read config file (and override values from commandline if so) 81 | // 82 | { 83 | std::ifstream f("GLTFSample.json"); 84 | if (!f) 85 | { 86 | MessageBox(NULL, "Config file not found!\n", "Cauldron Panic!", MB_ICONERROR); 87 | exit(0); 88 | } 89 | 90 | try 91 | { 92 | f >> m_jsonConfigFile; 93 | } 94 | catch (json::parse_error) 95 | { 96 | MessageBox(NULL, "Error parsing GLTFSample.json!\n", "Cauldron Panic!", MB_ICONERROR); 97 | exit(0); 98 | } 99 | } 100 | 101 | json globals = m_jsonConfigFile["globals"]; 102 | process(globals); 103 | 104 | // get the list of scenes 105 | for (const auto & scene : m_jsonConfigFile["scenes"]) 106 | m_sceneNames.push_back(scene["name"]); 107 | } 108 | 109 | //-------------------------------------------------------------------------------------- 110 | // 111 | // OnCreate 112 | // 113 | //-------------------------------------------------------------------------------------- 114 | void GLTFSample::OnCreate() 115 | { 116 | // Init the shader compiler 117 | InitDirectXCompiler(); 118 | CreateShaderCache(); 119 | 120 | // Create a instance of the renderer and initialize it, we need to do that for each GPU 121 | m_pRenderer = new Renderer(); 122 | m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); 123 | 124 | // init GUI (non gfx stuff) 125 | ImGUI_Init((void *)m_windowHwnd); 126 | m_UIState.Initialize(); 127 | 128 | OnResize(true); 129 | OnUpdateDisplay(); 130 | 131 | // Init Camera, looking at the origin 132 | m_camera.LookAt(math::Vector4(0, 0, 5, 0), math::Vector4(0, 0, 0, 0)); 133 | } 134 | 135 | //-------------------------------------------------------------------------------------- 136 | // 137 | // OnDestroy 138 | // 139 | //-------------------------------------------------------------------------------------- 140 | void GLTFSample::OnDestroy() 141 | { 142 | ImGUI_Shutdown(); 143 | 144 | m_device.GPUFlush(); 145 | 146 | m_pRenderer->UnloadScene(); 147 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 148 | m_pRenderer->OnDestroy(); 149 | 150 | delete m_pRenderer; 151 | 152 | // shut down the shader compiler 153 | DestroyShaderCache(&m_device); 154 | 155 | if (m_pGltfLoader) 156 | { 157 | delete m_pGltfLoader; 158 | m_pGltfLoader = NULL; 159 | } 160 | } 161 | 162 | //-------------------------------------------------------------------------------------- 163 | // 164 | // OnEvent, win32 sends us events and we forward them to ImGUI 165 | // 166 | //-------------------------------------------------------------------------------------- 167 | bool GLTFSample::OnEvent(MSG msg) 168 | { 169 | if (ImGUI_WndProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam)) 170 | return true; 171 | 172 | // handle function keys (F1, F2...) here, rest of the input is handled 173 | // by imGUI later in HandleInput() function 174 | const WPARAM& KeyPressed = msg.wParam; 175 | switch (msg.message) 176 | { 177 | case WM_KEYUP: 178 | case WM_SYSKEYUP: 179 | /* WINDOW TOGGLES */ 180 | if (KeyPressed == VK_F1) m_UIState.bShowControlsWindow ^= 1; 181 | if (KeyPressed == VK_F2) m_UIState.bShowProfilerWindow ^= 1; 182 | break; 183 | } 184 | 185 | return true; 186 | } 187 | 188 | //-------------------------------------------------------------------------------------- 189 | // 190 | // OnResize 191 | // 192 | //-------------------------------------------------------------------------------------- 193 | void GLTFSample::OnResize(bool resizeRender) 194 | { 195 | // destroy resources (if we are not minimized) 196 | if (resizeRender && m_Width && m_Height && m_pRenderer) 197 | { 198 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 199 | m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); 200 | } 201 | 202 | m_camera.SetFov(AMD_PI_OVER_4, m_Width, m_Height, 0.1f, 1000.0f); 203 | } 204 | 205 | //-------------------------------------------------------------------------------------- 206 | // 207 | // UpdateDisplay 208 | // 209 | //-------------------------------------------------------------------------------------- 210 | void GLTFSample::OnUpdateDisplay() 211 | { 212 | // Destroy resources (if we are not minimized) 213 | if (m_pRenderer) 214 | { 215 | m_pRenderer->OnUpdateDisplayDependentResources(&m_swapChain, m_UIState.bUseMagnifier); 216 | } 217 | } 218 | 219 | //-------------------------------------------------------------------------------------- 220 | // 221 | // LoadScene 222 | // 223 | //-------------------------------------------------------------------------------------- 224 | void GLTFSample::LoadScene(int sceneIndex) 225 | { 226 | json scene = m_jsonConfigFile["scenes"][sceneIndex]; 227 | 228 | // release everything and load the GLTF, just the light json data, the rest (textures and geometry) will be done in the main loop 229 | if (m_pGltfLoader != NULL) 230 | { 231 | m_pRenderer->UnloadScene(); 232 | m_pRenderer->OnDestroyWindowSizeDependentResources(); 233 | m_pRenderer->OnDestroy(); 234 | m_pGltfLoader->Unload(); 235 | m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); 236 | m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); 237 | } 238 | 239 | delete(m_pGltfLoader); 240 | m_pGltfLoader = new GLTFCommon(); 241 | if (m_pGltfLoader->Load(scene["directory"], scene["filename"]) == false) 242 | { 243 | MessageBox(NULL, "The selected model couldn't be found, please check the documentation", "Cauldron Panic!", MB_ICONERROR); 244 | exit(0); 245 | } 246 | 247 | 248 | // Load the UI settings, and also some defaults cameras and lights, in case the GLTF has none 249 | { 250 | #define LOAD(j, key, val) val = j.value(key, val) 251 | 252 | // global settings 253 | LOAD(scene, "TAA", m_UIState.bUseTAA); 254 | LOAD(scene, "toneMapper", m_UIState.SelectedTonemapperIndex); 255 | LOAD(scene, "skyDomeType", m_UIState.SelectedSkydomeTypeIndex); 256 | LOAD(scene, "exposure", m_UIState.Exposure); 257 | LOAD(scene, "iblFactor", m_UIState.IBLFactor); 258 | LOAD(scene, "emmisiveFactor", m_UIState.EmissiveFactor); 259 | LOAD(scene, "skyDomeType", m_UIState.SelectedSkydomeTypeIndex); 260 | 261 | // Add a default light in case there are none 262 | if (m_pGltfLoader->m_lights.size() == 0) 263 | { 264 | tfNode n; 265 | n.m_tranform.LookAt(PolarToVector(AMD_PI_OVER_2, 0.58f) * 3.5f, math::Vector4(0, 0, 0, 0)); 266 | 267 | tfLight l; 268 | l.m_type = tfLight::LIGHT_SPOTLIGHT; 269 | l.m_intensity = scene.value("intensity", 1.0f); 270 | l.m_color = math::Vector4(1.0f, 1.0f, 1.0f, 0.0f); 271 | l.m_range = 15; 272 | l.m_outerConeAngle = AMD_PI_OVER_4; 273 | l.m_innerConeAngle = AMD_PI_OVER_4 * 0.9f; 274 | l.m_shadowResolution = 1024; 275 | 276 | m_pGltfLoader->AddLight(n, l); 277 | } 278 | 279 | // Allocate shadow information (if any) 280 | m_pRenderer->AllocateShadowMaps(m_pGltfLoader); 281 | 282 | // set default camera 283 | json camera = scene["camera"]; 284 | m_activeCamera = scene.value("activeCamera", m_activeCamera); 285 | math::Vector4 from = GetVector(GetElementJsonArray(camera, "defaultFrom", { 0.0, 0.0, 10.0 })); 286 | math::Vector4 to = GetVector(GetElementJsonArray(camera, "defaultTo", { 0.0, 0.0, 0.0 })); 287 | m_camera.LookAt(from, to); 288 | 289 | // set benchmarking state if enabled 290 | if (m_bIsBenchmarking) 291 | { 292 | std::string deviceName; 293 | std::string driverVersion; 294 | m_device.GetDeviceInfo(&deviceName, &driverVersion); 295 | BenchmarkConfig(scene["BenchmarkSettings"], m_activeCamera, m_pGltfLoader, deviceName, driverVersion); 296 | } 297 | 298 | // indicate the mainloop we started loading a GLTF and it needs to load the rest (textures and geometry) 299 | m_loadingScene = true; 300 | } 301 | } 302 | 303 | 304 | //-------------------------------------------------------------------------------------- 305 | // 306 | // OnUpdate 307 | // 308 | //-------------------------------------------------------------------------------------- 309 | void GLTFSample::OnUpdate() 310 | { 311 | ImGuiIO& io = ImGui::GetIO(); 312 | 313 | //If the mouse was not used by the GUI then it's for the camera 314 | // 315 | if (io.WantCaptureMouse) 316 | { 317 | io.MouseDelta.x = 0; 318 | io.MouseDelta.y = 0; 319 | io.MouseWheel = 0; 320 | } 321 | 322 | // Update Camera 323 | UpdateCamera(m_camera, io); 324 | if (m_UIState.bUseTAA) 325 | { 326 | static uint32_t Seed; 327 | m_camera.SetProjectionJitter(m_Width, m_Height, Seed); 328 | } 329 | else 330 | m_camera.SetProjectionJitter(0.f, 0.f); 331 | 332 | // Keyboard & Mouse 333 | HandleInput(io); 334 | 335 | // Animation Update 336 | if (m_bPlay) 337 | m_time += (float)m_deltaTime / 1000.0f; // animation time in seconds 338 | 339 | if (m_pGltfLoader) 340 | { 341 | m_pGltfLoader->SetAnimationTime(0, m_time); 342 | m_pGltfLoader->TransformScene(0, math::Matrix4::identity()); 343 | } 344 | } 345 | 346 | void GLTFSample::HandleInput(const ImGuiIO& io) 347 | { 348 | auto fnIsKeyTriggered = [&io](char key) { return io.KeysDown[key] && io.KeysDownDuration[key] == 0.0f; }; 349 | 350 | // Handle Keyboard/Mouse input here 351 | 352 | /* MAGNIFIER CONTROLS */ 353 | if (fnIsKeyTriggered('L')) m_UIState.ToggleMagnifierLock(); 354 | if (fnIsKeyTriggered('M') || io.MouseClicked[2]) // middle mouse / M key toggles magnifier 355 | { 356 | m_UIState.bUseMagnifier ^= 1; 357 | // We need to update IMGUI's renderpass to draw to magnfier's renderpass when in hdr 358 | // Hence, flush GPU and update it through OnUpdateDisplay 359 | // Which needs to do the same thing when display mode is changed. 360 | m_device.GPUFlush(); 361 | OnUpdateDisplay(); 362 | } 363 | 364 | if (io.MouseClicked[1] && m_UIState.bUseMagnifier) // right mouse click 365 | m_UIState.ToggleMagnifierLock(); 366 | } 367 | 368 | void GLTFSample::UpdateCamera(Camera& cam, const ImGuiIO& io) 369 | { 370 | float yaw = cam.GetYaw(); 371 | float pitch = cam.GetPitch(); 372 | float distance = cam.GetDistance(); 373 | 374 | cam.UpdatePreviousMatrices(); // set previous view matrix 375 | 376 | // Sets Camera based on UI selection (WASD, Orbit or any of the GLTF cameras) 377 | if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) 378 | { 379 | yaw -= io.MouseDelta.x / 100.f; 380 | pitch += io.MouseDelta.y / 100.f; 381 | } 382 | 383 | // Choose camera movement depending on setting 384 | if (m_activeCamera == 0) 385 | { 386 | // If nothing has changed, don't calculate an update (we are getting micro changes in view causing bugs) 387 | if (!io.MouseWheel && (!io.MouseDown[0] || (!io.MouseDelta.x && !io.MouseDelta.y))) 388 | return; 389 | 390 | // Orbiting 391 | distance -= (float)io.MouseWheel / 3.0f; 392 | distance = std::max(distance, 0.1f); 393 | 394 | bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); 395 | 396 | cam.UpdateCameraPolar(yaw, pitch, 397 | panning ? -io.MouseDelta.x / 100.0f : 0.0f, 398 | panning ? io.MouseDelta.y / 100.0f : 0.0f, 399 | distance); 400 | } 401 | else if (m_activeCamera == 1) 402 | { 403 | // WASD 404 | cam.UpdateCameraWASD(yaw, pitch, io.KeysDown, io.DeltaTime); 405 | } 406 | else if (m_activeCamera > 1) 407 | { 408 | // Use a camera from the GLTF 409 | m_pGltfLoader->GetCamera(m_activeCamera - 2, &cam); 410 | } 411 | } 412 | 413 | //-------------------------------------------------------------------------------------- 414 | // 415 | // OnRender, updates the state from the UI, animates, transforms and renders the scene 416 | // 417 | //-------------------------------------------------------------------------------------- 418 | void GLTFSample::OnRender() 419 | { 420 | // Do any start of frame necessities 421 | BeginFrame(); 422 | 423 | ImGUI_UpdateIO(); 424 | ImGui::NewFrame(); 425 | 426 | if (m_loadingScene) 427 | { 428 | // the scene loads in chuncks, that way we can show a progress bar 429 | static int loadingStage = 0; 430 | loadingStage = m_pRenderer->LoadScene(m_pGltfLoader, loadingStage); 431 | if (loadingStage == 0) 432 | { 433 | m_time = 0; 434 | m_loadingScene = false; 435 | } 436 | } 437 | else if (m_pGltfLoader && m_bIsBenchmarking) 438 | { 439 | // Benchmarking takes control of the time, and exits the app when the animation is done 440 | std::vector timeStamps = m_pRenderer->GetTimingValues(); 441 | std::string Filename; 442 | m_time = BenchmarkLoop(timeStamps, &m_camera, Filename); 443 | } 444 | else 445 | { 446 | BuildUI(); // UI logic. Note that the rendering of the UI happens later. 447 | OnUpdate(); // Update camera, handle keyboard/mouse input 448 | } 449 | 450 | // Do Render frame using AFR 451 | m_pRenderer->OnRender(&m_UIState, m_camera, &m_swapChain); 452 | 453 | // Framework will handle Present and some other end of frame logic 454 | EndFrame(); 455 | } 456 | 457 | 458 | //-------------------------------------------------------------------------------------- 459 | // 460 | // WinMain 461 | // 462 | //-------------------------------------------------------------------------------------- 463 | int WINAPI WinMain(HINSTANCE hInstance, 464 | HINSTANCE hPrevInstance, 465 | LPSTR lpCmdLine, 466 | int nCmdShow) 467 | { 468 | LPCSTR Name = "SampleVK v1.4.1"; 469 | 470 | // create new Vulkan sample 471 | return RunFramework(hInstance, lpCmdLine, nCmdShow, new GLTFSample(Name)); 472 | } 473 | -------------------------------------------------------------------------------- /src/VK/GLTFSample.h: -------------------------------------------------------------------------------- 1 | // AMD SampleVK sample code 2 | // 3 | // Copyright(c) 2020 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 | 52 | GLTFCommon *m_pGltfLoader = NULL; 53 | bool m_loadingScene = false; 54 | 55 | Renderer* m_pRenderer = NULL; 56 | UIState m_UIState; 57 | float m_fontSize; 58 | Camera m_camera; 59 | 60 | float m_time; // Time accumulator in seconds, used for animation. 61 | 62 | // json config file 63 | json m_jsonConfigFile; 64 | std::vector m_sceneNames; 65 | int m_activeScene; 66 | int m_activeCamera; 67 | 68 | bool m_bPlay; 69 | }; 70 | -------------------------------------------------------------------------------- /src/VK/Renderer.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleVK sample code 2 | // 3 | // Copyright(c) 2020 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 | //-------------------------------------------------------------------------------------- 24 | // 25 | // OnCreate 26 | // 27 | //-------------------------------------------------------------------------------------- 28 | void Renderer::OnCreate(Device *pDevice, SwapChain *pSwapChain, float FontSize) 29 | { 30 | m_pDevice = pDevice; 31 | 32 | // Initialize helpers 33 | 34 | // Create all the heaps for the resources views 35 | const uint32_t cbvDescriptorCount = 2000; 36 | const uint32_t srvDescriptorCount = 8000; 37 | const uint32_t uavDescriptorCount = 10; 38 | const uint32_t samplerDescriptorCount = 20; 39 | m_ResourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, samplerDescriptorCount); 40 | 41 | // Create a commandlist ring for the Direct queue 42 | uint32_t commandListsPerBackBuffer = 8; 43 | m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer); 44 | 45 | // Create a 'dynamic' constant buffer 46 | const uint32_t constantBuffersMemSize = 200 * 1024 * 1024; 47 | m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, "Uniforms"); 48 | 49 | // Create a 'static' pool for vertices and indices 50 | const uint32_t staticGeometryMemSize = (1 * 128) * 1024 * 1024; 51 | m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, true, "StaticGeom"); 52 | 53 | // Create a 'static' pool for vertices and indices in system memory 54 | const uint32_t systemGeometryMemSize = 32 * 1024; 55 | m_SysMemBufferPool.OnCreate(pDevice, systemGeometryMemSize, false, "PostProcGeom"); 56 | 57 | // initialize the GPU time stamps module 58 | m_GPUTimer.OnCreate(pDevice, backBufferCount); 59 | 60 | // Quick helper to upload resources, it has it's own commandList and uses suballocation. 61 | const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024; 62 | m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results) 63 | 64 | // Create GBuffer and render passes 65 | // 66 | { 67 | m_GBuffer.OnCreate( 68 | pDevice, 69 | &m_ResourceViewHeaps, 70 | { 71 | { GBUFFER_DEPTH, VK_FORMAT_D32_SFLOAT}, 72 | { GBUFFER_FORWARD, VK_FORMAT_R16G16B16A16_SFLOAT}, 73 | { GBUFFER_MOTION_VECTORS, VK_FORMAT_R16G16_SFLOAT}, 74 | }, 75 | 1 76 | ); 77 | 78 | GBufferFlags fullGBuffer = GBUFFER_DEPTH | GBUFFER_FORWARD | GBUFFER_MOTION_VECTORS; 79 | bool bClear = true; 80 | m_RenderPassFullGBufferWithClear.OnCreate(&m_GBuffer, fullGBuffer, bClear,"m_RenderPassFullGBufferWithClear"); 81 | m_RenderPassFullGBuffer.OnCreate(&m_GBuffer, fullGBuffer, !bClear, "m_RenderPassFullGBuffer"); 82 | m_RenderPassJustDepthAndHdr.OnCreate(&m_GBuffer, GBUFFER_DEPTH | GBUFFER_FORWARD, !bClear, "m_RenderPassJustDepthAndHdr"); 83 | } 84 | 85 | // Create render pass shadow, will clear contents 86 | { 87 | VkAttachmentDescription depthAttachments; 88 | AttachClearBeforeUse(VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &depthAttachments); 89 | m_Render_pass_shadow = CreateRenderPassOptimal(m_pDevice->GetDevice(), 0, NULL, &depthAttachments); 90 | } 91 | 92 | m_SkyDome.OnCreate(pDevice, m_RenderPassJustDepthAndHdr.GetRenderPass(), &m_UploadHeap, VK_FORMAT_R16G16B16A16_SFLOAT, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, "..\\media\\cauldron-media\\envmaps\\papermill\\diffuse.dds", "..\\media\\cauldron-media\\envmaps\\papermill\\specular.dds", VK_SAMPLE_COUNT_1_BIT); 93 | m_SkyDomeProc.OnCreate(pDevice, m_RenderPassJustDepthAndHdr.GetRenderPass(), &m_UploadHeap, VK_FORMAT_R16G16B16A16_SFLOAT, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_SAMPLE_COUNT_1_BIT); 94 | m_Wireframe.OnCreate(pDevice, m_RenderPassJustDepthAndHdr.GetRenderPass(), &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_SAMPLE_COUNT_1_BIT); 95 | m_WireframeBox.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool); 96 | m_DownSample.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); 97 | m_Bloom.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); 98 | m_TAA.OnCreate(pDevice, &m_ResourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); 99 | m_MagnifierPS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); 100 | 101 | // Create tonemapping pass 102 | m_ToneMappingCS.OnCreate(pDevice, &m_ResourceViewHeaps, &m_ConstantBufferRing); 103 | m_ToneMappingPS.OnCreate(m_pDevice, pSwapChain->GetRenderPass(), &m_ResourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); 104 | m_ColorConversionPS.OnCreate(pDevice, pSwapChain->GetRenderPass(), &m_ResourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); 105 | 106 | // Initialize UI rendering resources 107 | m_ImGUI.OnCreate(m_pDevice, pSwapChain->GetRenderPass(), &m_UploadHeap, &m_ConstantBufferRing, FontSize); 108 | 109 | // Make sure upload heap has finished uploading before continuing 110 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 111 | m_UploadHeap.FlushAndFinish(); 112 | } 113 | 114 | //-------------------------------------------------------------------------------------- 115 | // 116 | // OnDestroy 117 | // 118 | //-------------------------------------------------------------------------------------- 119 | void Renderer::OnDestroy() 120 | { 121 | m_AsyncPool.Flush(); 122 | 123 | m_ImGUI.OnDestroy(); 124 | m_ColorConversionPS.OnDestroy(); 125 | m_ToneMappingPS.OnDestroy(); 126 | m_ToneMappingCS.OnDestroy(); 127 | m_TAA.OnDestroy(); 128 | m_Bloom.OnDestroy(); 129 | m_DownSample.OnDestroy(); 130 | m_MagnifierPS.OnDestroy(); 131 | m_WireframeBox.OnDestroy(); 132 | m_Wireframe.OnDestroy(); 133 | m_SkyDomeProc.OnDestroy(); 134 | m_SkyDome.OnDestroy(); 135 | 136 | m_RenderPassFullGBufferWithClear.OnDestroy(); 137 | m_RenderPassJustDepthAndHdr.OnDestroy(); 138 | m_RenderPassFullGBuffer.OnDestroy(); 139 | m_GBuffer.OnDestroy(); 140 | 141 | vkDestroyRenderPass(m_pDevice->GetDevice(), m_Render_pass_shadow, nullptr); 142 | 143 | m_UploadHeap.OnDestroy(); 144 | m_GPUTimer.OnDestroy(); 145 | m_VidMemBufferPool.OnDestroy(); 146 | m_SysMemBufferPool.OnDestroy(); 147 | m_ConstantBufferRing.OnDestroy(); 148 | m_ResourceViewHeaps.OnDestroy(); 149 | m_CommandListRing.OnDestroy(); 150 | } 151 | 152 | //-------------------------------------------------------------------------------------- 153 | // 154 | // OnCreateWindowSizeDependentResources 155 | // 156 | //-------------------------------------------------------------------------------------- 157 | void Renderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height) 158 | { 159 | m_Width = Width; 160 | m_Height = Height; 161 | 162 | // Set the viewport 163 | // 164 | m_Viewport.x = 0; 165 | m_Viewport.y = (float)Height; 166 | m_Viewport.width = (float)Width; 167 | m_Viewport.height = -(float)(Height); 168 | m_Viewport.minDepth = (float)0.0f; 169 | m_Viewport.maxDepth = (float)1.0f; 170 | 171 | // Create scissor rectangle 172 | // 173 | m_RectScissor.extent.width = Width; 174 | m_RectScissor.extent.height = Height; 175 | m_RectScissor.offset.x = 0; 176 | m_RectScissor.offset.y = 0; 177 | 178 | // Create GBuffer 179 | // 180 | m_GBuffer.OnCreateWindowSizeDependentResources(pSwapChain, Width, Height); 181 | 182 | // Create frame buffers for the GBuffer render passes 183 | // 184 | m_RenderPassFullGBufferWithClear.OnCreateWindowSizeDependentResources(Width, Height); 185 | m_RenderPassJustDepthAndHdr.OnCreateWindowSizeDependentResources(Width, Height); 186 | m_RenderPassFullGBuffer.OnCreateWindowSizeDependentResources(Width, Height); 187 | 188 | // Update PostProcessing passes 189 | // 190 | m_DownSample.OnCreateWindowSizeDependentResources(Width, Height, &m_GBuffer.m_HDR, 6); //downsample the HDR texture 6 times 191 | m_Bloom.OnCreateWindowSizeDependentResources(Width / 2, Height / 2, m_DownSample.GetTexture(), 6, &m_GBuffer.m_HDR); 192 | m_TAA.OnCreateWindowSizeDependentResources(Width, Height, &m_GBuffer); 193 | m_MagnifierPS.OnCreateWindowSizeDependentResources(&m_GBuffer.m_HDR); 194 | m_bMagResourceReInit = true; 195 | } 196 | 197 | //-------------------------------------------------------------------------------------- 198 | // 199 | // OnDestroyWindowSizeDependentResources 200 | // 201 | //-------------------------------------------------------------------------------------- 202 | void Renderer::OnDestroyWindowSizeDependentResources() 203 | { 204 | m_Bloom.OnDestroyWindowSizeDependentResources(); 205 | m_DownSample.OnDestroyWindowSizeDependentResources(); 206 | m_TAA.OnDestroyWindowSizeDependentResources(); 207 | m_MagnifierPS.OnDestroyWindowSizeDependentResources(); 208 | 209 | m_RenderPassFullGBufferWithClear.OnDestroyWindowSizeDependentResources(); 210 | m_RenderPassJustDepthAndHdr.OnDestroyWindowSizeDependentResources(); 211 | m_RenderPassFullGBuffer.OnDestroyWindowSizeDependentResources(); 212 | m_GBuffer.OnDestroyWindowSizeDependentResources(); 213 | } 214 | 215 | void Renderer::OnUpdateDisplayDependentResources(SwapChain *pSwapChain, bool bUseMagnifier) 216 | { 217 | // Update the pipelines if the swapchain render pass has changed (for example when the format of the swapchain changes) 218 | // 219 | m_ColorConversionPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode()); 220 | m_ToneMappingPS.UpdatePipelines(pSwapChain->GetRenderPass()); 221 | 222 | m_ImGUI.UpdatePipeline((pSwapChain->GetDisplayMode() == DISPLAYMODE_SDR) ? pSwapChain->GetRenderPass() : bUseMagnifier ? m_MagnifierPS.GetPassRenderPass() : m_RenderPassJustDepthAndHdr.GetRenderPass()); 223 | } 224 | 225 | //-------------------------------------------------------------------------------------- 226 | // 227 | // OnUpdateLocalDimmingChangedResources 228 | // 229 | //-------------------------------------------------------------------------------------- 230 | void Renderer::OnUpdateLocalDimmingChangedResources(SwapChain *pSwapChain) 231 | { 232 | m_ColorConversionPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode()); 233 | } 234 | 235 | //-------------------------------------------------------------------------------------- 236 | // 237 | // LoadScene 238 | // 239 | //-------------------------------------------------------------------------------------- 240 | int Renderer::LoadScene(GLTFCommon *pGLTFCommon, int Stage) 241 | { 242 | // show loading progress 243 | // 244 | ImGui::OpenPopup("Loading"); 245 | if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize)) 246 | { 247 | float progress = (float)Stage / 12.0f; 248 | ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL); 249 | ImGui::EndPopup(); 250 | } 251 | 252 | // use multi threading 253 | AsyncPool *pAsyncPool = &m_AsyncPool; 254 | 255 | // Loading stages 256 | // 257 | if (Stage == 0) 258 | { 259 | } 260 | else if (Stage == 5) 261 | { 262 | Profile p("m_pGltfLoader->Load"); 263 | 264 | m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers(); 265 | m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing); 266 | } 267 | else if (Stage == 6) 268 | { 269 | Profile p("LoadTextures"); 270 | 271 | // here we are loading onto the GPU all the textures and the inverse matrices 272 | // this data will be used to create the PBR and Depth passes 273 | m_pGLTFTexturesAndBuffers->LoadTextures(pAsyncPool); 274 | } 275 | else if (Stage == 7) 276 | { 277 | Profile p("m_GLTFDepth->OnCreate"); 278 | 279 | //create the glTF's textures, VBs, IBs, shaders and descriptors for this particular pass 280 | m_GLTFDepth = new GltfDepthPass(); 281 | m_GLTFDepth->OnCreate( 282 | m_pDevice, 283 | m_Render_pass_shadow, 284 | &m_UploadHeap, 285 | &m_ResourceViewHeaps, 286 | &m_ConstantBufferRing, 287 | &m_VidMemBufferPool, 288 | m_pGLTFTexturesAndBuffers, 289 | pAsyncPool 290 | ); 291 | 292 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 293 | m_UploadHeap.FlushAndFinish(); 294 | } 295 | else if (Stage == 8) 296 | { 297 | Profile p("m_GLTFPBR->OnCreate"); 298 | 299 | // same thing as above but for the PBR pass 300 | m_GLTFPBR = new GltfPbrPass(); 301 | m_GLTFPBR->OnCreate( 302 | m_pDevice, 303 | &m_UploadHeap, 304 | &m_ResourceViewHeaps, 305 | &m_ConstantBufferRing, 306 | &m_VidMemBufferPool, 307 | m_pGLTFTexturesAndBuffers, 308 | &m_SkyDome, 309 | false, // use SSAO mask 310 | m_ShadowSRVPool, 311 | &m_RenderPassFullGBufferWithClear, 312 | pAsyncPool 313 | ); 314 | 315 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 316 | m_UploadHeap.FlushAndFinish(); 317 | } 318 | else if (Stage == 9) 319 | { 320 | Profile p("m_GLTFBBox->OnCreate"); 321 | 322 | // just a bounding box pass that will draw boundingboxes instead of the geometry itself 323 | m_GLTFBBox = new GltfBBoxPass(); 324 | m_GLTFBBox->OnCreate( 325 | m_pDevice, 326 | m_RenderPassJustDepthAndHdr.GetRenderPass(), 327 | &m_ResourceViewHeaps, 328 | &m_ConstantBufferRing, 329 | &m_VidMemBufferPool, 330 | m_pGLTFTexturesAndBuffers, 331 | &m_Wireframe 332 | ); 333 | 334 | // we are borrowing the upload heap command list for uploading to the GPU the IBs and VBs 335 | m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); 336 | 337 | } 338 | else if (Stage == 10) 339 | { 340 | Profile p("Flush"); 341 | 342 | m_UploadHeap.FlushAndFinish(); 343 | 344 | //once everything is uploaded we dont need the upload heaps anymore 345 | m_VidMemBufferPool.FreeUploadHeap(); 346 | 347 | // tell caller that we are done loading the map 348 | return 0; 349 | } 350 | 351 | Stage++; 352 | return Stage; 353 | } 354 | 355 | //-------------------------------------------------------------------------------------- 356 | // 357 | // UnloadScene 358 | // 359 | //-------------------------------------------------------------------------------------- 360 | void Renderer::UnloadScene() 361 | { 362 | // wait for all the async loading operations to finish 363 | m_AsyncPool.Flush(); 364 | 365 | m_pDevice->GPUFlush(); 366 | 367 | if (m_GLTFPBR) 368 | { 369 | m_GLTFPBR->OnDestroy(); 370 | delete m_GLTFPBR; 371 | m_GLTFPBR = NULL; 372 | } 373 | 374 | if (m_GLTFDepth) 375 | { 376 | m_GLTFDepth->OnDestroy(); 377 | delete m_GLTFDepth; 378 | m_GLTFDepth = NULL; 379 | } 380 | 381 | if (m_GLTFBBox) 382 | { 383 | m_GLTFBBox->OnDestroy(); 384 | delete m_GLTFBBox; 385 | m_GLTFBBox = NULL; 386 | } 387 | 388 | if (m_pGLTFTexturesAndBuffers) 389 | { 390 | m_pGLTFTexturesAndBuffers->OnDestroy(); 391 | delete m_pGLTFTexturesAndBuffers; 392 | m_pGLTFTexturesAndBuffers = NULL; 393 | } 394 | 395 | assert(m_shadowMapPool.size() == m_ShadowSRVPool.size()); 396 | while (!m_shadowMapPool.empty()) 397 | { 398 | m_shadowMapPool.back().ShadowMap.OnDestroy(); 399 | vkDestroyFramebuffer(m_pDevice->GetDevice(), m_shadowMapPool.back().ShadowFrameBuffer, nullptr); 400 | vkDestroyImageView(m_pDevice->GetDevice(), m_ShadowSRVPool.back(), nullptr); 401 | vkDestroyImageView(m_pDevice->GetDevice(), m_shadowMapPool.back().ShadowDSV, nullptr); 402 | m_ShadowSRVPool.pop_back(); 403 | m_shadowMapPool.pop_back(); 404 | } 405 | } 406 | 407 | void Renderer::AllocateShadowMaps(GLTFCommon* pGLTFCommon) 408 | { 409 | // Go through the lights and allocate shadow information 410 | uint32_t NumShadows = 0; 411 | for (int i = 0; i < pGLTFCommon->m_lightInstances.size(); ++i) 412 | { 413 | const tfLight& lightData = pGLTFCommon->m_lights[pGLTFCommon->m_lightInstances[i].m_lightId]; 414 | if (lightData.m_shadowResolution) 415 | { 416 | SceneShadowInfo ShadowInfo; 417 | ShadowInfo.ShadowResolution = lightData.m_shadowResolution; 418 | ShadowInfo.ShadowIndex = NumShadows++; 419 | ShadowInfo.LightIndex = i; 420 | m_shadowMapPool.push_back(ShadowInfo); 421 | } 422 | } 423 | 424 | if (NumShadows > MaxShadowInstances) 425 | { 426 | Trace("Number of shadows has exceeded maximum supported. Please grow value in gltfCommon.h/perFrameStruct.h"); 427 | throw; 428 | } 429 | 430 | // If we had shadow information, allocate all required maps and bindings 431 | if (!m_shadowMapPool.empty()) 432 | { 433 | std::vector::iterator CurrentShadow = m_shadowMapPool.begin(); 434 | for (uint32_t i = 0; CurrentShadow < m_shadowMapPool.end(); ++i, ++CurrentShadow) 435 | { 436 | CurrentShadow->ShadowMap.InitDepthStencil(m_pDevice, CurrentShadow->ShadowResolution, CurrentShadow->ShadowResolution, VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, "ShadowMap"); 437 | CurrentShadow->ShadowMap.CreateDSV(&CurrentShadow->ShadowDSV); 438 | 439 | // Create render pass shadow, will clear contents 440 | { 441 | VkAttachmentDescription depthAttachments; 442 | AttachClearBeforeUse(VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &depthAttachments); 443 | 444 | // Create frame buffer 445 | VkImageView attachmentViews[1] = { CurrentShadow->ShadowDSV }; 446 | VkFramebufferCreateInfo fb_info = {}; 447 | fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; 448 | fb_info.pNext = NULL; 449 | fb_info.renderPass = m_Render_pass_shadow; 450 | fb_info.attachmentCount = 1; 451 | fb_info.pAttachments = attachmentViews; 452 | fb_info.width = CurrentShadow->ShadowResolution; 453 | fb_info.height = CurrentShadow->ShadowResolution; 454 | fb_info.layers = 1; 455 | VkResult res = vkCreateFramebuffer(m_pDevice->GetDevice(), &fb_info, NULL, &CurrentShadow->ShadowFrameBuffer); 456 | assert(res == VK_SUCCESS); 457 | } 458 | 459 | VkImageView ShadowSRV; 460 | CurrentShadow->ShadowMap.CreateSRV(&ShadowSRV); 461 | m_ShadowSRVPool.push_back(ShadowSRV); 462 | } 463 | } 464 | } 465 | 466 | //-------------------------------------------------------------------------------------- 467 | // 468 | // OnRender 469 | // 470 | //-------------------------------------------------------------------------------------- 471 | void Renderer::OnRender(const UIState* pState, const Camera& Cam, SwapChain* pSwapChain) 472 | { 473 | // Let our resource managers do some house keeping 474 | m_ConstantBufferRing.OnBeginFrame(); 475 | 476 | // command buffer calls 477 | VkCommandBuffer cmdBuf1 = m_CommandListRing.GetNewCommandList(); 478 | 479 | { 480 | VkCommandBufferBeginInfo cmd_buf_info; 481 | cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 482 | cmd_buf_info.pNext = NULL; 483 | cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; 484 | cmd_buf_info.pInheritanceInfo = NULL; 485 | VkResult res = vkBeginCommandBuffer(cmdBuf1, &cmd_buf_info); 486 | assert(res == VK_SUCCESS); 487 | } 488 | 489 | m_GPUTimer.OnBeginFrame(cmdBuf1, &m_TimeStamps); 490 | 491 | // Sets the perFrame data 492 | per_frame *pPerFrame = NULL; 493 | if (m_pGLTFTexturesAndBuffers) 494 | { 495 | // fill as much as possible using the GLTF (camera, lights, ...) 496 | pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(Cam); 497 | 498 | // Set some lighting factors 499 | pPerFrame->iblFactor = pState->IBLFactor; 500 | pPerFrame->emmisiveFactor = pState->EmissiveFactor; 501 | pPerFrame->invScreenResolution[0] = 1.0f / ((float)m_Width); 502 | pPerFrame->invScreenResolution[1] = 1.0f / ((float)m_Height); 503 | 504 | pPerFrame->wireframeOptions.setX(pState->WireframeColor[0]); 505 | pPerFrame->wireframeOptions.setY(pState->WireframeColor[1]); 506 | pPerFrame->wireframeOptions.setZ(pState->WireframeColor[2]); 507 | pPerFrame->wireframeOptions.setW(pState->WireframeMode == UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR ? 1.0f : 0.0f); 508 | pPerFrame->lodBias = 0.0f; 509 | m_pGLTFTexturesAndBuffers->SetPerFrameConstants(); 510 | m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons(); 511 | } 512 | 513 | // Render all shadow maps 514 | if (m_GLTFDepth && pPerFrame != NULL) 515 | { 516 | SetPerfMarkerBegin(cmdBuf1, "ShadowPass"); 517 | 518 | VkClearValue depth_clear_values[1]; 519 | depth_clear_values[0].depthStencil.depth = 1.0f; 520 | depth_clear_values[0].depthStencil.stencil = 0; 521 | 522 | VkRenderPassBeginInfo rp_begin; 523 | rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 524 | rp_begin.pNext = NULL; 525 | rp_begin.renderPass = m_Render_pass_shadow; 526 | rp_begin.renderArea.offset.x = 0; 527 | rp_begin.renderArea.offset.y = 0; 528 | rp_begin.clearValueCount = 1; 529 | rp_begin.pClearValues = depth_clear_values; 530 | 531 | std::vector::iterator ShadowMap = m_shadowMapPool.begin(); 532 | while (ShadowMap < m_shadowMapPool.end()) 533 | { 534 | // Clear shadow map 535 | rp_begin.framebuffer = ShadowMap->ShadowFrameBuffer; 536 | rp_begin.renderArea.extent.width = ShadowMap->ShadowResolution; 537 | rp_begin.renderArea.extent.height = ShadowMap->ShadowResolution; 538 | vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); 539 | 540 | // Render to shadow map 541 | SetViewportAndScissor(cmdBuf1, 0, 0, ShadowMap->ShadowResolution, ShadowMap->ShadowResolution); 542 | 543 | // Set per frame constant buffer values 544 | GltfDepthPass::per_frame* cbPerFrame = m_GLTFDepth->SetPerFrameConstants(); 545 | cbPerFrame->mViewProj = pPerFrame->lights[ShadowMap->LightIndex].mLightViewProj; 546 | 547 | m_GLTFDepth->Draw(cmdBuf1); 548 | 549 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Shadow Map Render"); 550 | 551 | vkCmdEndRenderPass(cmdBuf1); 552 | ++ShadowMap; 553 | } 554 | 555 | SetPerfMarkerEnd(cmdBuf1); 556 | } 557 | 558 | // Render Scene to the GBuffer ------------------------------------------------ 559 | SetPerfMarkerBegin(cmdBuf1, "Color pass"); 560 | 561 | VkRect2D renderArea = { 0, 0, m_Width, m_Height }; 562 | 563 | if (pPerFrame != NULL && m_GLTFPBR) 564 | { 565 | const bool bWireframe = pState->WireframeMode != UIState::WireframeMode::WIREFRAME_MODE_OFF; 566 | 567 | std::vector opaque, transparent; 568 | m_GLTFPBR->BuildBatchLists(&opaque, &transparent, bWireframe); 569 | 570 | // Render opaque 571 | { 572 | m_RenderPassFullGBufferWithClear.BeginPass(cmdBuf1, renderArea); 573 | 574 | m_GLTFPBR->DrawBatchList(cmdBuf1, &opaque, bWireframe); 575 | m_GPUTimer.GetTimeStamp(cmdBuf1, "PBR Opaque"); 576 | 577 | m_RenderPassFullGBufferWithClear.EndPass(cmdBuf1); 578 | } 579 | 580 | // Render skydome 581 | { 582 | m_RenderPassJustDepthAndHdr.BeginPass(cmdBuf1, renderArea); 583 | 584 | if (pState->SelectedSkydomeTypeIndex == 1) 585 | { 586 | math::Matrix4 clipToView = math::inverse(pPerFrame->mCameraCurrViewProj); 587 | m_SkyDome.Draw(cmdBuf1, clipToView); 588 | 589 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Skydome cube"); 590 | } 591 | else if (pState->SelectedSkydomeTypeIndex == 0) 592 | { 593 | SkyDomeProc::Constants skyDomeConstants; 594 | skyDomeConstants.invViewProj = math::inverse(pPerFrame->mCameraCurrViewProj); 595 | skyDomeConstants.vSunDirection = math::Vector4(1.0f, 0.05f, 0.0f, 0.0f); 596 | skyDomeConstants.turbidity = 10.0f; 597 | skyDomeConstants.rayleigh = 2.0f; 598 | skyDomeConstants.mieCoefficient = 0.005f; 599 | skyDomeConstants.mieDirectionalG = 0.8f; 600 | skyDomeConstants.luminance = 1.0f; 601 | m_SkyDomeProc.Draw(cmdBuf1, skyDomeConstants); 602 | 603 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Skydome Proc"); 604 | } 605 | 606 | m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1); 607 | } 608 | 609 | // draw transparent geometry 610 | { 611 | m_RenderPassFullGBuffer.BeginPass(cmdBuf1, renderArea); 612 | 613 | std::sort(transparent.begin(), transparent.end()); 614 | m_GLTFPBR->DrawBatchList(cmdBuf1, &transparent, bWireframe); 615 | m_GPUTimer.GetTimeStamp(cmdBuf1, "PBR Transparent"); 616 | 617 | m_RenderPassFullGBuffer.EndPass(cmdBuf1); 618 | } 619 | 620 | // draw object's bounding boxes 621 | { 622 | m_RenderPassJustDepthAndHdr.BeginPass(cmdBuf1, renderArea); 623 | 624 | if (m_GLTFBBox) 625 | { 626 | if (pState->bDrawBoundingBoxes) 627 | { 628 | m_GLTFBBox->Draw(cmdBuf1, pPerFrame->mCameraCurrViewProj); 629 | 630 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Bounding Box"); 631 | } 632 | } 633 | 634 | // draw light's frustums 635 | if (pState->bDrawLightFrustum && pPerFrame != NULL) 636 | { 637 | SetPerfMarkerBegin(cmdBuf1, "light frustums"); 638 | 639 | math::Vector4 vCenter = math::Vector4(0.0f, 0.0f, 0.5f, 0.0f); 640 | math::Vector4 vRadius = math::Vector4(1.0f, 1.0f, 0.5f, 0.0f); 641 | math::Vector4 vColor = math::Vector4(1.0f, 1.0f, 1.0f, 1.0f); 642 | for (uint32_t i = 0; i < pPerFrame->lightCount; i++) 643 | { 644 | math::Matrix4 spotlightMatrix = math::inverse(pPerFrame->lights[i].mLightViewProj); 645 | math::Matrix4 worldMatrix = pPerFrame->mCameraCurrViewProj * spotlightMatrix; 646 | m_WireframeBox.Draw(cmdBuf1, &m_Wireframe, worldMatrix, vCenter, vRadius, vColor); 647 | } 648 | 649 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Light's frustum"); 650 | 651 | SetPerfMarkerEnd(cmdBuf1); 652 | } 653 | 654 | m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1); 655 | } 656 | } 657 | else 658 | { 659 | m_RenderPassFullGBufferWithClear.BeginPass(cmdBuf1, renderArea); 660 | m_RenderPassFullGBufferWithClear.EndPass(cmdBuf1); 661 | m_RenderPassJustDepthAndHdr.BeginPass(cmdBuf1, renderArea); 662 | m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1); 663 | } 664 | 665 | VkImageMemoryBarrier barrier[1] = {}; 666 | barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 667 | barrier[0].pNext = NULL; 668 | barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; 669 | barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 670 | barrier[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 671 | barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 672 | barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 673 | barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 674 | barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 675 | barrier[0].subresourceRange.baseMipLevel = 0; 676 | barrier[0].subresourceRange.levelCount = 1; 677 | barrier[0].subresourceRange.baseArrayLayer = 0; 678 | barrier[0].subresourceRange.layerCount = 1; 679 | barrier[0].image = m_GBuffer.m_HDR.Resource(); 680 | vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT | VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 1, barrier); 681 | 682 | SetPerfMarkerEnd(cmdBuf1); 683 | 684 | // Post proc--------------------------------------------------------------------------- 685 | 686 | // Bloom, takes HDR as input and applies bloom to it. 687 | { 688 | SetPerfMarkerBegin(cmdBuf1, "PostProcess"); 689 | 690 | // Downsample pass 691 | m_DownSample.Draw(cmdBuf1); 692 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Downsample"); 693 | 694 | // Bloom pass (needs the downsampled data) 695 | m_Bloom.Draw(cmdBuf1); 696 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Bloom"); 697 | 698 | SetPerfMarkerEnd(cmdBuf1); 699 | } 700 | 701 | // Apply TAA & Sharpen to m_HDR 702 | if (pState->bUseTAA) 703 | { 704 | { 705 | VkImageMemoryBarrier barrier = {}; 706 | barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 707 | barrier.pNext = NULL; 708 | barrier.srcAccessMask = 0; 709 | barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 710 | barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 711 | barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 712 | barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 713 | barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 714 | barrier.subresourceRange.baseMipLevel = 0; 715 | barrier.subresourceRange.levelCount = 1; 716 | barrier.subresourceRange.baseArrayLayer = 0; 717 | barrier.subresourceRange.layerCount = 1; 718 | 719 | VkImageMemoryBarrier barriers[3]; 720 | barriers[0] = barrier; 721 | barriers[0].srcAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT; 722 | barriers[0].oldLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; 723 | barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT; 724 | barriers[0].image = m_GBuffer.m_DepthBuffer.Resource(); 725 | 726 | barriers[1] = barrier; 727 | barriers[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; 728 | barriers[1].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 729 | barriers[1].image = m_GBuffer.m_MotionVectors.Resource(); 730 | 731 | // no layout transition but we still need to wait 732 | barriers[2] = barrier; 733 | barriers[2].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 734 | barriers[2].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 735 | barriers[2].image = m_GBuffer.m_HDR.Resource(); 736 | 737 | vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT | VK_PIPELINE_STAGE_LATE_FRAGMENT_TESTS_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 3, barriers); 738 | } 739 | 740 | m_TAA.Draw(cmdBuf1); 741 | m_GPUTimer.GetTimeStamp(cmdBuf1, "TAA"); 742 | } 743 | 744 | 745 | // Magnifier Pass: m_HDR as input, pass' own output 746 | if (pState->bUseMagnifier) 747 | { 748 | VkImageMemoryBarrier barrier = {}; 749 | barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 750 | barrier.pNext = NULL; 751 | barrier.srcAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; 752 | barrier.dstAccessMask = VK_ACCESS_INPUT_ATTACHMENT_READ_BIT; 753 | barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 754 | barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 755 | barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 756 | barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 757 | barrier.subresourceRange.baseMipLevel = 0; 758 | barrier.subresourceRange.levelCount = 1; 759 | barrier.subresourceRange.baseArrayLayer = 0; 760 | barrier.subresourceRange.layerCount = 1; 761 | barrier.image = m_MagnifierPS.GetPassOutputResource(); 762 | 763 | if (m_bMagResourceReInit) 764 | { 765 | barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; 766 | vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); 767 | m_bMagResourceReInit = false; 768 | } 769 | else 770 | { 771 | barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 772 | vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); 773 | } 774 | 775 | // Note: assumes the input texture (specified in OnCreateWindowSizeDependentResources()) is in read state 776 | m_MagnifierPS.Draw(cmdBuf1, pState->MagnifierParams); 777 | m_GPUTimer.GetTimeStamp(cmdBuf1, "Magnifier"); 778 | } 779 | 780 | 781 | // Start tracking input/output resources at this point to handle HDR and SDR render paths 782 | VkImage ImgCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputResource() : m_GBuffer.m_HDR.Resource(); 783 | VkImageView SRVCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputSRV() : m_GBuffer.m_HDRSRV; 784 | 785 | // If using FreeSync HDR, we need to do these in order: Tonemapping -> GUI -> Color Conversion 786 | const bool bHDR = pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR; 787 | if (bHDR) 788 | { 789 | // In place Tonemapping ------------------------------------------------------------------------ 790 | { 791 | VkImageMemoryBarrier barrier = {}; 792 | barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 793 | barrier.pNext = NULL; 794 | barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; 795 | barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 796 | barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 797 | barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; 798 | barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 799 | barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 800 | barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 801 | barrier.subresourceRange.baseMipLevel = 0; 802 | barrier.subresourceRange.levelCount = 1; 803 | barrier.subresourceRange.baseArrayLayer = 0; 804 | barrier.subresourceRange.layerCount = 1; 805 | barrier.image = ImgCurrentInput; 806 | vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); 807 | 808 | m_ToneMappingCS.Draw(cmdBuf1, SRVCurrentInput, pState->Exposure, pState->SelectedTonemapperIndex, m_Width, m_Height); 809 | 810 | barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 811 | barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 812 | barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; 813 | barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 814 | barrier.image = ImgCurrentInput; 815 | vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); 816 | 817 | } 818 | 819 | // Render HUD ------------------------------------------------------------------------ 820 | { 821 | 822 | if (pState->bUseMagnifier) 823 | { 824 | m_MagnifierPS.BeginPass(cmdBuf1, renderArea); 825 | } 826 | else 827 | { 828 | m_RenderPassJustDepthAndHdr.BeginPass(cmdBuf1, renderArea); 829 | } 830 | 831 | vkCmdSetScissor(cmdBuf1, 0, 1, &m_RectScissor); 832 | vkCmdSetViewport(cmdBuf1, 0, 1, &m_Viewport); 833 | 834 | m_ImGUI.Draw(cmdBuf1); 835 | 836 | if (pState->bUseMagnifier) 837 | { 838 | m_MagnifierPS.EndPass(cmdBuf1); 839 | } 840 | else 841 | { 842 | m_RenderPassJustDepthAndHdr.EndPass(cmdBuf1); 843 | } 844 | 845 | if (bHDR && !pState->bUseMagnifier) 846 | { 847 | VkImageMemoryBarrier barrier = {}; 848 | barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; 849 | barrier.pNext = NULL; 850 | barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; 851 | barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; 852 | barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; 853 | barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; 854 | barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 855 | barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; 856 | barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; 857 | barrier.subresourceRange.baseMipLevel = 0; 858 | barrier.subresourceRange.levelCount = 1; 859 | barrier.subresourceRange.baseArrayLayer = 0; 860 | barrier.subresourceRange.layerCount = 1; 861 | barrier.image = ImgCurrentInput; 862 | vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); 863 | } 864 | 865 | m_GPUTimer.GetTimeStamp(cmdBuf1, "ImGUI Rendering"); 866 | } 867 | } 868 | 869 | // submit command buffer 870 | { 871 | VkResult res = vkEndCommandBuffer(cmdBuf1); 872 | assert(res == VK_SUCCESS); 873 | 874 | VkSubmitInfo submit_info; 875 | submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 876 | submit_info.pNext = NULL; 877 | submit_info.waitSemaphoreCount = 0; 878 | submit_info.pWaitSemaphores = NULL; 879 | submit_info.pWaitDstStageMask = NULL; 880 | submit_info.commandBufferCount = 1; 881 | submit_info.pCommandBuffers = &cmdBuf1; 882 | submit_info.signalSemaphoreCount = 0; 883 | submit_info.pSignalSemaphores = NULL; 884 | res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE); 885 | assert(res == VK_SUCCESS); 886 | } 887 | 888 | // Wait for swapchain (we are going to render to it) ----------------------------------- 889 | int imageIndex = pSwapChain->WaitForSwapChain(); 890 | 891 | // Keep tracking input/output resource views 892 | ImgCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputResource() : m_GBuffer.m_HDR.Resource(); // these haven't changed, re-assign as sanity check 893 | SRVCurrentInput = pState->bUseMagnifier ? m_MagnifierPS.GetPassOutputSRV() : m_GBuffer.m_HDRSRV; // these haven't changed, re-assign as sanity check 894 | 895 | m_CommandListRing.OnBeginFrame(); 896 | 897 | VkCommandBuffer cmdBuf2 = m_CommandListRing.GetNewCommandList(); 898 | 899 | { 900 | VkCommandBufferBeginInfo cmd_buf_info; 901 | cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; 902 | cmd_buf_info.pNext = NULL; 903 | cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; 904 | cmd_buf_info.pInheritanceInfo = NULL; 905 | VkResult res = vkBeginCommandBuffer(cmdBuf2, &cmd_buf_info); 906 | assert(res == VK_SUCCESS); 907 | } 908 | 909 | SetPerfMarkerBegin(cmdBuf2, "Swapchain RenderPass"); 910 | 911 | // prepare render pass 912 | { 913 | VkRenderPassBeginInfo rp_begin = {}; 914 | rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; 915 | rp_begin.pNext = NULL; 916 | rp_begin.renderPass = pSwapChain->GetRenderPass(); 917 | rp_begin.framebuffer = pSwapChain->GetFramebuffer(imageIndex); 918 | rp_begin.renderArea.offset.x = 0; 919 | rp_begin.renderArea.offset.y = 0; 920 | rp_begin.renderArea.extent.width = m_Width; 921 | rp_begin.renderArea.extent.height = m_Height; 922 | rp_begin.clearValueCount = 0; 923 | rp_begin.pClearValues = NULL; 924 | vkCmdBeginRenderPass(cmdBuf2, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); 925 | } 926 | 927 | vkCmdSetScissor(cmdBuf2, 0, 1, &m_RectScissor); 928 | vkCmdSetViewport(cmdBuf2, 0, 1, &m_Viewport); 929 | 930 | if (bHDR) 931 | { 932 | m_ColorConversionPS.Draw(cmdBuf2, SRVCurrentInput); 933 | m_GPUTimer.GetTimeStamp(cmdBuf2, "Color Conversion"); 934 | } 935 | 936 | // For SDR pipeline, we apply the tonemapping and then draw the GUI and skip the color conversion 937 | else 938 | { 939 | // Tonemapping ------------------------------------------------------------------------ 940 | { 941 | m_ToneMappingPS.Draw(cmdBuf2, SRVCurrentInput, pState->Exposure, pState->SelectedTonemapperIndex); 942 | m_GPUTimer.GetTimeStamp(cmdBuf2, "Tonemapping"); 943 | } 944 | 945 | // Render HUD ------------------------------------------------------------------------- 946 | { 947 | m_ImGUI.Draw(cmdBuf2); 948 | m_GPUTimer.GetTimeStamp(cmdBuf2, "ImGUI Rendering"); 949 | } 950 | } 951 | 952 | SetPerfMarkerEnd(cmdBuf2); 953 | 954 | m_GPUTimer.OnEndFrame(); 955 | 956 | vkCmdEndRenderPass(cmdBuf2); 957 | 958 | // Close & Submit the command list ---------------------------------------------------- 959 | { 960 | VkResult res = vkEndCommandBuffer(cmdBuf2); 961 | assert(res == VK_SUCCESS); 962 | 963 | VkSemaphore ImageAvailableSemaphore; 964 | VkSemaphore RenderFinishedSemaphores; 965 | VkFence CmdBufExecutedFences; 966 | pSwapChain->GetSemaphores(&ImageAvailableSemaphore, &RenderFinishedSemaphores, &CmdBufExecutedFences); 967 | 968 | VkPipelineStageFlags submitWaitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; 969 | VkSubmitInfo submit_info2; 970 | submit_info2.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; 971 | submit_info2.pNext = NULL; 972 | submit_info2.waitSemaphoreCount = 1; 973 | submit_info2.pWaitSemaphores = &ImageAvailableSemaphore; 974 | submit_info2.pWaitDstStageMask = &submitWaitStage; 975 | submit_info2.commandBufferCount = 1; 976 | submit_info2.pCommandBuffers = &cmdBuf2; 977 | submit_info2.signalSemaphoreCount = 1; 978 | submit_info2.pSignalSemaphores = &RenderFinishedSemaphores; 979 | 980 | res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info2, CmdBufExecutedFences); 981 | assert(res == VK_SUCCESS); 982 | } 983 | } 984 | -------------------------------------------------------------------------------- /src/VK/Renderer.h: -------------------------------------------------------------------------------- 1 | // AMD SampleVK sample code 2 | // 3 | // Copyright(c) 2020 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 | 26 | // We are queuing (backBufferCount + 0.5) frames, so we need to triple buffer the resources that get modified each frame 27 | static const int backBufferCount = 3; 28 | 29 | using namespace CAULDRON_VK; 30 | 31 | struct UIState; 32 | 33 | // 34 | // Renderer class is responsible for rendering resources management and recording command buffers. 35 | class Renderer 36 | { 37 | public: 38 | void OnCreate(Device *pDevice, SwapChain *pSwapChain, float FontSize); 39 | void OnDestroy(); 40 | 41 | void OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height); 42 | void OnDestroyWindowSizeDependentResources(); 43 | 44 | void OnUpdateDisplayDependentResources(SwapChain *pSwapChain, bool bUseMagnifier); 45 | void OnUpdateLocalDimmingChangedResources(SwapChain *pSwapChain); 46 | 47 | int LoadScene(GLTFCommon *pGLTFCommon, int Stage = 0); 48 | void UnloadScene(); 49 | 50 | void AllocateShadowMaps(GLTFCommon* pGLTFCommon); 51 | 52 | const std::vector &GetTimingValues() { return m_TimeStamps; } 53 | 54 | void OnRender(const UIState* pState, const Camera& Cam, SwapChain* pSwapChain); 55 | 56 | private: 57 | Device *m_pDevice; 58 | 59 | uint32_t m_Width; 60 | uint32_t m_Height; 61 | 62 | VkRect2D m_RectScissor; 63 | VkViewport m_Viewport; 64 | 65 | // Initialize helper classes 66 | ResourceViewHeaps m_ResourceViewHeaps; 67 | UploadHeap m_UploadHeap; 68 | DynamicBufferRing m_ConstantBufferRing; 69 | StaticBufferPool m_VidMemBufferPool; 70 | StaticBufferPool m_SysMemBufferPool; 71 | CommandListRing m_CommandListRing; 72 | GPUTimestamps m_GPUTimer; 73 | 74 | //gltf passes 75 | GltfPbrPass *m_GLTFPBR; 76 | GltfBBoxPass *m_GLTFBBox; 77 | GltfDepthPass *m_GLTFDepth; 78 | GLTFTexturesAndBuffers *m_pGLTFTexturesAndBuffers; 79 | 80 | // effects 81 | Bloom m_Bloom; 82 | SkyDome m_SkyDome; 83 | DownSamplePS m_DownSample; 84 | SkyDomeProc m_SkyDomeProc; 85 | ToneMapping m_ToneMappingPS; 86 | ToneMappingCS m_ToneMappingCS; 87 | ColorConversionPS m_ColorConversionPS; 88 | TAA m_TAA; 89 | MagnifierPS m_MagnifierPS; 90 | bool m_bMagResourceReInit = false; 91 | 92 | // GUI 93 | ImGUI m_ImGUI; 94 | 95 | // GBuffer and render passes 96 | GBuffer m_GBuffer; 97 | GBufferRenderPass m_RenderPassFullGBufferWithClear; 98 | GBufferRenderPass m_RenderPassJustDepthAndHdr; 99 | GBufferRenderPass m_RenderPassFullGBuffer; 100 | 101 | // shadowmaps 102 | VkRenderPass m_Render_pass_shadow; 103 | 104 | typedef struct { 105 | Texture ShadowMap; 106 | uint32_t ShadowIndex; 107 | uint32_t ShadowResolution; 108 | uint32_t LightIndex; 109 | VkImageView ShadowDSV; 110 | VkFramebuffer ShadowFrameBuffer; 111 | } SceneShadowInfo; 112 | 113 | std::vector m_shadowMapPool; 114 | std::vector< VkImageView> m_ShadowSRVPool; 115 | 116 | // widgets 117 | Wireframe m_Wireframe; 118 | WireframeBox m_WireframeBox; 119 | 120 | std::vector m_TimeStamps; 121 | 122 | AsyncPool m_AsyncPool; 123 | }; 124 | 125 | -------------------------------------------------------------------------------- /src/VK/UI.cpp: -------------------------------------------------------------------------------- 1 | // AMD SampleVK sample code 2 | // 3 | // Copyright(c) 2020 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 | 22 | #include "UI.h" 23 | #include "GLTFSample.h" 24 | #include "imgui.h" 25 | 26 | #include "base/FrameworkWindows.h" 27 | 28 | // To use the 'disabled UI state' functionality (ImGuiItemFlags_Disabled), include internal header 29 | // https://github.com/ocornut/imgui/issues/211#issuecomment-339241929 30 | #include "imgui_internal.h" 31 | static void DisableUIStateBegin(const bool& bEnable) 32 | { 33 | if (!bEnable) 34 | { 35 | ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); 36 | ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); 37 | } 38 | }; 39 | static void DisableUIStateEnd(const bool& bEnable) 40 | { 41 | if (!bEnable) 42 | { 43 | ImGui::PopItemFlag(); 44 | ImGui::PopStyleVar(); 45 | } 46 | }; 47 | 48 | // Some constants and utility functions 49 | static constexpr float MAGNIFICATION_AMOUNT_MIN = 1.0f; 50 | static constexpr float MAGNIFICATION_AMOUNT_MAX = 32.0f; 51 | static constexpr float MAGNIFIER_RADIUS_MIN = 0.01f; 52 | static constexpr float MAGNIFIER_RADIUS_MAX = 0.85f; 53 | static constexpr float MAGNIFIER_BORDER_COLOR__LOCKED[3] = { 0.002f, 0.72f, 0.0f }; // G 54 | static constexpr float MAGNIFIER_BORDER_COLOR__FREE[3] = { 0.72f, 0.002f, 0.0f }; // R 55 | template static T clamped(const T& v, const T& min, const T& max) 56 | { 57 | if (v < min) return min; 58 | else if (v > max) return max; 59 | else return v; 60 | } 61 | 62 | 63 | void GLTFSample::BuildUI() 64 | { 65 | // if we haven't initialized GLTFLoader yet, don't draw UI. 66 | if (m_pGltfLoader == nullptr) 67 | { 68 | LoadScene(m_activeScene); 69 | return; 70 | } 71 | 72 | ImGuiIO& io = ImGui::GetIO(); 73 | ImGuiStyle& style = ImGui::GetStyle(); 74 | style.FrameBorderSize = 1.0f; 75 | 76 | const uint32_t W = this->GetWidth(); 77 | const uint32_t H = this->GetHeight(); 78 | 79 | const uint32_t PROFILER_WINDOW_PADDIG_X = 10; 80 | const uint32_t PROFILER_WINDOW_PADDIG_Y = 10; 81 | const uint32_t PROFILER_WINDOW_SIZE_X = 330; 82 | const uint32_t PROFILER_WINDOW_SIZE_Y = 450; 83 | const uint32_t PROFILER_WINDOW_POS_X = W - PROFILER_WINDOW_PADDIG_X - PROFILER_WINDOW_SIZE_X; 84 | const uint32_t PROFILER_WINDOW_POS_Y = PROFILER_WINDOW_PADDIG_Y; 85 | 86 | const uint32_t CONTROLS_WINDOW_POS_X = 10; 87 | const uint32_t CONTROLS_WINDOW_POS_Y = 10; 88 | const uint32_t CONTROLW_WINDOW_SIZE_X = 350; 89 | const uint32_t CONTROLW_WINDOW_SIZE_Y = 780; // assuming > 720p 90 | 91 | // Render CONTROLS window 92 | // 93 | ImGui::SetNextWindowPos(ImVec2(CONTROLS_WINDOW_POS_X, CONTROLS_WINDOW_POS_Y), ImGuiCond_FirstUseEver); 94 | ImGui::SetNextWindowSize(ImVec2(CONTROLW_WINDOW_SIZE_X, CONTROLW_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); 95 | 96 | if (m_UIState.bShowControlsWindow) 97 | { 98 | ImGui::Begin("CONTROLS (F1)", &m_UIState.bShowControlsWindow); 99 | if (ImGui::CollapsingHeader("Animation", ImGuiTreeNodeFlags_DefaultOpen)) 100 | { 101 | ImGui::Checkbox("Play", &m_bPlay); 102 | ImGui::SliderFloat("Time", &m_time, 0, 30); 103 | } 104 | 105 | ImGui::Spacing(); 106 | ImGui::Spacing(); 107 | 108 | if (ImGui::CollapsingHeader("Scene", ImGuiTreeNodeFlags_DefaultOpen)) 109 | { 110 | char* cameraControl[] = { "Orbit", "WASD", "cam #0", "cam #1", "cam #2", "cam #3" , "cam #4", "cam #5" }; 111 | 112 | if (m_activeCamera >= m_pGltfLoader->m_cameras.size() + 2) 113 | m_activeCamera = 0; 114 | ImGui::Combo("Camera", &m_activeCamera, cameraControl, min((int)(m_pGltfLoader->m_cameras.size() + 2), _countof(cameraControl))); 115 | 116 | auto getterLambda = [](void* data, int idx, const char** out_str)->bool { *out_str = ((std::vector *)data)->at(idx).c_str(); return true; }; 117 | if (ImGui::Combo("Model", &m_activeScene, getterLambda, &m_sceneNames, (int)m_sceneNames.size())) 118 | { 119 | LoadScene(m_activeScene); 120 | 121 | //bail out as we need to reload everything 122 | ImGui::End(); 123 | ImGui::EndFrame(); 124 | ImGui::NewFrame(); 125 | return; 126 | } 127 | 128 | ImGui::SliderFloat("Emissive Intensity", &m_UIState.EmissiveFactor, 1.0f, 1000.0f, NULL, 1.0f); 129 | 130 | const char* skyDomeType[] = { "Procedural Sky", "cubemap", "Simple clear" }; 131 | ImGui::Combo("Skydome", &m_UIState.SelectedSkydomeTypeIndex, skyDomeType, _countof(skyDomeType)); 132 | 133 | ImGui::SliderFloat("IBL Factor", &m_UIState.IBLFactor, 0.0f, 3.0f); 134 | for (int i = 0; i < m_pGltfLoader->m_lights.size(); i++) 135 | { 136 | ImGui::SliderFloat(format("Light %i Intensity", i).c_str(), &m_pGltfLoader->m_lights[i].m_intensity, 0.0f, 50.0f); 137 | } 138 | if (ImGui::Button("Set Spot Light 0 to Camera's View")) 139 | { 140 | int idx = m_pGltfLoader->m_lightInstances[0].m_nodeIndex; 141 | m_pGltfLoader->m_nodes[idx].m_tranform.LookAt(m_camera.GetPosition(), m_camera.GetPosition() - m_camera.GetDirection()); 142 | m_pGltfLoader->m_animatedMats[idx] = m_pGltfLoader->m_nodes[idx].m_tranform.GetWorldMat(); 143 | } 144 | } 145 | 146 | ImGui::Spacing(); 147 | ImGui::Spacing(); 148 | 149 | if (ImGui::CollapsingHeader("PostProcessing", ImGuiTreeNodeFlags_DefaultOpen)) 150 | { 151 | const char* tonemappers[] = { "AMD Tonemapper", "DX11DSK", "Reinhard", "Uncharted2Tonemap", "ACES", "No tonemapper" }; 152 | ImGui::Combo("Tonemapper", &m_UIState.SelectedTonemapperIndex, tonemappers, _countof(tonemappers)); 153 | 154 | ImGui::SliderFloat("Exposure", &m_UIState.Exposure, 0.0f, 4.0f); 155 | 156 | ImGui::Checkbox("TAA", &m_UIState.bUseTAA); 157 | } 158 | 159 | ImGui::Spacing(); 160 | ImGui::Spacing(); 161 | 162 | if (ImGui::CollapsingHeader("Magnifier", ImGuiTreeNodeFlags_DefaultOpen)) 163 | { 164 | // read in Magnifier pass parameters from the UI & app state 165 | MagnifierPS::PassParameters& params = m_UIState.MagnifierParams; 166 | params.uImageHeight = m_Height; 167 | params.uImageWidth = m_Width; 168 | params.iMousePos[0] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionX : static_cast(io.MousePos.x); 169 | params.iMousePos[1] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionY : static_cast(io.MousePos.y); 170 | 171 | if (ImGui::Checkbox("Show Magnifier (M)", &m_UIState.bUseMagnifier)) 172 | { 173 | // We need to update IMGUI's renderpass to draw to magnfier's renderpass when in hdr 174 | // Hence, flush GPU and update it through OnUpdateDisplay 175 | // Which needs to do the same thing when display mode is changed. 176 | m_device.GPUFlush(); 177 | OnUpdateDisplay(); 178 | } 179 | 180 | DisableUIStateBegin(m_UIState.bUseMagnifier); 181 | { 182 | // use a local bool state here to track locked state through the UI widget, 183 | // and then call ToggleMagnifierLockedState() to update the persistent state (m_UIState). 184 | // the keyboard input for toggling lock directly operates on the persistent state. 185 | const bool bIsMagnifierCurrentlyLocked = m_UIState.bLockMagnifierPosition; 186 | bool bMagnifierToggle = bIsMagnifierCurrentlyLocked; 187 | ImGui::Checkbox("Lock Position (L)", &bMagnifierToggle); 188 | 189 | if (bMagnifierToggle != bIsMagnifierCurrentlyLocked) 190 | m_UIState.ToggleMagnifierLock(); 191 | 192 | ImGui::SliderFloat("Screen Size", ¶ms.fMagnifierScreenRadius, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); 193 | ImGui::SliderFloat("Magnification", ¶ms.fMagnificationAmount, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); 194 | ImGui::SliderInt("OffsetX", ¶ms.iMagnifierOffset[0], -m_Width, m_Width); 195 | ImGui::SliderInt("OffsetY", ¶ms.iMagnifierOffset[1], -m_Height, m_Height); 196 | } 197 | DisableUIStateEnd(m_UIState.bUseMagnifier); 198 | } 199 | 200 | ImGui::Spacing(); 201 | ImGui::Spacing(); 202 | 203 | if (ImGui::CollapsingHeader("Debug", ImGuiTreeNodeFlags_DefaultOpen)) 204 | { 205 | ImGui::Checkbox("Show Bounding Boxes", &m_UIState.bDrawBoundingBoxes); 206 | ImGui::Checkbox("Show Light Frustum", &m_UIState.bDrawLightFrustum); 207 | 208 | ImGui::Text("Wireframe"); 209 | ImGui::SameLine(); ImGui::RadioButton("Off", (int*)&m_UIState.WireframeMode, (int)UIState::WireframeMode::WIREFRAME_MODE_OFF); 210 | ImGui::SameLine(); ImGui::RadioButton("Shaded", (int*)&m_UIState.WireframeMode, (int)UIState::WireframeMode::WIREFRAME_MODE_SHADED); 211 | ImGui::SameLine(); ImGui::RadioButton("Solid color", (int*)&m_UIState.WireframeMode, (int)UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR); 212 | if (m_UIState.WireframeMode == UIState::WireframeMode::WIREFRAME_MODE_SOLID_COLOR) 213 | ImGui::ColorEdit3("Wire solid color", m_UIState.WireframeColor, ImGuiColorEditFlags_NoAlpha); 214 | } 215 | 216 | ImGui::Spacing(); 217 | ImGui::Spacing(); 218 | 219 | if (ImGui::CollapsingHeader("Presentation Mode", ImGuiTreeNodeFlags_DefaultOpen)) 220 | { 221 | const char* fullscreenModes[] = { "Windowed", "BorderlessFullscreen", "ExclusiveFulscreen" }; 222 | if (ImGui::Combo("Fullscreen Mode", (int*)&m_fullscreenMode, fullscreenModes, _countof(fullscreenModes))) 223 | { 224 | if (m_previousFullscreenMode != m_fullscreenMode) 225 | { 226 | HandleFullScreen(); 227 | m_previousFullscreenMode = m_fullscreenMode; 228 | } 229 | } 230 | } 231 | 232 | ImGui::Spacing(); 233 | ImGui::Spacing(); 234 | 235 | if (m_FreesyncHDROptionEnabled && ImGui::CollapsingHeader("FreeSync HDR", ImGuiTreeNodeFlags_DefaultOpen)) 236 | { 237 | static bool openWarning = false; 238 | const char** displayModeNames = &m_displayModesNamesAvailable[0]; 239 | if (ImGui::Combo("Display Mode", (int*)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) 240 | { 241 | if (m_fullscreenMode != PRESENTATIONMODE_WINDOWED) 242 | { 243 | UpdateDisplay(); 244 | m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; 245 | } 246 | else if (CheckIfWindowModeHdrOn() && 247 | (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_SDR || 248 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_2084 || 249 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_SCRGB)) 250 | { 251 | UpdateDisplay(); 252 | m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; 253 | } 254 | else 255 | { 256 | openWarning = true; 257 | m_currentDisplayModeNamesIndex = m_previousDisplayModeNamesIndex; 258 | } 259 | } 260 | 261 | if (openWarning) 262 | { 263 | ImGui::OpenPopup("Display Modes Warning"); 264 | ImGui::BeginPopupModal("Display Modes Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize); 265 | 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"); 266 | if (ImGui::Button("Cancel", ImVec2(120, 0))) { openWarning = false; ImGui::CloseCurrentPopup(); } 267 | ImGui::EndPopup(); 268 | } 269 | 270 | if (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_Gamma22 || 271 | m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_SCRGB) 272 | { 273 | if (ImGui::Checkbox("Enable Local Dimming", &m_enableLocalDimming)) 274 | { 275 | OnLocalDimmingChanged(); 276 | } 277 | } 278 | } 279 | 280 | ImGui::End(); // CONTROLS 281 | } 282 | 283 | 284 | // Render PROFILER window 285 | // 286 | if (m_UIState.bShowProfilerWindow) 287 | { 288 | constexpr size_t NUM_FRAMES = 128; 289 | static float FRAME_TIME_ARRAY[NUM_FRAMES] = { 0 }; 290 | 291 | // track highest frame rate and determine the max value of the graph based on the measured highest value 292 | static float RECENT_HIGHEST_FRAME_TIME = 0.0f; 293 | constexpr int FRAME_TIME_GRAPH_MAX_FPS[] = { 800, 240, 120, 90, 60, 45, 30, 15, 10, 5, 4, 3, 2, 1 }; 294 | static float FRAME_TIME_GRAPH_MAX_VALUES[_countof(FRAME_TIME_GRAPH_MAX_FPS)] = { 0 }; // us 295 | 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]; } 296 | 297 | //scrolling data and average FPS computing 298 | const std::vector& timeStamps = m_pRenderer->GetTimingValues(); 299 | const bool bTimeStampsAvailable = timeStamps.size() > 0; 300 | if (bTimeStampsAvailable) 301 | { 302 | RECENT_HIGHEST_FRAME_TIME = 0; 303 | FRAME_TIME_ARRAY[NUM_FRAMES - 1] = timeStamps.back().m_microseconds; 304 | for (uint32_t i = 0; i < NUM_FRAMES - 1; i++) 305 | { 306 | FRAME_TIME_ARRAY[i] = FRAME_TIME_ARRAY[i + 1]; 307 | } 308 | RECENT_HIGHEST_FRAME_TIME = max(RECENT_HIGHEST_FRAME_TIME, FRAME_TIME_ARRAY[NUM_FRAMES - 1]); 309 | } 310 | const float& frameTime_us = FRAME_TIME_ARRAY[NUM_FRAMES - 1]; 311 | const float frameTime_ms = frameTime_us * 0.001f; 312 | const int fps = bTimeStampsAvailable ? static_cast(1000000.0f / frameTime_us) : 0; 313 | 314 | // UI 315 | ImGui::SetNextWindowPos(ImVec2((float)PROFILER_WINDOW_POS_X, (float)PROFILER_WINDOW_POS_Y), ImGuiCond_FirstUseEver); 316 | ImGui::SetNextWindowSize(ImVec2(PROFILER_WINDOW_SIZE_X, PROFILER_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); 317 | ImGui::Begin("PROFILER (F2)", &m_UIState.bShowProfilerWindow); 318 | 319 | ImGui::Text("Resolution : %ix%i", m_Width, m_Height); 320 | ImGui::Text("API : %s", m_systemInfo.mGfxAPI.c_str()); 321 | ImGui::Text("GPU : %s", m_systemInfo.mGPUName.c_str()); 322 | ImGui::Text("CPU : %s", m_systemInfo.mCPUName.c_str()); 323 | ImGui::Text("FPS : %d (%.2f ms)", fps, frameTime_ms); 324 | 325 | if (ImGui::CollapsingHeader("GPU Timings", ImGuiTreeNodeFlags_DefaultOpen)) 326 | { 327 | std::string msOrUsButtonText = m_UIState.bShowMilliseconds ? "Switch to microseconds(us)" : "Switch to milliseconds(ms)"; 328 | if (ImGui::Button(msOrUsButtonText.c_str())) { 329 | m_UIState.bShowMilliseconds = !m_UIState.bShowMilliseconds; 330 | } 331 | ImGui::Spacing(); 332 | 333 | if (m_isCpuValidationLayerEnabled || m_isGpuValidationLayerEnabled) 334 | { 335 | ImGui::TextColored(ImVec4(1, 1, 0, 1), "WARNING: Validation layer is switched on"); 336 | ImGui::Text("Performance numbers may be inaccurate!"); 337 | } 338 | 339 | // find the index of the FrameTimeGraphMaxValue as the next higher-than-recent-highest-frame-time in the pre-determined value list 340 | size_t iFrameTimeGraphMaxValue = 0; 341 | for (int i = 0; i < _countof(FRAME_TIME_GRAPH_MAX_VALUES); ++i) 342 | { 343 | if (RECENT_HIGHEST_FRAME_TIME < FRAME_TIME_GRAPH_MAX_VALUES[i]) // FRAME_TIME_GRAPH_MAX_VALUES are in increasing order 344 | { 345 | iFrameTimeGraphMaxValue = min(_countof(FRAME_TIME_GRAPH_MAX_VALUES) - 1, i + 1); 346 | break; 347 | } 348 | } 349 | ImGui::PlotLines("", FRAME_TIME_ARRAY, NUM_FRAMES, 0, "GPU frame time (us)", 0.0f, FRAME_TIME_GRAPH_MAX_VALUES[iFrameTimeGraphMaxValue], ImVec2(0, 80)); 350 | 351 | for (uint32_t i = 0; i < timeStamps.size(); i++) 352 | { 353 | float value = m_UIState.bShowMilliseconds ? timeStamps[i].m_microseconds / 1000.0f : timeStamps[i].m_microseconds; 354 | const char* pStrUnit = m_UIState.bShowMilliseconds ? "ms" : "us"; 355 | ImGui::Text("%-18s: %7.2f %s", timeStamps[i].m_label.c_str(), value, pStrUnit); 356 | } 357 | } 358 | ImGui::End(); // PROFILER 359 | } 360 | } 361 | 362 | void UIState::Initialize() 363 | { 364 | // init magnifier params 365 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; // start at 'free' state 366 | 367 | // init GUI state 368 | this->SelectedTonemapperIndex = 0; 369 | this->bUseTAA = true; 370 | this->bUseMagnifier = false; 371 | this->bLockMagnifierPosition = this->bLockMagnifierPositionHistory = false; 372 | this->SelectedSkydomeTypeIndex = 0; 373 | this->Exposure = 1.0f; 374 | this->IBLFactor = 2.0f; 375 | this->EmissiveFactor = 1.0f; 376 | this->bDrawLightFrustum = false; 377 | this->bDrawBoundingBoxes = false; 378 | this->WireframeMode = WireframeMode::WIREFRAME_MODE_OFF; 379 | this->WireframeColor[0] = 0.0f; 380 | this->WireframeColor[1] = 1.0f; 381 | this->WireframeColor[2] = 0.0f; 382 | this->bShowControlsWindow = true; 383 | this->bShowProfilerWindow = true; 384 | } 385 | 386 | 387 | 388 | // 389 | // Magnifier UI Controls 390 | // 391 | void UIState::ToggleMagnifierLock() 392 | { 393 | if (this->bUseMagnifier) 394 | { 395 | this->bLockMagnifierPositionHistory = this->bLockMagnifierPosition; // record histroy 396 | this->bLockMagnifierPosition = !this->bLockMagnifierPosition; // flip state 397 | const bool bLockSwitchedOn = !this->bLockMagnifierPositionHistory && this->bLockMagnifierPosition; 398 | const bool bLockSwitchedOff = this->bLockMagnifierPositionHistory && !this->bLockMagnifierPosition; 399 | if (bLockSwitchedOn) 400 | { 401 | const ImGuiIO& io = ImGui::GetIO(); 402 | this->LockedMagnifiedScreenPositionX = static_cast(io.MousePos.x); 403 | this->LockedMagnifiedScreenPositionY = static_cast(io.MousePos.y); 404 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__LOCKED[ch]; 405 | } 406 | else if (bLockSwitchedOff) 407 | { 408 | for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; 409 | } 410 | } 411 | } 412 | // These are currently not bound to any mouse input and are here for convenience/reference. 413 | // Mouse scroll is currently wired up to camera for panning and moving in the local Z direction. 414 | // Any application that would prefer otherwise can utilize these for easily controlling the magnifier parameters through the desired input. 415 | void UIState::AdjustMagnifierSize (float increment /*= 0.05f*/){ MagnifierParams.fMagnifierScreenRadius = clamped(MagnifierParams.fMagnifierScreenRadius + increment, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); } 416 | void UIState::AdjustMagnifierMagnification(float increment /*= 1.00f*/){ MagnifierParams.fMagnificationAmount = clamped(MagnifierParams.fMagnificationAmount + increment, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); } 417 | -------------------------------------------------------------------------------- /src/VK/UI.h: -------------------------------------------------------------------------------- 1 | // AMD SampleVK sample code 2 | // 3 | // Copyright(c) 2020 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 | 34 | // 35 | // POST PROCESS CONTROLS 36 | // 37 | int SelectedTonemapperIndex; 38 | float Exposure; 39 | 40 | bool bUseTAA; 41 | 42 | bool bUseMagnifier; 43 | bool bLockMagnifierPosition; 44 | bool bLockMagnifierPositionHistory; 45 | int LockedMagnifiedScreenPositionX; 46 | int LockedMagnifiedScreenPositionY; 47 | MagnifierPS::PassParameters MagnifierParams; 48 | 49 | 50 | // 51 | // APP/SCENE CONTROLS 52 | // 53 | float IBLFactor; 54 | float EmissiveFactor; 55 | int SelectedSkydomeTypeIndex; 56 | 57 | bool bDrawLightFrustum; 58 | bool bDrawBoundingBoxes; 59 | 60 | enum class WireframeMode : int 61 | { 62 | WIREFRAME_MODE_OFF = 0, 63 | WIREFRAME_MODE_SHADED = 1, 64 | WIREFRAME_MODE_SOLID_COLOR = 2, 65 | }; 66 | 67 | WireframeMode WireframeMode; 68 | float WireframeColor[3]; 69 | 70 | // 71 | // PROFILER CONTROLS 72 | // 73 | bool bShowMilliseconds; 74 | 75 | // ----------------------------------------------- 76 | 77 | void Initialize(); 78 | 79 | void ToggleMagnifierLock(); 80 | void AdjustMagnifierSize(float increment = 0.05f); 81 | void AdjustMagnifierMagnification(float increment = 1.00f); 82 | }; -------------------------------------------------------------------------------- /src/VK/dpiawarescaling.manifest: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | true/PM 6 | 7 | 8 | -------------------------------------------------------------------------------- /src/VK/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // ObjRendererD3D12.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 | 10 | 11 | -------------------------------------------------------------------------------- /src/VK/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 | // Windows Header Files: 9 | #include 10 | #include 11 | 12 | // C RunTime Header Files 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "vulkan/vulkan.h" 20 | 21 | // Pull in math library 22 | #include "../../libs/vectormath/vectormath.hpp" 23 | 24 | // TODO: reference additional headers your program requires here 25 | #include "Base/Imgui.h" 26 | #include "Base/ImguiHelper.h" 27 | #include "Base/Device.h" 28 | #include "Base/Helper.h" 29 | #include "Base/Texture.h" 30 | #include "Base/FrameworkWindows.h" 31 | #include "Base/FreeSyncHDR.h" 32 | #include "Base/SwapChain.h" 33 | #include "Base/UploadHeap.h" 34 | #include "Base/GPUTimeStamps.h" 35 | #include "Base/CommandListRing.h" 36 | #include "Base/StaticBufferPool.h" 37 | #include "Base/DynamicBufferRing.h" 38 | #include "Base/ResourceViewHeaps.h" 39 | #include "Base/ShaderCompilerCache.h" 40 | #include "Base/ShaderCompilerHelper.h" 41 | 42 | 43 | #include "GLTF/GltfPbrPass.h" 44 | #include "GLTF/GltfBBoxPass.h" 45 | #include "GLTF/GltfDepthPass.h" 46 | 47 | #include "Misc/Misc.h" 48 | #include "Misc/Camera.h" 49 | 50 | #include "PostProc/TAA.h" 51 | #include "PostProc/Bloom.h" 52 | #include "PostProc/BlurPS.h" 53 | #include "PostProc/SkyDome.h" 54 | #include "PostProc/ToneMapping.h" 55 | #include "PostProc/ToneMappingCS.h" 56 | #include "PostProc/ColorConversionPS.h" 57 | #include "PostProc/SkyDomeProc.h" 58 | #include "PostProc/DownSamplePS.h" 59 | 60 | 61 | #include "Widgets/Axis.h" 62 | #include "Widgets/CheckerBoardFloor.h" 63 | #include "Widgets/WireframeBox.h" 64 | #include "Widgets/WireframeSphere.h" 65 | 66 | 67 | 68 | using namespace CAULDRON_VK; 69 | --------------------------------------------------------------------------------