From cb5fd829026947f91561803149b5fba4ba58d462 Mon Sep 17 00:00:00 2001 From: Rys Sommefeldt Date: Mon, 26 Apr 2021 15:14:29 +0100 Subject: [PATCH] FidelityFX LPM sample release v1.2 --- .gitlab-ci.yml | 4 +- ffx-lpm/ffx_a.h | 27 +- sample/CMakeLists.txt | 78 +- sample/build/GenerateSolutions.bat | 54 +- sample/common.cmake | 28 + sample/libs/cauldron | 2 +- sample/src/Common/CMakeLists.txt | 10 + sample/src/Common/LPMSample.json | 82 ++ sample/src/DX12/CMakeLists.txt | 92 +- sample/src/DX12/FlipBookAnimation.cpp | 9 +- sample/src/DX12/FlipBookAnimation.h | 12 +- sample/src/DX12/LPMPS.cpp | 48 +- sample/src/DX12/LPMPS.h | 18 +- sample/src/DX12/LPMSample.cpp | 550 ++++---- sample/src/DX12/LPMSample.h | 79 +- sample/src/DX12/Renderer.cpp | 657 ++++++++++ sample/src/DX12/Renderer.h | 129 ++ sample/src/DX12/SampleRenderer.cpp | 592 --------- sample/src/DX12/SampleRenderer.h | 123 -- sample/src/DX12/TestImages.cpp | 24 +- sample/src/DX12/TestImages.h | 17 +- sample/src/DX12/UI.cpp | 498 +++++++ sample/src/DX12/UI.h | 85 ++ sample/src/DX12/dpiawarescaling.manifest | 8 + .../src/DX12/shaders/FlipBookAnimationPS.hlsl | 24 +- .../src/DX12/shaders/FlipBookAnimationVS.hlsl | 32 +- sample/src/DX12/shaders/TestImagesPS.hlsl | 2 +- sample/src/DX12/stdafx.h | 90 +- sample/src/VK/CMakeLists.txt | 92 +- sample/src/VK/ExposureMultiplierCS.cpp | 3 +- sample/src/VK/FlipBookAnimation.cpp | 19 +- sample/src/VK/FlipBookAnimation.h | 12 +- sample/src/VK/LPMPS.cpp | 29 +- sample/src/VK/LPMPS.h | 16 +- sample/src/VK/LPMSample.cpp | 561 ++++---- sample/src/VK/LPMSample.h | 81 +- sample/src/VK/Renderer.cpp | 1026 +++++++++++++++ sample/src/VK/Renderer.h | 128 ++ sample/src/VK/SampleRenderer.cpp | 1148 ----------------- sample/src/VK/SampleRenderer.h | 138 -- sample/src/VK/TestImages.cpp | 34 +- sample/src/VK/TestImages.h | 20 +- sample/src/VK/UI.cpp | 507 ++++++++ sample/src/VK/UI.h | 85 ++ sample/src/VK/dpiawarescaling.manifest | 8 + .../src/VK/shaders/ExposureMultiplierCS.glsl | 2 +- .../src/VK/shaders/FlipBookAnimationPS.glsl | 6 +- .../src/VK/shaders/FlipBookAnimationVS.glsl | 2 +- sample/src/VK/shaders/LPMPS.glsl | 6 +- sample/src/VK/shaders/TestImagesPS.glsl | 4 +- sample/src/VK/stdafx.h | 86 +- 51 files changed, 4415 insertions(+), 2972 deletions(-) create mode 100644 sample/common.cmake create mode 100644 sample/src/Common/CMakeLists.txt create mode 100644 sample/src/Common/LPMSample.json create mode 100644 sample/src/DX12/Renderer.cpp create mode 100644 sample/src/DX12/Renderer.h delete mode 100644 sample/src/DX12/SampleRenderer.cpp delete mode 100644 sample/src/DX12/SampleRenderer.h create mode 100644 sample/src/DX12/UI.cpp create mode 100644 sample/src/DX12/UI.h create mode 100644 sample/src/DX12/dpiawarescaling.manifest create mode 100644 sample/src/VK/Renderer.cpp create mode 100644 sample/src/VK/Renderer.h delete mode 100644 sample/src/VK/SampleRenderer.cpp delete mode 100644 sample/src/VK/SampleRenderer.h create mode 100644 sample/src/VK/UI.cpp create mode 100644 sample/src/VK/UI.h create mode 100644 sample/src/VK/dpiawarescaling.manifest diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 118c21f..c33c152 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,6 +1,6 @@ variables: SampleName: LPMSample - CMakeConfig: -G "Visual Studio 15 2017" -A x64 + CMakeConfig: -G "Visual Studio 16 2019" -A x64 GIT_SUBMODULE_STRATEGY: normal stages: @@ -58,4 +58,4 @@ package_sample: - "%SampleName%/NOTICES.txt" - "%SampleName%/media" - "%SampleName%_VK.bat" - - "%SampleName%_DX12.bat" \ No newline at end of file + - "%SampleName%_DX12.bat" diff --git a/ffx-lpm/ffx_a.h b/ffx-lpm/ffx_a.h index 3feb0e2..2659048 100644 --- a/ffx-lpm/ffx_a.h +++ b/ffx-lpm/ffx_a.h @@ -50,6 +50,30 @@ // COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. //------------------------------------------------------------------------------------------------------------------------------ +// - https://github.com/michaldrobot/ShaderFastLibs/blob/master/LICENCE.txt +///****************************************************************************** +// The MIT License (MIT) +// +// Copyright (c) <2014> +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +// ******************************************************************************** // ABOUT // ===== // For questions and comments, feel free to contact the author directly: timothy.lottes@amd.com @@ -137,7 +161,6 @@ // Requires standard C types: stdint.h // Requires a collection of standard math intrinsics. // - Requires VS2013 when not using GCC to get exp2() and log2(). -// - https://blogs.msdn.microsoft.com/vcblog/2013/07/19/c99-library-support-in-visual-studio-2013/ //------------------------------------------------------------------------------------------------------------------------------ // This provides a minimum subset of functionality compared to the GPU parts. //============================================================================================================================== @@ -296,7 +319,7 @@ A_STATIC AD1 AAbsD1(AD1 a){return fabs(a);} A_STATIC AF1 AAbsF1(AF1 a){return fabsf(a);} A_STATIC AU1 AAbsSU1(AU1 a){return AU1_(abs(ASU1_(a)));} - A_STATIC AL1 AAbsSL1(AL1 a){return AL1_(labs(ASL1_(a)));} + A_STATIC AL1 AAbsSL1(AL1 a){return AL1_(llabs(ASL1_(a)));} #endif //------------------------------------------------------------------------------------------------------------------------------ #ifdef A_GCC diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index 4bc5a79..63bf2d5 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -1,7 +1,44 @@ -cmake_minimum_required(VERSION 3.4) -set(CMAKE_GENERATOR_PLATFORM x64) +cmake_minimum_required(VERSION 3.6) -project (LPMSample_${GFX_API}) +option (GFX_API_DX12 "Build with DX12" ON) +option (GFX_API_VK "Build with Vulkan" ON) + +if(NOT DEFINED GFX_API) + project (LPMSample) +else() + project (LPMSample_${GFX_API}) + + set_property(DIRECTORY ${CMAKE_PROJECT_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) + + if(GFX_API STREQUAL DX12) + set(GFX_API_DX12 ON) + set(GFX_API_VK OFF) + elseif(GFX_API STREQUAL VK) + set(GFX_API_DX12 OFF) + set(GFX_API_VK ON) + else() + message(STATUS "----------------------------------------------------------------------------------------") + message(STATUS "") + message(STATUS "** Almost there!!") + message(STATUS "") + message(STATUS " This framework supports DX12 and VULKAN, you need to invoke cmake in one of these ways:") + message(STATUS "") + message(STATUS " Examples:") + message(STATUS " Generate selected one:") + message(STATUS " cmake -DGFX_API=DX12") + message(STATUS " cmake -DGFX_API=VK") + message(STATUS " Generate with switches (Default is ON):") + message(STATUS " cmake [-DGFX_API_DX12=ON|OFF] [-DGFX_API_VK=ON|OFF]") + message(STATUS "") + message(STATUS "----------------------------------------------------------------------------------------") + message(FATAL_ERROR "") + endif() +endif() + +# Check MSVC toolset version, Visual Studio 2019 required +if(MSVC_TOOLSET_VERSION VERSION_LESS 142) + message(FATAL_ERROR "Cannot find MSVC toolset version 142 or greater. Please make sure Visual Studio 2019 or newer installed") +endif() # ouput exe to bin directory SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_HOME_DIRECTORY}/bin) @@ -10,27 +47,26 @@ foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} ) set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} ${CMAKE_HOME_DIRECTORY}/bin ) endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES ) +add_compile_options(/MP /MT) + # reference libs used by both backends add_subdirectory(libs/cauldron) +add_subdirectory(src/Common) -set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT ${PROJECT_NAME}) +# application icon +set(icon_src + ${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/GPUOpenChip.ico + ${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/resource.h + ${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/Cauldron_Common.rc +) -if(GFX_API STREQUAL DX12) - add_subdirectory(src/DX12) -elseif(GFX_API STREQUAL VK) +if(GFX_API_VK) find_package(Vulkan REQUIRED) add_subdirectory(src/VK) -else() - message(STATUS "----------------------------------------------------------------------------------------") - message(STATUS "") - message(STATUS "** Almost there!!") - message(STATUS "") - message(STATUS " This framework supports DX12 or VULKAN, you need to invoke cmake in one of these ways:") - message(STATUS "") - message(STATUS " Examples:") - message(STATUS " cmake -DGFX_API=DX12") - message(STATUS " cmake -DGFX_API=VK") - message(STATUS "") - message(STATUS "----------------------------------------------------------------------------------------") - message(FATAL_ERROR "") -endif() \ No newline at end of file +endif() +if(GFX_API_DX12) + add_subdirectory(src/DX12) +endif() + +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/Cauldron_Common.rc PROPERTIES VS_TOOL_OVERRIDE "Resource compiler") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/libs/cauldron/src/common/Icon/GPUOpenChip.ico PROPERTIES VS_TOOL_OVERRIDE "Image") diff --git a/sample/build/GenerateSolutions.bat b/sample/build/GenerateSolutions.bat index 5ee4fbc..98c1828 100644 --- a/sample/build/GenerateSolutions.bat +++ b/sample/build/GenerateSolutions.bat @@ -1,9 +1,59 @@ +@echo off +setlocal enabledelayedexpansion + +echo Checking pre-requisites... + +:: Check if CMake is installed +cmake --version > nul 2>&1 +if %errorlevel% NEQ 0 ( + echo Cannot find path to cmake. Is CMake installed? Exiting... + exit /b -1 +) else ( + echo CMake - Ready. +) + +:: Check if submodule is initialized (first time) to avoid CMake file not found errors +if not exist ..\libs\cauldron\common.cmake ( + echo File: common.cmake doesn't exist in '.\libs\cauldron\' - Initializing submodule... + + :: attempt to initialize submodule + cd .. + echo. + git submodule sync --recursive + git submodule update --init --recursive + cd build + + + :: check if submodule initialized properly + if not exist ..\libs\cauldron\common.cmake ( + echo. + echo '..\libs\cauldron\common.cmake is still not there.' + echo Could not initialize submodule. Make sure all the submodules are initialized and updated. + echo Exiting... + echo. + exit /b -1 + ) else ( + echo Cauldron - Ready. + ) +) else ( + echo Cauldron - Ready. +) + +:: Check if VULKAN_SDK is installed but don't bail out +if "%VULKAN_SDK%"=="" ( + echo Vulkan SDK is not installed -Environment variable VULKAN_SDK is not defined- : Please install the latest Vulkan SDK from LunarG. +) else ( + echo Vulkan SDK - Ready : %VULKAN_SDK% +) + + +:: Call CMake mkdir DX12 cd DX12 -cmake ..\.. -DGFX_API=DX12 +cmake -A x64 ..\.. -DGFX_API=DX12 cd .. mkdir VK cd VK -cmake ..\.. -DGFX_API=VK +cmake -A x64 ..\.. -DGFX_API=VK cd .. \ No newline at end of file diff --git a/sample/common.cmake b/sample/common.cmake new file mode 100644 index 0000000..4ea0fda --- /dev/null +++ b/sample/common.cmake @@ -0,0 +1,28 @@ +# +# enables multithreading compilation +# + +add_compile_options(/MP) + +# +# includes cauldron's helper cmakes +# +include(${CMAKE_CURRENT_SOURCE_DIR}/../../libs/cauldron/common.cmake) + +# +# Add manifest so the app uses the right DPI settings +# +function(addManifest PROJECT_NAME) + IF (MSVC) + IF (CMAKE_MAJOR_VERSION LESS 3) + MESSAGE(WARNING "CMake version 3.0 or newer is required use build variable TARGET_FILE") + ELSE() + ADD_CUSTOM_COMMAND( + TARGET ${PROJECT_NAME} + POST_BUILD + COMMAND "mt.exe" -manifest \"${CMAKE_CURRENT_SOURCE_DIR}\\dpiawarescaling.manifest\" -inputresource:\"$\"\;\#1 -outputresource:\"$\"\;\#1 + COMMENT "Adding display aware manifest..." + ) + ENDIF() + ENDIF(MSVC) +endfunction() \ No newline at end of file diff --git a/sample/libs/cauldron b/sample/libs/cauldron index 050b274..d220600 160000 --- a/sample/libs/cauldron +++ b/sample/libs/cauldron @@ -1 +1 @@ -Subproject commit 050b274df95777d688686d017a6926a515a58b30 +Subproject commit d22060043138b38e3aa01f766227ee0bd4e4f83e diff --git a/sample/src/Common/CMakeLists.txt b/sample/src/Common/CMakeLists.txt new file mode 100644 index 0000000..f17eced --- /dev/null +++ b/sample/src/Common/CMakeLists.txt @@ -0,0 +1,10 @@ +include(${CMAKE_CURRENT_SOURCE_DIR}/../../common.cmake) + +add_library(LPMSample_Common INTERFACE) + +set(config + ${CMAKE_CURRENT_SOURCE_DIR}/../Common/LPMSample.json +) + +copyTargetCommand("${config}" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY} copied_common_config) +add_dependencies(LPMSample_Common copied_common_config) diff --git a/sample/src/Common/LPMSample.json b/sample/src/Common/LPMSample.json new file mode 100644 index 0000000..78471c1 --- /dev/null +++ b/sample/src/Common/LPMSample.json @@ -0,0 +1,82 @@ +{ + "globals": { + "CpuValidationLayerEnabled": false, + "GpuValidationLayerEnabled": false, + "AGSEnabled": true, + "presentationMode": 0, + "width": 1920, + "height": 1080, + "activeScene": 0, + "benchmark": false, + "vsync": false, + "stablePowerState": false, + "fontsize": 13 + }, + "scenes": [ + { + "name": "Campfire", + "directory": "..\\media\\campfire\\", + "filename": "Campfire_scene_groundscaled.gltf", + "toneMapper": 0, + "emmisiveFactor": 1, + "intensity": 10, + "exposure": 1, + "activeCamera": 0, + "camera": { + "defaultFrom": [ -53.5, -26.0, -49.0 ], + "defaultTo": [ -52.0, -26.0, -47.0 ] + }, + "colorspace": 0, + "BenchmarkSettings": { + "timeStep": 1, + "timeStart": 0, + "timeEnd": 10000, + "exitWhenTimeEnds": true, + "resultsFilename": "Campfire.csv", + "warmUpFrames": 200, + "sequence": { + "timeStart": 0, + "timeEnd": 2000, + "keyFrames": [ + { + "time": 1000, + "from": [ -53.5, -26.0, -49.0 ], + "to": [ -52.0, -26.0, -47.0 ], + "screenShotName": "camera1.jpg" + } + ] + } + } + }, + { + "name": "Luxo Double Checker", + "directory": "..\\media\\color_ramp_bt2020_dcip3\\", + "filename": "LuxoDoubleChecker_EXR_ARGB_16F_1.DDS", + "toneMapper": 0, + "exposure": 1, + "colorspace": 0 + }, + { + "name": "DCI P3 1000 Nits", + "directory": "..\\media\\color_ramp_bt2020_dcip3\\", + "filename": "dcip3_1000_EXR_ARGB_16F_1.DDS", + "toneMapper": 0, + "exposure": 1, + "colorspace": 1 + }, + { + "name": "REC 2020 1000 Nits", + "directory": "..\\media\\color_ramp_bt2020_dcip3\\", + "filename": "bt2020_1000_EXR_ARGB_16F_1.DDS", + "toneMapper": 0, + "exposure": 1, + "colorspace": 2 + }, + { + "name": "Rec 709 5000 Nits", + "toneMapper": 0, + "exposure": 1, + "colorspace": 0 + } + ] +} diff --git a/sample/src/DX12/CMakeLists.txt b/sample/src/DX12/CMakeLists.txt index 752a5b5..cd561a9 100644 --- a/sample/src/DX12/CMakeLists.txt +++ b/sample/src/DX12/CMakeLists.txt @@ -1,55 +1,63 @@ project (LPMSample_${GFX_API}) set(sources - LPMSample.cpp - LPMSample.h - SampleRenderer.cpp - SampleRenderer.h - TestImages.cpp - TestImages.h - FlipBookAnimation.cpp - FlipBookAnimation.h - ExposureMultiplierCS.h - ExposureMultiplierCS.cpp - LPMPS.cpp - LPMPS.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h - stdafx.cpp - stdafx.h) + LPMSample.cpp + LPMSample.h + Renderer.cpp + Renderer.h + UI.cpp + UI.h + TestImages.cpp + TestImages.h + FlipBookAnimation.cpp + FlipBookAnimation.h + ExposureMultiplierCS.h + ExposureMultiplierCS.cpp + LPMPS.cpp + LPMPS.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h + stdafx.cpp + stdafx.h + dpiawarescaling.manifest) set(LPM_Shaders_src - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/TestImagesPS.hlsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationVS.hlsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationPS.hlsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/transferFunction.h - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/ExposureMultiplierCS.hlsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/LPMPS.hlsl - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h) - -source_group("Sources" FILES ${sources}) -source_group("LPM_Shaders_src" FILES ${LPM_Shaders_src}) - -add_executable(${PROJECT_NAME} WIN32 ${sources} ${LPM_Shaders_src}) -target_link_libraries (${PROJECT_NAME} LINK_PUBLIC Cauldron_DX12 ImGUI amd_ags DXC) + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/TestImagesPS.hlsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationVS.hlsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationPS.hlsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/transferFunction.h + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/ExposureMultiplierCS.hlsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/LPMPS.hlsl + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h) + +set(JSON_Data_src + ${CMAKE_CURRENT_SOURCE_DIR}/../Common/LPMSample.json) + +source_group("Sources" FILES ${sources}) +source_group("LPM_Shaders_src" FILES ${LPM_Shaders_src}) +source_group("Icon" FILES ${icon_src}) # defined in top-level CMakeLists.txt +source_group("JSON_Data" FILES ${JSON_Data_src}) + +add_executable(${PROJECT_NAME} WIN32 ${sources} ${LPM_Shaders_src} ${icon_src} ${JSON_Data_src}) +target_link_libraries (${PROJECT_NAME} LINK_PUBLIC LPMSample_Common Cauldron_DX12 ImGUI amd_ags d3dcompiler D3D12) set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin") set_source_files_properties(${LPM_Shaders_src} PROPERTIES VS_TOOL_OVERRIDE "Text") function(copyCommand list dest) - foreach(fullFileName ${list}) - get_filename_component(file ${fullFileName} NAME) - message("Generating custom command for ${fullFileName}") - add_custom_command( - OUTPUT ${dest}/${file} - PRE_BUILD - COMMAND cmake -E make_directory ${dest} - COMMAND cmake -E copy ${fullFileName} ${dest} - MAIN_DEPENDENCY ${fullFileName} - COMMENT "Updating ${file} into ${dest}" - ) - endforeach() + foreach(fullFileName ${list}) + get_filename_component(file ${fullFileName} NAME) + message("Generating custom command for ${fullFileName}") + add_custom_command( + OUTPUT ${dest}/${file} + PRE_BUILD + COMMAND cmake -E make_directory ${dest} + COMMAND cmake -E copy ${fullFileName} ${dest} + MAIN_DEPENDENCY ${fullFileName} + COMMENT "Updating ${file} into ${dest}" + ) + endforeach() endfunction() copyCommand("${LPM_Shaders_src}" ${CMAKE_HOME_DIRECTORY}/bin/ShaderLibDX) \ No newline at end of file diff --git a/sample/src/DX12/FlipBookAnimation.cpp b/sample/src/DX12/FlipBookAnimation.cpp index 60dba67..fc485a5 100644 --- a/sample/src/DX12/FlipBookAnimation.cpp +++ b/sample/src/DX12/FlipBookAnimation.cpp @@ -31,7 +31,7 @@ namespace CAULDRON_DX12 StaticBufferPool *pStaticBufferPool, UINT sampleDescCount, DXGI_FORMAT outFormat, - UINT numRows, UINT numColms, std::string flipBookAnimationTexture, XMMATRIX worldMatrix) + UINT numRows, UINT numColms, std::string flipBookAnimationTexture, math::Matrix4 worldMatrix) { m_pDevice = pDevice; m_pResourceViewHeaps = pResourceViewHeaps; @@ -182,7 +182,7 @@ namespace CAULDRON_DX12 m_pFlipBookTexture.OnDestroy(); } - void FlipBookAnimation::Draw(ID3D12GraphicsCommandList* pCommandList, float time, XMVECTOR camPos, XMMATRIX viewProjMat) + void FlipBookAnimation::Draw(ID3D12GraphicsCommandList* pCommandList, float time, math::Vector4 camPos, math::Matrix4 viewProjMat) { D3D12_GPU_VIRTUAL_ADDRESS cbFlipBookAnimation; FlipBookAnimationCBuffer *pFlipBookAnimation; @@ -191,9 +191,8 @@ namespace CAULDRON_DX12 pFlipBookAnimation->cols = m_numColms; pFlipBookAnimation->time = time; - XMFLOAT4 dist; - XMStoreFloat4(&dist, camPos - m_worldMatrix.r[3]); - float angle = atan2(dist.x, dist.z); + math::Vector4 dist = camPos - m_worldMatrix.getCol3(); + float angle = atan2(dist.getX(), dist.getZ()); pFlipBookAnimation->angle = angle; pFlipBookAnimation->camPos = camPos; diff --git a/sample/src/DX12/FlipBookAnimation.h b/sample/src/DX12/FlipBookAnimation.h index cb89925..f30653c 100644 --- a/sample/src/DX12/FlipBookAnimation.h +++ b/sample/src/DX12/FlipBookAnimation.h @@ -38,9 +38,9 @@ namespace CAULDRON_DX12 StaticBufferPool *pStaticBufferPool, UINT sampleDescCount, DXGI_FORMAT outFormat, - UINT numRows, UINT numColms, std::string flipBookAnimationTexture, XMMATRIX worldMatrix); + UINT numRows, UINT numColms, std::string flipBookAnimationTexture, math::Matrix4 worldMatrix); void OnDestroy(); - void Draw(ID3D12GraphicsCommandList* pCommandList, float time, XMVECTOR camPos, XMMATRIX viewProjMat); + void Draw(ID3D12GraphicsCommandList* pCommandList, float time, math::Vector4 camPos, math::Matrix4 viewProjMat); private: Device* m_pDevice; @@ -64,16 +64,16 @@ namespace CAULDRON_DX12 UINT m_numRows; UINT m_numColms; - XMMATRIX m_worldMatrix; + math::Matrix4 m_worldMatrix; struct FlipBookAnimationCBuffer { UINT row; UINT cols; float time; float angle; - XMVECTOR camPos; - XMMATRIX worldMat; - XMMATRIX viewProjMat; + math::Vector4 camPos; + math::Matrix4 worldMat; + math::Matrix4 viewProjMat; }; }; } \ No newline at end of file diff --git a/sample/src/DX12/LPMPS.cpp b/sample/src/DX12/LPMPS.cpp index e523af3..80ab669 100644 --- a/sample/src/DX12/LPMPS.cpp +++ b/sample/src/DX12/LPMPS.cpp @@ -102,7 +102,15 @@ namespace CAULDRON_DX12 m_scaleC = scaleC; } - void LPMPS::UpdatePipeline(DXGI_FORMAT outFormat, DisplayModes displayMode, ColorSpace colorSpace) + void LPMPS::UpdatePipeline(DXGI_FORMAT outFormat, DisplayMode displayMode, ColorSpace colorSpace, + bool shoulder, + float softGap, + float hdrMax, + float lpmExposure, + float contrast, + float shoulderContrast, + float saturation[3], + float crosstalk[3]) { m_lpm.UpdatePipeline(outFormat); @@ -121,30 +129,30 @@ namespace CAULDRON_DX12 varAF2(displayMinMaxLuminance); if (displayMode != DISPLAYMODE_SDR) { - const AGSDisplayInfo *agsDisplayInfo = fsHdrGetDisplayInfo(); + const DXGI_OUTPUT_DESC1 *displayInfo = GetDisplayInfo(); // Only used in fs2 modes - fs2R[0] = (float) agsDisplayInfo->chromaticityRedX; - fs2R[1] = (float) agsDisplayInfo->chromaticityRedY; - fs2G[0] = (float) agsDisplayInfo->chromaticityGreenX; - fs2G[1] = (float) agsDisplayInfo->chromaticityGreenY; - fs2B[0] = (float) agsDisplayInfo->chromaticityBlueX; - fs2B[1] = (float) agsDisplayInfo->chromaticityBlueY; - fs2W[0] = (float) agsDisplayInfo->chromaticityWhitePointX; - fs2W[1] = (float) agsDisplayInfo->chromaticityWhitePointY; + fs2R[0] = displayInfo->RedPrimary[0]; + fs2R[1] = displayInfo->RedPrimary[1]; + fs2G[0] = displayInfo->GreenPrimary[0]; + fs2G[1] = displayInfo->GreenPrimary[1]; + fs2B[0] = displayInfo->BluePrimary[0]; + fs2B[1] = displayInfo->BluePrimary[1]; + fs2W[0] = displayInfo->WhitePoint[0]; + fs2W[1] = displayInfo->WhitePoint[1]; // Only used in fs2 modes - displayMinMaxLuminance[0] = (float) agsDisplayInfo->minLuminance; - displayMinMaxLuminance[1] = (float) agsDisplayInfo->maxLuminance; + displayMinMaxLuminance[0] = displayInfo->MinLuminance; + displayMinMaxLuminance[1] = displayInfo->MaxLuminance; } - m_shoulder = 0; - m_softGap = 1.0f / 32.0f; - m_hdrMax = 256.0f; // Controls brightness. Need to tune according to display mode - m_exposure = 8.0f; // Controls brightness. Need to tune according to display mode - m_contrast = 0.3f; - m_shoulderContrast = 1.0f; - m_saturation[0] = 0.0f; m_saturation[1] = 0.0f; m_saturation[2] = 0.0f; - m_crosstalk[0] = 1.0f; m_crosstalk[1] = 1.0f / 2.0f; m_crosstalk[2] = 1.0f / 32.0f; + m_shoulder = shoulder; + m_softGap = softGap; + m_hdrMax = hdrMax; + m_exposure = lpmExposure; + m_contrast = contrast; + m_shoulderContrast = shoulderContrast; + m_saturation[0] = saturation[0]; m_saturation[1] = saturation[1]; m_saturation[2] = saturation[2]; + m_crosstalk[0] = crosstalk[0]; m_crosstalk[1] = crosstalk[1]; m_crosstalk[2] = crosstalk[2]; switch (colorSpace) { diff --git a/sample/src/DX12/LPMPS.h b/sample/src/DX12/LPMPS.h index af36220..148f009 100644 --- a/sample/src/DX12/LPMPS.h +++ b/sample/src/DX12/LPMPS.h @@ -27,7 +27,17 @@ namespace CAULDRON_DX12 public: void OnCreate(Device* pDevice, ResourceViewHeaps *pResourceViewHeaps, DynamicBufferRing *pDynamicBufferRing, StaticBufferPool *pStaticBufferPool, DXGI_FORMAT outFormat); void OnDestroy(); - void UpdatePipeline(DXGI_FORMAT outFormat, DisplayModes displayMode, ColorSpace colourSpace); + + void UpdatePipeline(DXGI_FORMAT outFormat, DisplayMode displayMode, ColorSpace colorSpace, + bool shoulder, + float softGap, + float hdrMax, + float lpmExposure, + float contrast, + float shoulderContrast, + float saturation[3], + float crosstalk[3]); + void Draw(ID3D12GraphicsCommandList* pCommandList, CBV_SRV_UAV *pSRV); private: @@ -61,8 +71,8 @@ namespace CAULDRON_DX12 PostProcPS m_lpm; DynamicBufferRing *m_pDynamicBufferRing = NULL; - DisplayModes m_displayMode; - XMMATRIX m_inputToOutputMatrix; + DisplayMode m_displayMode; + math::Matrix4 m_inputToOutputMatrix; struct LPMConsts { UINT shoulder; @@ -73,7 +83,7 @@ namespace CAULDRON_DX12 UINT scaleOnly; UINT displayMode; UINT pad; - XMMATRIX inputToOutputMatrix; + math::Matrix4 inputToOutputMatrix; uint32_t ctl[24 * 4]; }; }; diff --git a/sample/src/DX12/LPMSample.cpp b/sample/src/DX12/LPMSample.cpp index 233196b..8e21e79 100644 --- a/sample/src/DX12/LPMSample.cpp +++ b/sample/src/DX12/LPMSample.cpp @@ -18,18 +18,16 @@ // THE SOFTWARE. #include "stdafx.h" +#include #include "LPMSample.h" LPMSample::LPMSample(LPCSTR name) : FrameworkWindows(name) { - m_lastFrameTime = MillisecondsNow(); m_time = 0; m_bPlay = true; m_pGltfLoader = NULL; - m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; - m_disableLocalDimming = false; } //-------------------------------------------------------------------------------------- @@ -37,12 +35,82 @@ LPMSample::LPMSample(LPCSTR name) : FrameworkWindows(name) // OnParseCommandLine // //-------------------------------------------------------------------------------------- -void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight, bool* pbFullScreen) +void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight) { // set some default values *pWidth = 1920; *pHeight = 1080; - *pbFullScreen = false; + m_activeScene = 0; //load the first one by default + m_VsyncEnabled = false; + m_bIsBenchmarking = false; + m_fontSize = 13.f; // default value overridden by a json file if available + m_isCpuValidationLayerEnabled = false; + m_isGpuValidationLayerEnabled = false; + m_initializeAGS = false; + m_activeCamera = 0; + m_stablePowerState = false; + + //read globals + auto process = [&](json jData) + { + *pWidth = jData.value("width", *pWidth); + *pHeight = jData.value("height", *pHeight); + m_fullscreenMode = jData.value("presentationMode", m_fullscreenMode); + m_activeScene = jData.value("activeScene", m_activeScene); + m_activeCamera = jData.value("activeCamera", m_activeCamera); + m_isCpuValidationLayerEnabled = jData.value("CpuValidationLayerEnabled", m_isCpuValidationLayerEnabled); + m_isGpuValidationLayerEnabled = jData.value("GpuValidationLayerEnabled", m_isGpuValidationLayerEnabled); + m_initializeAGS = jData.value("AGSEnabled", m_initializeAGS); + m_VsyncEnabled = jData.value("vsync", m_VsyncEnabled); + m_bIsBenchmarking = jData.value("benchmark", m_bIsBenchmarking); + m_stablePowerState = jData.value("stablePowerState", m_stablePowerState); + m_fontSize = jData.value("fontsize", m_fontSize); + }; + + //read json globals from commandline + // + try + { + if (strlen(lpCmdLine) > 0) + { + auto j3 = json::parse(lpCmdLine); + process(j3); + } + } + catch (json::parse_error) + { + Trace("Error parsing commandline\n"); + exit(0); + } + + // read config file (and override values from commandline if so) + // + { + std::ifstream f("LPMSample.json"); + if (!f) + { + MessageBox(NULL, "Config file not found!\n", "Cauldron Panic!", MB_ICONERROR); + exit(0); + } + + try + { + f >> m_jsonConfigFile; + } + catch (json::parse_error) + { + MessageBox(NULL, "Error parsing LPMSample.json!\n", "Cauldron Panic!", MB_ICONERROR); + exit(0); + } + } + + + json globals = m_jsonConfigFile["globals"]; + process(globals); + + // get the list of scenes + for (const auto & scene : m_jsonConfigFile["scenes"]) + m_sceneNames.push_back(scene["name"]); } //-------------------------------------------------------------------------------------- @@ -50,42 +118,25 @@ void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* // OnCreate // //-------------------------------------------------------------------------------------- -void LPMSample::OnCreate(HWND hWnd) +void LPMSample::OnCreate() { - // Create Device - // - m_device.OnCreate("myapp", "myEngine", m_isCpuValidationLayerEnabled, m_isGpuValidationLayerEnabled, hWnd); - m_device.CreatePipelineCache(); - //init the shader compiler InitDirectXCompiler(); CreateShaderCache(); - // Create Swapchain - // - uint32_t dwNumberOfBackBuffers = 2; - m_swapChain.OnCreate(&m_device, dwNumberOfBackBuffers, hWnd); - // Create a instance of the renderer and initialize it, we need to do that for each GPU - // - m_Node = new SampleRenderer(); - m_Node->OnCreate(&m_device, &m_swapChain); + m_pRenderer = new Renderer(); + m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); // init GUI (non gfx stuff) - // - ImGUI_Init((void *)hWnd); - - // init GUI state - m_state.testPattern = 0; - m_state.colorSpace = ColorSpace::ColorSpace_REC709; - m_state.toneMapper = 6; - m_state.exposure = 0.5f; - m_state.unusedExposure = 1.0f; - m_state.emmisiveFactor = 1.0f; - m_state.camera.LookAt(10.0f, 0.0f, 3.5f, XMVectorSet(-52.0f, -26.0f, -47.0f, 0)); - m_state.lightIntensity = 10.0f; - - m_swapChain.EnumerateDisplayModes(&m_displayModesAvailable, &m_displayModesNamesAvailable); + ImGUI_Init((void*)m_windowHwnd); + m_UIState.Initialize(); + + OnResize(); + OnUpdateDisplay(); + + // Init Camera, looking at the origin + m_camera.LookAt(math::Vector4(0, 0, 5, 0), math::Vector4(0, 0, 0, 0)); } //-------------------------------------------------------------------------------------- @@ -99,20 +150,11 @@ void LPMSample::OnDestroy() m_device.GPUFlush(); - // Set display mode to SDR before quitting. - m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; - - // Fullscreen state should always be false before exiting the app. - m_swapChain.SetFullScreen(false); + m_pRenderer->UnloadScene(); + m_pRenderer->OnDestroyWindowSizeDependentResources(); + m_pRenderer->OnDestroy(); - m_Node->UnloadScene(); - m_Node->OnDestroyWindowSizeDependentResources(); - m_Node->OnDestroy(); - - delete m_Node; - - m_swapChain.OnDestroyWindowSizeDependentResources(); - m_swapChain.OnDestroy(); + delete m_pRenderer; //shut down the shader compiler DestroyShaderCache(&m_device); @@ -122,287 +164,279 @@ void LPMSample::OnDestroy() delete m_pGltfLoader; m_pGltfLoader = NULL; } - - m_device.DestroyPipelineCache(); - m_device.OnDestroy(); } //-------------------------------------------------------------------------------------- // -// OnEvent +// OnEvent, win32 sends us events and we forward them to ImGUI // //-------------------------------------------------------------------------------------- +static void ToggleBool(bool& b) { b = !b; } bool LPMSample::OnEvent(MSG msg) { if (ImGUI_WndProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam)) return true; + // handle function keys (F1, F2...) here, rest of the input is handled + // by imGUI later in HandleInput() function + const WPARAM& KeyPressed = msg.wParam; + switch (msg.message) + { + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + + /* WINDOW TOGGLES */ + if (KeyPressed == VK_F1) ToggleBool(m_UIState.bShowControlsWindow); + if (KeyPressed == VK_F2) ToggleBool(m_UIState.bShowProfilerWindow); + break; + } + return true; } //-------------------------------------------------------------------------------------- // -// SetFullScreen +// OnResize // //-------------------------------------------------------------------------------------- -void LPMSample::SetFullScreen(bool fullscreen) +void LPMSample::OnResize() { - m_device.GPUFlush(); + // Destroy resources (if we are not minimized) + if (m_Width && m_Height && m_pRenderer) + { + m_pRenderer->OnDestroyWindowSizeDependentResources(); + m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); + } - // when going to windowed make sure we are always using SDR - if ((fullscreen == false) && (m_currentDisplayMode != DISPLAYMODE_SDR)) - m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; + m_camera.SetFov(AMD_PI_OVER_4, m_Width, m_Height, 0.1f, 1000.0f); +} - m_swapChain.SetFullScreen(fullscreen); +//-------------------------------------------------------------------------------------- +// +// UpdateDisplay +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnUpdateDisplay() +{ + // Update resources that depend on display mode changed + if (m_pRenderer) + { + m_pRenderer->OnUpdateDisplayDependentResources(&m_swapChain, &m_UIState); + } } //-------------------------------------------------------------------------------------- // -// OnResize +// LoadScene // //-------------------------------------------------------------------------------------- -void LPMSample::OnResize(uint32_t width, uint32_t height) +void LPMSample::LoadScene(int sceneIndex) { - // Flush GPU - // - m_device.GPUFlush(); + json scene = m_jsonConfigFile["scenes"][sceneIndex]; - // If resizing but no minimizing - // - if (m_Width > 0 && m_Height > 0) + // release everything and load the GLTF, just the light json data, the rest (textures and geometry) will be done in the main loop + if (m_pGltfLoader != NULL) { - if (m_Node != NULL) + m_pRenderer->UnloadScene(); + m_pRenderer->OnDestroyWindowSizeDependentResources(); + m_pRenderer->OnDestroy(); + m_pGltfLoader->Unload(); + m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); + m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); + } + + delete(m_pGltfLoader); + m_pGltfLoader = new GLTFCommon(); + if (m_pGltfLoader->Load(scene["directory"], scene["filename"]) == false) + { + MessageBox(NULL, "The selected model couldn't be found, please check the documentation", "Cauldron Panic!", MB_ICONERROR); + exit(0); + } + + // Load the UI settings, and also some defaults cameras and lights, in case the GLTF has none + { +#define LOAD(j, key, val) val = j.value(key, val) + + // global settings + LOAD(scene, "toneMapper", m_UIState.SelectedTonemapperIndex); + LOAD(scene, "exposure", m_UIState.Exposure); + LOAD(scene, "emmisiveFactor", m_UIState.EmissiveFactor); + + // Add a default light in case there are none + // + if (m_pGltfLoader->m_lights.size() == 0) { - m_Node->OnDestroyWindowSizeDependentResources(); + tfNode n; + n.m_tranform.LookAt(PolarToVector(AMD_PI_OVER_2, 0.58f) * 3.5f, math::Vector4(0, 0, 0, 0)); + + tfLight l; + l.m_type = tfLight::LIGHT_SPOTLIGHT; + l.m_intensity = scene.value("intensity", 1.0f); + l.m_color = math::Vector4(1.0f, 1.0f, 1.0f, 0.0f); + l.m_range = 15; + l.m_outerConeAngle = AMD_PI_OVER_4; + l.m_innerConeAngle = AMD_PI_OVER_4 * 0.9f; + + m_pGltfLoader->AddLight(n, l); } - m_swapChain.OnDestroyWindowSizeDependentResources(); - } - m_Width = width; - m_Height = height; + // Allocate shadow information (if any) + m_pRenderer->AllocateShadowMaps(m_pGltfLoader); - m_swapChain.EnumerateDisplayModes(&m_displayModesAvailable, &m_displayModesNamesAvailable); + // set default camera + // + json camera = scene["camera"]; + m_activeCamera = scene.value("activeCamera", m_activeCamera); + math::Vector4 from = GetVector(GetElementJsonArray(camera, "defaultFrom", { 0.0, 0.0, 10.0 })); + math::Vector4 to = GetVector(GetElementJsonArray(camera, "defaultTo", { 0.0, 0.0, 0.0 })); + m_camera.LookAt(from, to); - // if resizing but not minimizing the recreate it with the new size - // - if (m_Width > 0 && m_Height > 0) - { - m_swapChain.OnCreateWindowSizeDependentResources(m_Width, m_Height, false, m_currentDisplayMode, m_disableLocalDimming); - if (m_Node != NULL) + // set benchmarking state if enabled + // + if (m_bIsBenchmarking) { - m_Node->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height, &m_state); + std::string deviceName; + std::string driverVersion; + m_device.GetDeviceInfo(&deviceName, &driverVersion); + BenchmarkConfig(scene["BenchmarkSettings"], m_activeCamera, m_pGltfLoader, deviceName, driverVersion); } - } - m_state.camera.SetFov(XM_PI / 4, m_Width, m_Height, 0.1f, 1000.0f); + // indicate the mainloop we started loading a GLTF and it needs to load the rest (textures and geometry) + m_loadingScene = true; + } } - //-------------------------------------------------------------------------------------- // -// OnActivate +// OnUpdate // //-------------------------------------------------------------------------------------- -void LPMSample::OnActivate(bool windowActive) +void LPMSample::OnUpdate() { - if (m_previousDisplayMode == DisplayModes::DISPLAYMODE_SDR && m_currentDisplayMode == DisplayModes::DISPLAYMODE_SDR) - return; + ImGuiIO& io = ImGui::GetIO(); - m_currentDisplayMode = windowActive && m_swapChain.IsFullScreen() ? m_previousDisplayMode : DisplayModes::DISPLAYMODE_SDR; - m_currentDisplayModeNamesIndex= windowActive && m_swapChain.IsFullScreen() ? m_previousDisplayModeNamesIndex : DisplayModes::DISPLAYMODE_SDR; + //If the mouse was not used by the GUI then it's for the camera + if (io.WantCaptureMouse) + { + io.MouseDelta.x = 0; + io.MouseDelta.y = 0; + io.MouseWheel = 0; + } - OnResize(m_Width, m_Height); -} + // Update Camera + UpdateCamera(m_camera, io); -//-------------------------------------------------------------------------------------- -// -// OnRender -// -//-------------------------------------------------------------------------------------- -void LPMSample::OnRender() -{ - // Get timings - // - double timeNow = MillisecondsNow(); - m_deltaTime = timeNow - m_lastFrameTime; - m_lastFrameTime = timeNow; + // Keyboard & Mouse + HandleInput(io); - // Build UI and set the scene state. Note that the rendering of the UI happens later. - // - ImGUI_UpdateIO(); - ImGui::NewFrame(); + // Animation Update + if (m_bPlay) + m_time += (float)m_deltaTime / 1000.0f; // animation time in seconds - static int cameraControlSelected = 1; - static int loadingStage = 0; - if (loadingStage >= 0) + if (m_pGltfLoader) { - // LoadScene needs to be called a number of times, the scene is not fully loaded until it returns -1 - // This is done so we can display a progress bar when the scene is loading - if (m_pGltfLoader == NULL) - { - m_pGltfLoader = new GLTFCommon(); - m_pGltfLoader->Load("..\\media\\campfire\\", "Campfire_scene_groundscaled.gltf"); - } - - loadingStage = m_Node->LoadScene(m_pGltfLoader, loadingStage); + m_pGltfLoader->SetAnimationTime(0, m_time); + m_pGltfLoader->TransformScene(0, math::Matrix4::identity()); } - else - { - ImGuiStyle& style = ImGui::GetStyle(); - style.FrameBorderSize = 1.0f; +} +void LPMSample::HandleInput(const ImGuiIO& io) +{ + auto fnIsKeyTriggered = [&io](char key) { return io.KeysDown[key] && io.KeysDownDuration[key] == 0.0f; }; - bool opened = true; - ImGui::Begin("Stats", &opened); + // Handle Keyboard/Mouse input here - if (ImGui::CollapsingHeader("Info", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Text("Resolution : %ix%i", m_Width, m_Height); - std::vector timeStamps = m_Node->GetTimingValues(); - if (timeStamps.size() > 0) - { - static float values[128]; - values[127] = (float)(timeStamps.back().m_microseconds - timeStamps.front().m_microseconds); - float average = values[0]; - for (int i = 0; i < 128 - 1; i++) { values[i] = values[i + 1]; average += values[i]; } - average /= 128; - - ImGui::Text("%-17s:%7.1f FPS", "Framerate", (1.0f / average) * 1000000.0f); - } - } + /* MAGNIFIER CONTROLS */ + if (fnIsKeyTriggered('L')) m_UIState.ToggleMagnifierLock(); + if (fnIsKeyTriggered('M') || io.MouseClicked[2]) ToggleBool(m_UIState.bUseMagnifier); // middle mouse / M key toggles magnifier - if (ImGui::CollapsingHeader("Scene Setup", ImGuiTreeNodeFlags_DefaultOpen)) - { - static float exposureStep = 0.0f; - ImGui::SliderFloat("Exposure", &exposureStep, -4.0f, +1.0f, NULL, 1.0f); - m_state.exposure = (float)pow(2, exposureStep); - ImGui::SliderFloat("Emmisive", &m_state.emmisiveFactor, 0.0f, 2.0f, NULL, 1.0f); - ImGui::SliderFloat("PointLightIntensity", &m_state.lightIntensity, 0.0f, 20.0f); - - const char * tonemappers[] = { "Timothy", "DX11DSK", "Reinhard", "Uncharted2Tonemap", "ACES", "No tonemapper", "FidelityFX LPM" }; - ImGui::Combo("Tone mapper", &m_state.toneMapper, tonemappers, _countof(tonemappers)); - - static bool openWarning = false; - - const char **displayModeNames = &m_displayModesNamesAvailable[0]; - if (ImGui::Combo("Display Mode", (int *)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) - { - if (m_swapChain.IsFullScreen()) - { - m_previousDisplayMode = m_currentDisplayMode = m_displayModesAvailable[m_currentDisplayModeNamesIndex]; - m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; - OnResize(m_Width, m_Height); - } - else - { - openWarning = true; - m_previousDisplayMode = m_currentDisplayMode = DisplayModes::DISPLAYMODE_SDR; - m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DisplayModes::DISPLAYMODE_SDR; - } - } - - if (openWarning) - { - ImGui::OpenPopup("Display Modes Warning"); - ImGui::BeginPopupModal("Display Modes Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::Text("\nChanging display modes is only available in fullscreen, please press ALT + ENTER for fun!\n\n"); - if (ImGui::Button("Cancel", ImVec2(120, 0))) { openWarning = false; ImGui::CloseCurrentPopup(); } - ImGui::EndPopup(); - } - - if (m_currentDisplayMode == DisplayModes::DISPLAYMODE_FSHDR_Gamma22 || m_currentDisplayMode == DisplayModes::DISPLAYMODE_FSHDR_SCRGB) - { - if (ImGui::Checkbox("Disable Local Dimming", &m_disableLocalDimming)) - { - OnResize(m_Width, m_Height); - } - } - - const char * testPatterns[] = { "None", "Luxo Double Checker", "DCI P3 1000 Nits", "REC 2020 1000 Nits", "Rec 709 5000 Nits" }; - if (ImGui::Combo("Test Patterns", &m_state.testPattern, testPatterns, _countof(testPatterns))) - { - if (m_state.testPattern == 2) // P3 - m_state.colorSpace = ColorSpace::ColorSpace_P3; - else if (m_state.testPattern == 3) // rec2020 - m_state.colorSpace = ColorSpace::ColorSpace_REC2020; - else // Rec 709 - m_state.colorSpace = ColorSpace::ColorSpace_REC709; - - // Flush GPU - // - m_device.GPUFlush(); - - if (m_Node != NULL) - { - m_Node->OnDestroyWindowSizeDependentResources(); - m_Node->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height, &m_state); - } - } - - const char * cameraControl[] = { "WASD", "Orbit" }; - ImGui::Combo("Camera", &cameraControlSelected, cameraControl, _countof(cameraControl)); - } + if (io.MouseClicked[1] && m_UIState.bUseMagnifier) // right mouse click + m_UIState.ToggleMagnifierLock(); + + if (fnIsKeyTriggered('R')) + m_UIState.ResetLPMSceneDefaults(); +} +void LPMSample::UpdateCamera(Camera& cam, const ImGuiIO& io) +{ + float yaw = cam.GetYaw(); + float pitch = cam.GetPitch(); + float distance = cam.GetDistance(); - ImGui::End(); + cam.UpdatePreviousMatrices(); // set previous view matrix + + // Sets Camera based on UI selection (WASD, Orbit or any of the GLTF cameras) + if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) + { + yaw -= io.MouseDelta.x / 100.f; + pitch += io.MouseDelta.y / 100.f; } - // If the mouse was not used by the GUI then it's for the camera - // - ImGuiIO& io = ImGui::GetIO(); - if (io.WantCaptureMouse == false) + // Choose camera movement depending on setting + if (m_activeCamera == 0) { - float yaw = m_state.camera.GetYaw(); - float pitch = m_state.camera.GetPitch(); - float distance = m_state.camera.GetDistance(); + // Orbiting + distance -= (float)io.MouseWheel / 3.0f; + distance = std::max(distance, 0.1f); - if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) - { - yaw -= io.MouseDelta.x / 100.f; - pitch += io.MouseDelta.y / 100.f; - } + bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); - // Choose camera movement depending on setting - // + cam.UpdateCameraPolar(yaw, pitch, + panning ? -io.MouseDelta.x / 100.0f : 0.0f, + panning ? io.MouseDelta.y / 100.0f : 0.0f, + distance); + } + else if (m_activeCamera == 1) + { + // WASD + cam.UpdateCameraWASD(yaw, pitch, io.KeysDown, io.DeltaTime); + } + else if (m_activeCamera > 1) + { + // Use a camera from the GLTF + m_pGltfLoader->GetCamera(m_activeCamera - 2, &cam); + } +} - if (cameraControlSelected == 0) - { - // WASD - // - m_state.camera.UpdateCameraWASD(yaw, pitch, io.KeysDown, io.DeltaTime); - } - else - { - // Orbiting - // - distance -= (float)io.MouseWheel / 3.0f; - distance = std::max(distance, 0.1f); +//-------------------------------------------------------------------------------------- +// +// OnRender +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnRender() +{ + // Do any start of frame necessities + BeginFrame(); - bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); + ImGUI_UpdateIO(); + ImGui::NewFrame(); - m_state.camera.UpdateCameraPolar(yaw, pitch, panning ? -io.MouseDelta.x / 100.0f : 0.0f, panning ? io.MouseDelta.y / 100.0f : 0.0f, distance); + if (m_loadingScene) + { + // the scene loads in chunks, that way we can show a progress bar + static int loadingStage = 0; + loadingStage = m_pRenderer->LoadScene(m_pGltfLoader, loadingStage); + if (loadingStage == 0) + { + m_time = 0; + m_loadingScene = false; } } - - // Set animation time - // - if (m_bPlay) + else if (m_pGltfLoader && m_bIsBenchmarking) { - m_time += (float)m_deltaTime / 1000.0f; - } - - // transform scene - // - if (m_pGltfLoader) + // Benchmarking takes control of the time, and exits the app when the animation is done + std::vector timeStamps = m_pRenderer->GetTimingValues(); + m_time = BenchmarkLoop(timeStamps, &m_camera, m_pRenderer->GetScreenshotFileName()); + } + else { - m_pGltfLoader->SetAnimationTime(0, m_time); - m_pGltfLoader->TransformScene(0, XMMatrixIdentity()); + BuildUI(); // UI logic. Note that the rendering of the UI happens later. + OnUpdate(); // Update camera, handle keyboard/mouse input } - m_state.time = m_time; - - // Do Render frame using AFR - // - m_Node->OnRender(&m_state, &m_swapChain); + // Do Render frame using AFR + m_pRenderer->OnRender(&m_UIState, m_camera, &m_swapChain, m_time); - m_swapChain.Present(); + // Framework will handle Present and some other end of frame logic + EndFrame(); } @@ -416,7 +450,7 @@ int WINAPI WinMain(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow) { - LPCSTR Name = "LPMSample DX12 v1.0"; + LPCSTR Name = "LPMSample DX12 v1.2"; // create new DX sample return RunFramework(hInstance, lpCmdLine, nCmdShow, new LPMSample(Name)); diff --git a/sample/src/DX12/LPMSample.h b/sample/src/DX12/LPMSample.h index b0de4a5..b2e1af2 100644 --- a/sample/src/DX12/LPMSample.h +++ b/sample/src/DX12/LPMSample.h @@ -18,61 +18,52 @@ // THE SOFTWARE. #pragma once -#include "SampleRenderer.h" +#include "base/FrameworkWindows.h" +#include "Renderer.h" +#include "UI.h" - -// -// This is the main class, it manages the state of the sample and does all the high level work without touching the GPU directly. -// This class uses the GPU via the the SampleRenderer class. We would have a SampleRenderer instance for each GPU. -// -// This class takes care of: -// -// - loading a scene (just the CPU data) -// - updating the camera -// - keeping track of time -// - handling the keyboard -// - updating the animation -// - building the UI (but do not renders it) -// - uses the SampleRenderer to update all the state to the GPU and do the rendering -// +// This class encapsulates the 'application' and is responsible for handling window events and scene updates (simulation) +// Rendering and rendering resource management is done by the Renderer class class LPMSample : public FrameworkWindows { public: LPMSample(LPCSTR name); - void OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight, bool* pbFullScreen); - void OnCreate(HWND hWnd); - void OnDestroy(); - void OnRender(); - bool OnEvent(MSG msg); - void OnResize(uint32_t Width, uint32_t Height); - void OnActivate(bool windowActive); - void SetFullScreen(bool fullscreen); - -private: + void OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight) override; + void OnCreate() override; + void OnDestroy() override; + void OnRender() override; + bool OnEvent(MSG msg) override; + void OnResize() override; + void OnUpdateDisplay() override; + + void BuildUI(); + void LoadScene(int sceneIndex); - Device m_device; - SwapChain m_swapChain; + void OnUpdate(); + + void HandleInput(const ImGuiIO& io); + void UpdateCamera(Camera& cam, const ImGuiIO& io); + +private: - DisplayModes m_previousDisplayMode; - DisplayModes m_currentDisplayMode; - DisplayModes m_previousDisplayModeNamesIndex; - DisplayModes m_currentDisplayModeNamesIndex; - std::vector m_displayModesAvailable; - std::vector m_displayModesNamesAvailable; - bool m_disableLocalDimming; + bool m_bIsBenchmarking; - GLTFCommon *m_pGltfLoader; + GLTFCommon *m_pGltfLoader = NULL; + bool m_loadingScene = false; - SampleRenderer *m_Node; - SampleRenderer::State m_state; + Renderer *m_pRenderer = NULL; + UIState m_UIState; + float m_fontSize; + Camera m_camera; - float m_time; - double m_deltaTime; // The elapsed time since the previous frame. - double m_lastFrameTime; + float m_time; // Time accumulator in seconds, used for animation. - bool m_isCpuValidationLayerEnabled = false; - bool m_isGpuValidationLayerEnabled = false; + // json config file + json m_jsonConfigFile; + std::vector m_sceneNames; + int m_activeScene; + int m_activeCamera; - bool m_bPlay; + bool m_bPlay; }; diff --git a/sample/src/DX12/Renderer.cpp b/sample/src/DX12/Renderer.cpp new file mode 100644 index 0000000..f9f8a45 --- /dev/null +++ b/sample/src/DX12/Renderer.cpp @@ -0,0 +1,657 @@ +// AMD LPMSample sample code +// +// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "Renderer.h" +#include "UI.h" + +#include + +//-------------------------------------------------------------------------------------- +// +// OnCreate +// +//-------------------------------------------------------------------------------------- +void Renderer::OnCreate(Device* pDevice, SwapChain* pSwapChain, float fontSize) +{ + m_pDevice = pDevice; + + // Initialize helpers + + // Create all the heaps for the resources views + const uint32_t cbvDescriptorCount = 4000; + const uint32_t srvDescriptorCount = 8000; + const uint32_t uavDescriptorCount = 10; + const uint32_t dsvDescriptorCount = 10; + const uint32_t rtvDescriptorCount = 60; + const uint32_t samplerDescriptorCount = 20; + m_resourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, dsvDescriptorCount, rtvDescriptorCount, samplerDescriptorCount); + + // Create a commandlist ring for the Direct queue + uint32_t commandListsPerBackBuffer = 8; + m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer, pDevice->GetGraphicsQueue()->GetDesc()); + + // Create a 'dynamic' constant buffer + const uint32_t constantBuffersMemSize = 200 * 1024 * 1024; + m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, &m_resourceViewHeaps); + + // Create a 'static' pool for vertices, indices and constant buffers + const uint32_t staticGeometryMemSize = (5 * 128) * 1024 * 1024; + m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, true, "StaticGeom"); + + // initialize the GPU time stamps module + m_GPUTimer.OnCreate(pDevice, backBufferCount); + + // Quick helper to upload resources, it has it's own commandList and uses suballocation. + // for 4K textures we'll need 100Megs + const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024; + m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results) + + // Create GBuffer and render passes + // + { + m_GBuffer.OnCreate( + pDevice, + &m_resourceViewHeaps, + { + { GBUFFER_DEPTH, DXGI_FORMAT_D32_FLOAT}, + { GBUFFER_FORWARD, DXGI_FORMAT_R16G16B16A16_FLOAT}, + }, + 1 + ); + + GBufferFlags fullGBuffer = GBUFFER_DEPTH | GBUFFER_FORWARD; + m_renderPassFullGBuffer.OnCreate(&m_GBuffer, fullGBuffer); + m_renderPassJustDepthAndHdr.OnCreate(&m_GBuffer, GBUFFER_DEPTH | GBUFFER_FORWARD); + } + + m_downSample.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); + m_bloom.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); + m_magnifierPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); + + // Create tonemapping pass + m_toneMappingPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); + m_toneMappingCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); + m_colorConversionPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); + + // Initialize UI rendering resources + m_ImGUI.OnCreate(pDevice, &m_UploadHeap, &m_resourceViewHeaps, &m_ConstantBufferRing, DXGI_FORMAT_R16G16B16A16_FLOAT, fontSize); + + math::Matrix4 campfireWorldMatrix = math::Matrix4(math::Vector4(0.5f, 0.0f, 0.0f, 0.0f), + math::Vector4(0.0f, 0.5f, 0.0f, 0.0f), + math::Vector4(0.0f, 0.0f, 0.5f, 0.0f), + math::Vector4(-47.3f, -26.5f, -40.425f, 1.0f)); + m_CampfireAnimation.OnCreate(pDevice, &m_UploadHeap, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, 1, DXGI_FORMAT_R16G16B16A16_FLOAT, 12, 12, "..\\media\\FlipBookAnimationTextures\\cf_loop_comp_v1_mosaic.png", campfireWorldMatrix); + + m_testImages.OnCreate(pDevice, &m_UploadHeap, &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing, DXGI_FORMAT_R16G16B16A16_FLOAT); + + // Create tonemapping pass + m_exposureMultiplierCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); + m_lpmPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); + + // Make sure upload heap has finished uploading before continuing + m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); + m_UploadHeap.FlushAndFinish(); +} + +//-------------------------------------------------------------------------------------- +// +// OnDestroy +// +//-------------------------------------------------------------------------------------- +void Renderer::OnDestroy() +{ + m_lpmPS.OnDestroy(); + m_exposureMultiplierCS.OnDestroy(); + m_testImages.OnDestroy(); + m_CampfireAnimation.OnDestroy(); + + m_asyncPool.Flush(); + + m_ImGUI.OnDestroy(); + m_colorConversionPS.OnDestroy(); + m_toneMappingCS.OnDestroy(); + m_toneMappingPS.OnDestroy(); + m_bloom.OnDestroy(); + m_downSample.OnDestroy(); + m_magnifierPS.OnDestroy(); + m_GBuffer.OnDestroy(); + + m_UploadHeap.OnDestroy(); + m_GPUTimer.OnDestroy(); + m_VidMemBufferPool.OnDestroy(); + m_ConstantBufferRing.OnDestroy(); + m_resourceViewHeaps.OnDestroy(); + m_CommandListRing.OnDestroy(); +} + +//-------------------------------------------------------------------------------------- +// +// OnCreateWindowSizeDependentResources +// +//-------------------------------------------------------------------------------------- +void Renderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height) +{ + m_Width = Width; + m_Height = Height; + + // Set the viewport & scissors rect + m_viewport = { 0.0f, 0.0f, static_cast(Width), static_cast(Height), 0.0f, 1.0f }; + m_rectScissor = { 0, 0, (LONG)Width, (LONG)Height }; + + // Create GBuffer + // + m_GBuffer.OnCreateWindowSizeDependentResources(pSwapChain, Width, Height); + m_renderPassFullGBuffer.OnCreateWindowSizeDependentResources(Width, Height); + m_renderPassJustDepthAndHdr.OnCreateWindowSizeDependentResources(Width, Height); + + // update bloom and downscaling effect + // + m_downSample.OnCreateWindowSizeDependentResources(m_Width, m_Height, &m_GBuffer.m_HDR, 5); //downsample the HDR texture 5 times + m_bloom.OnCreateWindowSizeDependentResources(m_Width / 2, m_Height / 2, m_downSample.GetTexture(), 5, &m_GBuffer.m_HDR); + m_magnifierPS.OnCreateWindowSizeDependentResources(&m_GBuffer.m_HDR); +} + +//-------------------------------------------------------------------------------------- +// +// OnDestroyWindowSizeDependentResources +// +//-------------------------------------------------------------------------------------- +void Renderer::OnDestroyWindowSizeDependentResources() +{ + m_magnifierPS.OnDestroyWindowSizeDependentResources(); + m_bloom.OnDestroyWindowSizeDependentResources(); + m_downSample.OnDestroyWindowSizeDependentResources(); + m_GBuffer.OnDestroyWindowSizeDependentResources(); +} + +//-------------------------------------------------------------------------------------- +// +// OnUpdateDisplayDependentResources +// +//-------------------------------------------------------------------------------------- +void Renderer::OnUpdateDisplayDependentResources(SwapChain* pSwapChain, const UIState* pState) +{ + // update the pipelines if the swapchain render pass has changed (for example when the format of the swapchain changes) + // + m_colorConversionPS.UpdatePipelines(pSwapChain->GetFormat(), pSwapChain->GetDisplayMode()); + m_toneMappingPS.UpdatePipelines(pSwapChain->GetFormat()); + m_lpmPS.UpdatePipeline(pSwapChain->GetFormat(), pSwapChain->GetDisplayMode(), pState->ColorSpace, + pState->bShoulder, + pState->SoftGap, + pState->HdrMax, + pState->LpmExposure, + pState->Contrast, + pState->ShoulderContrast, + (float *) pState->Saturation, + (float *) pState->Crosstalk); +} + +//-------------------------------------------------------------------------------------- +// +// LoadScene +// +//-------------------------------------------------------------------------------------- +int Renderer::LoadScene(GLTFCommon *pGLTFCommon, int stage) +{ + // show loading progress + // + ImGui::OpenPopup("Loading"); + if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + float progress = (float)stage / 10.0f; + ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL); + ImGui::EndPopup(); + } + + // use multi threading + AsyncPool *pAsyncPool = &m_asyncPool; + + // Loading stages + // + if (stage == 0) + { + } + else if (stage == 5) + { + Profile p("m_pGltfLoader->Load"); + + m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers(); + m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing); + } + else if (stage == 6) + { + Profile p("LoadTextures"); + + // here we are loading onto the GPU all the textures and the inverse matrices + // this data will be used to create the PBR and Depth passes + m_pGLTFTexturesAndBuffers->LoadTextures(pAsyncPool); + } + else if (stage == 7) + { + Profile p("m_gltfDepth->OnCreate"); + + //create the glTF's textures, VBs, IBs, shaders and descriptors for this particular pass + m_gltfDepth = new GltfDepthPass(); + m_gltfDepth->OnCreate( + m_pDevice, + &m_UploadHeap, + &m_resourceViewHeaps, + &m_ConstantBufferRing, + &m_VidMemBufferPool, + m_pGLTFTexturesAndBuffers, + pAsyncPool + ); + } + else if (stage == 8) + { + Profile p("m_gltfPBR->OnCreate"); + + // same thing as above but for the PBR pass + m_gltfPBR = new GltfPbrPass(); + m_gltfPBR->OnCreate( + m_pDevice, + &m_UploadHeap, + &m_resourceViewHeaps, + &m_ConstantBufferRing, + m_pGLTFTexturesAndBuffers, + nullptr, + false, // use a SSAO mask + false, + &m_renderPassFullGBuffer, + pAsyncPool + ); + + // we are borrowing the upload heap command list for uploading to the GPU the IBs and VBs + m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); + } + else if (stage == 9) + { + Profile p("Flush"); + + m_UploadHeap.FlushAndFinish(); + + //once everything is uploaded we dont need he upload heaps anymore + m_VidMemBufferPool.FreeUploadHeap(); + + // tell caller that we are done loading the map + return 0; + } + + stage++; + return stage; +} + +//-------------------------------------------------------------------------------------- +// +// UnloadScene +// +//-------------------------------------------------------------------------------------- +void Renderer::UnloadScene() +{ + // wait for all the async loading operations to finish + m_asyncPool.Flush(); + + m_pDevice->GPUFlush(); + + if (m_gltfPBR) + { + m_gltfPBR->OnDestroy(); + delete m_gltfPBR; + m_gltfPBR = NULL; + } + + if (m_gltfDepth) + { + m_gltfDepth->OnDestroy(); + delete m_gltfDepth; + m_gltfDepth = NULL; + } + + if (m_pGLTFTexturesAndBuffers) + { + m_pGLTFTexturesAndBuffers->OnDestroy(); + delete m_pGLTFTexturesAndBuffers; + m_pGLTFTexturesAndBuffers = NULL; + } + + while (!m_shadowMapPool.empty()) + { + m_shadowMapPool.back().ShadowMap.OnDestroy(); + m_shadowMapPool.pop_back(); + } +} + +void Renderer::AllocateShadowMaps(GLTFCommon* pGLTFCommon) +{ + // Go through the lights and allocate shadow information + uint32_t NumShadows = 0; + for (int i = 0; i < pGLTFCommon->m_lightInstances.size(); ++i) + { + const tfLight& lightData = pGLTFCommon->m_lights[pGLTFCommon->m_lightInstances[i].m_lightId]; + if (lightData.m_shadowResolution) + { + SceneShadowInfo ShadowInfo; + ShadowInfo.ShadowResolution = lightData.m_shadowResolution; + ShadowInfo.ShadowIndex = NumShadows++; + ShadowInfo.LightIndex = i; + m_shadowMapPool.push_back(ShadowInfo); + } + } + + if (NumShadows > MaxShadowInstances) + { + Trace("Number of shadows has exceeded maximum supported. Please grow value in gltfCommon.h/perFrameStruct.h"); + throw; + } + + // If we had shadow information, allocate all required maps and bindings + if (!m_shadowMapPool.empty()) + { + m_resourceViewHeaps.AllocDSVDescriptor((uint32_t)m_shadowMapPool.size(), &m_ShadowMapPoolDSV); + m_resourceViewHeaps.AllocCBV_SRV_UAVDescriptor((uint32_t)m_shadowMapPool.size(), &m_ShadowMapPoolSRV); + + std::vector::iterator CurrentShadow = m_shadowMapPool.begin(); + for( uint32_t i = 0; CurrentShadow < m_shadowMapPool.end(); ++i, ++CurrentShadow) + { + 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)); + CurrentShadow->ShadowMap.CreateDSV(CurrentShadow->ShadowIndex, &m_ShadowMapPoolDSV); + CurrentShadow->ShadowMap.CreateSRV(CurrentShadow->ShadowIndex, &m_ShadowMapPoolSRV); + } + } +} + +//-------------------------------------------------------------------------------------- +// +// OnRender +// +//-------------------------------------------------------------------------------------- +void Renderer::OnRender(const UIState* pState, const Camera& cam, SwapChain* pSwapChain, float time) +{ + // Timing values + UINT64 gpuTicksPerSecond; + m_pDevice->GetGraphicsQueue()->GetTimestampFrequency(&gpuTicksPerSecond); + + // Let our resource managers do some house keeping + m_CommandListRing.OnBeginFrame(); + m_ConstantBufferRing.OnBeginFrame(); + m_GPUTimer.OnBeginFrame(gpuTicksPerSecond, &m_TimeStamps); + + // Sets the perFrame data + per_frame *pPerFrame = NULL; + if (m_pGLTFTexturesAndBuffers) + { + // fill as much as possible using the GLTF (camera, lights, ...) + pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(cam); + + // Set some lighting factors + pPerFrame->emmisiveFactor = pState->EmissiveFactor; + pPerFrame->invScreenResolution[0] = 1.0f / ((float)m_Width); + pPerFrame->invScreenResolution[1] = 1.0f / ((float)m_Height); + + m_pGLTFTexturesAndBuffers->SetPerFrameConstants(); + m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons(); + } + + // command buffer calls + ID3D12GraphicsCommandList* pCmdLst1 = m_CommandListRing.GetNewCommandList(); + + m_GPUTimer.GetTimeStamp(pCmdLst1, "Begin Frame"); + + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); + + // Render shadow maps + std::vector ShadowReadBarriers; + std::vector ShadowWriteBarriers; + if (m_gltfDepth && pPerFrame != NULL) + { + std::vector::iterator ShadowMap = m_shadowMapPool.begin(); + while (ShadowMap < m_shadowMapPool.end()) + { + pCmdLst1->ClearDepthStencilView(m_ShadowMapPoolDSV.GetCPU(ShadowMap->ShadowIndex), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); + ++ShadowMap; + } + m_GPUTimer.GetTimeStamp(pCmdLst1, "Clear shadow maps"); + + // Render all shadows + ShadowMap = m_shadowMapPool.begin(); + while (ShadowMap < m_shadowMapPool.end()) + { + SetViewportAndScissor(pCmdLst1, 0, 0, ShadowMap->ShadowResolution, ShadowMap->ShadowResolution); + pCmdLst1->OMSetRenderTargets(0, NULL, false, &m_ShadowMapPoolDSV.GetCPU(ShadowMap->ShadowIndex)); + + GltfDepthPass::per_frame* cbDepthPerFrame = m_gltfDepth->SetPerFrameConstants(); + cbDepthPerFrame->mViewProj = pPerFrame->lights[ShadowMap->LightIndex].mLightViewProj; + + m_gltfDepth->Draw(pCmdLst1); + + // Push a barrier + ShadowReadBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(ShadowMap->ShadowMap.GetResource(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); + ShadowWriteBarriers.push_back(CD3DX12_RESOURCE_BARRIER::Transition(ShadowMap->ShadowMap.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); + + m_GPUTimer.GetTimeStamp(pCmdLst1, "Shadow map"); + ++ShadowMap; + } + + // Transition all shadow map barriers + pCmdLst1->ResourceBarrier((UINT)ShadowReadBarriers.size(), ShadowReadBarriers.data()); + } + + // Render Scene to the GBuffer ------------------------------------------------ + if (pPerFrame != NULL) + { + pCmdLst1->RSSetViewports(1, &m_viewport); + pCmdLst1->RSSetScissorRects(1, &m_rectScissor); + + if (m_gltfPBR) + { + std::vector opaque, transparent; + m_gltfPBR->BuildBatchLists(&opaque, &transparent); + + // Render opaque geometry + { + m_renderPassFullGBuffer.BeginPass(pCmdLst1, true); + m_gltfPBR->DrawBatchList(pCmdLst1, &m_ShadowMapPoolSRV, &opaque); + m_GPUTimer.GetTimeStamp(pCmdLst1, "PBR Opaque"); + m_renderPassFullGBuffer.EndPass(); + } + + // Draw campfire + m_CampfireAnimation.Draw(pCmdLst1, time, cam.GetPosition(), cam.GetProjection() * cam.GetView()); + + // draw transparent geometry + { + m_renderPassFullGBuffer.BeginPass(pCmdLst1, false); + + std::sort(transparent.begin(), transparent.end()); + m_gltfPBR->DrawBatchList(pCmdLst1, &m_ShadowMapPoolSRV, &transparent); + m_GPUTimer.GetTimeStamp(pCmdLst1, "PBR Transparent"); + + m_renderPassFullGBuffer.EndPass(); + } + } + } + + if (ShadowWriteBarriers.size()) + pCmdLst1->ResourceBarrier((UINT)ShadowWriteBarriers.size(), ShadowWriteBarriers.data()); + + D3D12_RESOURCE_BARRIER preResolve[1] = { + CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), + }; + pCmdLst1->ResourceBarrier(1, preResolve); + + // Post proc--------------------------------------------------------------------------- + + // Bloom, takes HDR as input and applies bloom to it. + { + D3D12_CPU_DESCRIPTOR_HANDLE renderTargets[] = { m_GBuffer.m_HDRRTV.GetCPU() }; + pCmdLst1->OMSetRenderTargets(ARRAYSIZE(renderTargets), renderTargets, false, NULL); + + m_downSample.Draw(pCmdLst1); + //m_downSample.Gui(); + m_GPUTimer.GetTimeStamp(pCmdLst1, "Downsample"); + + m_bloom.Draw(pCmdLst1, &m_GBuffer.m_HDR); + //m_bloom.Gui(); + m_GPUTimer.GetTimeStamp(pCmdLst1, "Bloom"); + } + + // Render TestPattern ------------------------------------------------------------------------ + // + { + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); + if (pState->TestPattern) + { + pCmdLst1->RSSetViewports(1, &m_viewport); + pCmdLst1->RSSetScissorRects(1, &m_rectScissor); + pCmdLst1->OMSetRenderTargets(1, &m_GBuffer.m_HDRRTV.GetCPU(), true, NULL); + + m_testImages.Draw(pCmdLst1, pState->TestPattern); + m_GPUTimer.GetTimeStamp(pCmdLst1, "Test Pattern Rendering"); + } + } + + // Apply Exposure ------------------------------------------------------------------------ + // + { + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_UNORDERED_ACCESS)); + + m_exposureMultiplierCS.Draw(pCmdLst1, &m_GBuffer.m_HDRUAV, pState->Exposure, m_Width, m_Height); + + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RENDER_TARGET)); + + m_GPUTimer.GetTimeStamp(pCmdLst1, "Apply Exposure"); + } + + // Render HUD ------------------------------------------------------------------------ + // + { + pCmdLst1->RSSetViewports(1, &m_viewport); + pCmdLst1->RSSetScissorRects(1, &m_rectScissor); + pCmdLst1->OMSetRenderTargets(1, &m_GBuffer.m_HDRRTV.GetCPU(), true, NULL); + + m_ImGUI.Draw(pCmdLst1); + + m_GPUTimer.GetTimeStamp(pCmdLst1, "ImGUI Rendering"); + + D3D12_RESOURCE_BARRIER hdrToSRV = CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + pCmdLst1->ResourceBarrier(1, &hdrToSRV); + } + + // Magnifier Pass: m_HDR as input, pass' own output + // + if (pState->bUseMagnifier) + { + pCmdLst1->RSSetViewports(1, &m_viewport); + pCmdLst1->RSSetScissorRects(1, &m_rectScissor); + + // Note: assumes m_GBuffer.HDR is in D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + m_magnifierPS.Draw(pCmdLst1, pState->MagnifierParams, m_GBuffer.m_HDRSRV); + m_GPUTimer.GetTimeStamp(pCmdLst1, "Magnifier"); + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_COPY_DEST)); + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_magnifierPS.GetPassOutputResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_COPY_SOURCE)); + + pCmdLst1->CopyResource(m_GBuffer.m_HDR.GetResource(), m_magnifierPS.GetPassOutputResource()); + + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_COPY_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); + pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_magnifierPS.GetPassOutputResource(), D3D12_RESOURCE_STATE_COPY_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); + } + + // If using FreeSync HDR we need to do the tonemapping in-place and then later we'll apply the color conversion into the swapchain + // We need to skip this step if using LPM tonemapper as that does the color conversion along with tone and gamut mapping + const bool bHDR = pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR; + if (bHDR && pState->SelectedTonemapperIndex > 0) + { + D3D12_RESOURCE_BARRIER hdrToUAV = CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); + pCmdLst1->ResourceBarrier(1, &hdrToUAV); + + m_toneMappingCS.Draw(pCmdLst1, &m_GBuffer.m_HDRUAV, pState->UnusedExposure, pState->SelectedTonemapperIndex - 1, m_Width, m_Height); + + D3D12_RESOURCE_BARRIER hdrToSRV = CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); + pCmdLst1->ResourceBarrier(1, &hdrToSRV); + + m_GPUTimer.GetTimeStamp(pCmdLst1, "Tone mapping"); + } + + // submit command buffer #1 + ThrowIfFailed(pCmdLst1->Close()); + ID3D12CommandList* CmdListList1[] = { pCmdLst1 }; + m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList1); + + // Wait for swapchain (we are going to render to it) ----------------------------------- + pSwapChain->WaitForSwapChain(); + + + ID3D12GraphicsCommandList* pCmdLst2 = m_CommandListRing.GetNewCommandList(); + + pCmdLst2->RSSetViewports(1, &m_viewport); + pCmdLst2->RSSetScissorRects(1, &m_rectScissor); + pCmdLst2->OMSetRenderTargets(1, pSwapChain->GetCurrentBackBufferRTV(), true, NULL); + + // Tonemapping LPM ------------------------------------------------------------------------ + // + if (pState->SelectedTonemapperIndex == 0) + { + m_lpmPS.Draw(pCmdLst2, &m_GBuffer.m_HDRSRV); + m_GPUTimer.GetTimeStamp(pCmdLst2, "Tone mapping LPM"); + } + else + { + if (bHDR) + { + // FS2 mode! Apply color conversion now. + // + m_colorConversionPS.Draw(pCmdLst2, &m_GBuffer.m_HDRSRV); + } + else + { + // non FS2 mode, that is SDR, here we apply the tonemapping from the HDR into the swapchain + + // Tonemapping ------------------------------------------------------------------------ + m_toneMappingPS.Draw(pCmdLst2, &m_GBuffer.m_HDRSRV, pState->UnusedExposure, pState->SelectedTonemapperIndex - 1); + m_GPUTimer.GetTimeStamp(pCmdLst2, "Tone mapping"); + } + } + + pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_GBuffer.m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); + + const bool bTakeScreenshot = !m_ScreenShotName.empty(); + if (bTakeScreenshot) + { + m_saveTexture.CopyRenderTargetIntoStagingTexture(m_pDevice->GetDevice(), pCmdLst2, pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_RENDER_TARGET); + } + + // Transition swapchain into present mode + pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); + + m_GPUTimer.OnEndFrame(); + + m_GPUTimer.CollectTimings(pCmdLst2); + + // Close & Submit the command list #2 ------------------------------------------------- + ThrowIfFailed(pCmdLst2->Close()); + + ID3D12CommandList* CmdListList2[] = { pCmdLst2 }; + m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList2); + + if (bTakeScreenshot) + { + m_saveTexture.SaveStagingTextureAsJpeg(m_pDevice->GetDevice(), m_pDevice->GetGraphicsQueue(), m_ScreenShotName.c_str()); + m_ScreenShotName = ""; + } +} diff --git a/sample/src/DX12/Renderer.h b/sample/src/DX12/Renderer.h new file mode 100644 index 0000000..77e21d1 --- /dev/null +++ b/sample/src/DX12/Renderer.h @@ -0,0 +1,129 @@ +// AMD LPMSample sample code +// +// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +#pragma once + +#include "stdafx.h" + +#include "base/GBuffer.h" +#include "PostProc/MagnifierPS.h" + +struct UIState; + +// We are queuing (backBufferCount + 0.5) frames, so we need to triple buffer the resources that get modified each frame +static const int backBufferCount = 3; + +using namespace CAULDRON_DX12; + +// +// This class deals with the GPU side of the sample. +// +class Renderer +{ +public: + + void OnCreate(Device* pDevice, SwapChain *pSwapChain, float fontSize); + void OnDestroy(); + + void OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height); + void OnDestroyWindowSizeDependentResources(); + + void OnUpdateDisplayDependentResources(SwapChain *pSwapChain, const UIState *pState); + + int LoadScene(GLTFCommon *pGLTFCommon, int stage = 0); + void UnloadScene(); + + void AllocateShadowMaps(GLTFCommon* pGLTFCommon); + + const std::vector &GetTimingValues() { return m_TimeStamps; } + std::string& GetScreenshotFileName() { return m_ScreenShotName; } + + void OnRender(const UIState* pState, const Camera& cam, SwapChain* pSwapChain, float time); + +private: + Device *m_pDevice; + + uint32_t m_Width; + uint32_t m_Height; + D3D12_VIEWPORT m_viewport; + D3D12_RECT m_rectScissor; + + // Initialize helper classes + ResourceViewHeaps m_resourceViewHeaps; + UploadHeap m_UploadHeap; + DynamicBufferRing m_ConstantBufferRing; + StaticBufferPool m_VidMemBufferPool; + CommandListRing m_CommandListRing; + GPUTimestamps m_GPUTimer; + + //gltf passes + GltfPbrPass *m_gltfPBR; + GltfDepthPass *m_gltfDepth; + GLTFTexturesAndBuffers *m_pGLTFTexturesAndBuffers; + + // effects + // effects + Bloom m_bloom; + SkyDome m_skyDome; + DownSamplePS m_downSample; + SkyDomeProc m_skyDomeProc; + ToneMapping m_toneMappingPS; + ToneMappingCS m_toneMappingCS; + ColorConversionPS m_colorConversionPS; + MagnifierPS m_magnifierPS; + + // GUI + ImGUI m_ImGUI; + + // Temporary render targets + GBuffer m_GBuffer; + GBufferRenderPass m_renderPassFullGBuffer; + GBufferRenderPass m_renderPassJustDepthAndHdr; + + Texture m_MotionVectorsDepthMap; + DSV m_MotionVectorsDepthMapDSV; + CBV_SRV_UAV m_MotionVectorsDepthMapSRV; + + // shadowmaps + typedef struct { + Texture ShadowMap; + uint32_t ShadowIndex; + uint32_t ShadowResolution; + uint32_t LightIndex; + } SceneShadowInfo; + std::vector m_shadowMapPool; + DSV m_ShadowMapPoolDSV; + CBV_SRV_UAV m_ShadowMapPoolSRV; + + // widgets + Wireframe m_wireframe; + WireframeBox m_wireframeBox; + + std::vector m_TimeStamps; + + // screen shot + std::string m_ScreenShotName; + SaveTexture m_saveTexture; + AsyncPool m_asyncPool; + + FlipBookAnimation m_CampfireAnimation; + TestImages m_testImages; + ExposureMultiplierCS m_exposureMultiplierCS; + LPMPS m_lpmPS; +}; + diff --git a/sample/src/DX12/SampleRenderer.cpp b/sample/src/DX12/SampleRenderer.cpp deleted file mode 100644 index 85d66f5..0000000 --- a/sample/src/DX12/SampleRenderer.cpp +++ /dev/null @@ -1,592 +0,0 @@ -// AMD LPMSample sample code -// -// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "stdafx.h" - -#include "SampleRenderer.h" - -//-------------------------------------------------------------------------------------- -// -// OnCreate -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnCreate(Device* pDevice, SwapChain *pSwapChain) -{ - m_pDevice = pDevice; - - // Initialize helpers - - // Create all the heaps for the resources views - const uint32_t cbvDescriptorCount = 2000; - const uint32_t srvDescriptorCount = 2000; - const uint32_t uavDescriptorCount = 10; - const uint32_t dsvDescriptorCount = 3; - const uint32_t rtvDescriptorCount = 60; - const uint32_t samplerDescriptorCount = 20; - m_resourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, dsvDescriptorCount, rtvDescriptorCount, samplerDescriptorCount); - - // Create a commandlist ring for the Direct queue - // We are queuing (backBufferCount + 0.5) frames, so we need to triple buffer the command lists - uint32_t commandListsPerBackBuffer = 8; - m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer, pDevice->GetGraphicsQueue()->GetDesc()); - - // Create a 'dynamic' constant buffer - const uint32_t constantBuffersMemSize = 20 * 1024 * 1024; - m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, &m_resourceViewHeaps); - - // Create a 'static' pool for vertices, indices and constant buffers - const uint32_t staticGeometryMemSize = 128 * 1024 * 1024; - m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, USE_VID_MEM, "StaticGeom"); - - // initialize the GPU time stamps module - m_GPUTimer.OnCreate(pDevice, backBufferCount); - - // Quick helper to upload resources, it has it's own commandList and uses suballocation. - // for 4K textures we'll need 100Megs - const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024; - m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results) - - // Create the depth buffer view - m_resourceViewHeaps.AllocDSVDescriptor(1, &m_DepthBufferDSV); - - // Create a Shadowmap atlas to hold 4 cascades/spotlights - m_shadowMap.InitDepthStencil(pDevice, "m_pShadowMap", &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_TYPELESS, 2 * 1024, 2 * 1024, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL)); - m_resourceViewHeaps.AllocDSVDescriptor(1, &m_ShadowMapDSV); - m_shadowMap.CreateDSV(0, &m_ShadowMapDSV); - m_resourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_ShadowMapSRV); - m_shadowMap.CreateSRV(0, &m_ShadowMapSRV); - - XMMATRIX campfireWorldMatrix = XMMATRIX(0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.5f, 0.0f, - -47.3f, -26.5f, -40.425f, 1.0f); - m_CampfireAnimation.OnCreate(pDevice, &m_UploadHeap, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, 4, DXGI_FORMAT_R16G16B16A16_FLOAT, 12, 12, "..\\media\\FlipBookAnimationTextures\\cf_loop_comp_v1_mosaic.png", campfireWorldMatrix); - - m_downSample.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); - m_bloom.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, DXGI_FORMAT_R16G16B16A16_FLOAT); - - m_testImages.OnCreate(pDevice, &m_UploadHeap, &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing, DXGI_FORMAT_R16G16B16A16_FLOAT); - - // Create tonemapping pass - m_exposureMultiplierCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); - m_lpmPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); - m_toneMappingPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); - m_toneMappingCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); - m_colorConversionPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, pSwapChain->GetFormat()); - - // Initialize UI rendering resources - m_ImGUI.OnCreate(pDevice, &m_UploadHeap, &m_resourceViewHeaps, &m_ConstantBufferRing, DXGI_FORMAT_R16G16B16A16_FLOAT); - - m_resourceViewHeaps.AllocRTVDescriptor(1, &m_HDRRTV); - m_resourceViewHeaps.AllocRTVDescriptor(1, &m_HDRRTVMSAA); - - m_resourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_HDRSRV); - m_resourceViewHeaps.AllocCBV_SRV_UAVDescriptor(1, &m_HDRUAV); - - // Make sure upload heap has finished uploading before continuing -#if (USE_VID_MEM==true) - m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); - m_UploadHeap.FlushAndFinish(); -#endif -} - -//-------------------------------------------------------------------------------------- -// -// OnDestroy -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnDestroy() -{ - m_colorConversionPS.OnDestroy(); - m_toneMappingCS.OnDestroy(); - m_toneMappingPS.OnDestroy(); - m_exposureMultiplierCS.OnDestroy(); - m_lpmPS.OnDestroy(); - m_ImGUI.OnDestroy(); - m_testImages.OnDestroy(); - m_bloom.OnDestroy(); - m_downSample.OnDestroy(); - m_CampfireAnimation.OnDestroy(); - m_shadowMap.OnDestroy(); - - m_UploadHeap.OnDestroy(); - m_GPUTimer.OnDestroy(); - m_VidMemBufferPool.OnDestroy(); - m_ConstantBufferRing.OnDestroy(); - m_resourceViewHeaps.OnDestroy(); - m_CommandListRing.OnDestroy(); -} - -//-------------------------------------------------------------------------------------- -// -// OnCreateWindowSizeDependentResources -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height, State *pState) -{ - m_Width = Width; - m_Height = Height; - - // Set the viewport - // - m_ViewPort = { 0.0f, 0.0f, static_cast(Width), static_cast(Height), 0.0f, 1.0f }; - - // Create scissor rectangle - // - m_RectScissor = { 0, 0, (LONG)Width, (LONG)Height }; - - // Create depth buffer - // - m_depthBuffer.InitDepthStencil(m_pDevice, "depthbuffer", &CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R32_TYPELESS, Width, Height, 1, 1, 4, 0, D3D12_RESOURCE_FLAG_ALLOW_DEPTH_STENCIL | D3D12_RESOURCE_FLAG_DENY_SHADER_RESOURCE)); - m_depthBuffer.CreateDSV(0, &m_DepthBufferDSV); - - // Create Texture + RTV with x4 MSAA - // - CD3DX12_RESOURCE_DESC RDescMSAA = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R16G16B16A16_FLOAT, Width, Height, 1, 1, 4, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET); - m_HDRMSAA.InitRenderTarget(m_pDevice, "HDRMSAA", &RDescMSAA, D3D12_RESOURCE_STATE_RENDER_TARGET); - m_HDRMSAA.CreateRTV(0, &m_HDRRTVMSAA); - - // Create Texture + RTV, to hold the resolved scene - // - CD3DX12_RESOURCE_DESC RDesc = CD3DX12_RESOURCE_DESC::Tex2D(DXGI_FORMAT_R16G16B16A16_FLOAT, Width, Height, 1, 1, 1, 0, D3D12_RESOURCE_FLAG_ALLOW_RENDER_TARGET | D3D12_RESOURCE_FLAG_ALLOW_UNORDERED_ACCESS); - m_HDR.InitRenderTarget(m_pDevice, "HDR", &RDesc, D3D12_RESOURCE_STATE_RENDER_TARGET); - m_HDR.CreateSRV(0, &m_HDRSRV); - m_HDR.CreateUAV(0, &m_HDRUAV); - m_HDR.CreateRTV(0, &m_HDRRTV); - - // update bloom and downscaling effect - // - { - m_downSample.OnCreateWindowSizeDependentResources(m_Width, m_Height, &m_HDR, 6); //downsample the HDR texture 6 times - m_bloom.OnCreateWindowSizeDependentResources(m_Width / 2, m_Height / 2, m_downSample.GetTexture(), 6, &m_HDR); - } - - // update the pipelines if the swapchain render pass has changed (for example when the format of the swapchain changes) - // - m_colorConversionPS.UpdatePipelines(pSwapChain->GetFormat(), pSwapChain->GetDisplayMode()); - m_toneMappingPS.UpdatePipelines(pSwapChain->GetFormat()); - m_lpmPS.UpdatePipeline(pSwapChain->GetFormat(), pSwapChain->GetDisplayMode(), pState->colorSpace); -} - -//-------------------------------------------------------------------------------------- -// -// OnDestroyWindowSizeDependentResources -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnDestroyWindowSizeDependentResources() -{ - m_bloom.OnDestroyWindowSizeDependentResources(); - m_downSample.OnDestroyWindowSizeDependentResources(); - - m_HDR.OnDestroy(); - m_HDRMSAA.OnDestroy(); - m_depthBuffer.OnDestroy(); -} - -//-------------------------------------------------------------------------------------- -// -// LoadScene -// -//-------------------------------------------------------------------------------------- -int SampleRenderer::LoadScene(GLTFCommon *pGLTFCommon, int stage) -{ - // show loading progress - // - ImGui::OpenPopup("Loading"); - if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize)) - { - float progress = (float)stage / 10.0f; - ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL); - ImGui::EndPopup(); - } - - // Loading stages - // - if (stage == 0) - { - } - else if (stage == 5) - { - Profile p("m_pGltfLoader->Load"); - - m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers(); - m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing); - } - else if (stage == 6) - { - Profile p("LoadTextures"); - - // here we are loading onto the GPU all the textures and the inverse matrices - // this data will be used to create the PBR and Depth passes - m_pGLTFTexturesAndBuffers->LoadTextures(); - } - else if (stage == 7) - { - Profile p("m_gltfDepth->OnCreate"); - //create the glTF's textures, VBs, IBs, shaders and descriptors - m_gltfDepth = new GltfDepthPass(); - m_gltfDepth->OnCreate( - m_pDevice, - &m_UploadHeap, - &m_resourceViewHeaps, - &m_ConstantBufferRing, - &m_VidMemBufferPool, - m_pGLTFTexturesAndBuffers - ); - } - else if (stage == 8) - { - Profile p("m_gltfPBR->OnCreate"); - m_gltfPBR = new GltfPbrPass(); - m_gltfPBR->OnCreate( - m_pDevice, - &m_UploadHeap, - &m_resourceViewHeaps, - &m_ConstantBufferRing, - &m_VidMemBufferPool, - m_pGLTFTexturesAndBuffers, - nullptr, - false, - USE_SHADOWMASK, - m_HDRMSAA.GetFormat(), // forward pass channel - DXGI_FORMAT_UNKNOWN, // specular-roughness channel - DXGI_FORMAT_UNKNOWN, // diffuse channel - DXGI_FORMAT_UNKNOWN, // normal channel - 4 - ); -#if (USE_VID_MEM==true) - // we are borrowing the upload heap command list for uploading to the GPU the IBs and VBs - m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); -#endif - } - else if (stage == 10) - { - Profile p("Flush"); - m_UploadHeap.FlushAndFinish(); - -#if (USE_VID_MEM==true) - //once everything is uploaded we dont need he upload heaps anymore - m_VidMemBufferPool.FreeUploadHeap(); -#endif - - // tell caller that we are done loading the map - return -1; - } - - stage++; - return stage; -} - -//-------------------------------------------------------------------------------------- -// -// UnloadScene -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::UnloadScene() -{ - if (m_gltfPBR) - { - m_gltfPBR->OnDestroy(); - delete m_gltfPBR; - m_gltfPBR = NULL; - } - - if (m_gltfDepth) - { - m_gltfDepth->OnDestroy(); - delete m_gltfDepth; - m_gltfDepth = NULL; - } - - if (m_pGLTFTexturesAndBuffers) - { - m_pGLTFTexturesAndBuffers->OnDestroy(); - delete m_pGLTFTexturesAndBuffers; - m_pGLTFTexturesAndBuffers = NULL; - } - -} - -//-------------------------------------------------------------------------------------- -// -// OnRender -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnRender(State *pState, SwapChain *pSwapChain) -{ - // Timing values - // - UINT64 gpuTicksPerSecond; - m_pDevice->GetGraphicsQueue()->GetTimestampFrequency(&gpuTicksPerSecond); - - // Let our resource managers do some house keeping - // - m_ConstantBufferRing.OnBeginFrame(); - m_GPUTimer.OnBeginFrame(gpuTicksPerSecond, &m_TimeStamps); - - per_frame *pPerFrame = NULL; - if (m_pGLTFTexturesAndBuffers) - { - pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(pState->camera); - - //override gltf camera with ours - pPerFrame->mCameraViewProj = pState->camera.GetView() * pState->camera.GetProjection(); - pPerFrame->cameraPos = pState->camera.GetPosition(); - pPerFrame->emmisiveFactor = pState->emmisiveFactor; - - pPerFrame->lights[0].intensity = pState->lightIntensity; - - // Up to 4 spotlights can have shadowmaps. Each spot the light has a shadowMap index which is used to find the sadowmap in the atlas - uint32_t shadowMapIndex = 0; - for (uint32_t i = 0; i < pPerFrame->lightCount; i++) - { - if ((shadowMapIndex < 4) && (pPerFrame->lights[i].type == LightType_Spot)) - { - pPerFrame->lights[i].shadowMapIndex = shadowMapIndex++; //set the shadowmap index so the color pass knows which shadow map to use - pPerFrame->lights[i].depthBias = 70.0f / 100000.0f; - } - } - - m_pGLTFTexturesAndBuffers->SetPerFrameConstants(); - - m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons(); - } - - // command buffer calls - // - ID3D12GraphicsCommandList* pCmdLst1 = m_CommandListRing.GetNewCommandList(); - - m_GPUTimer.GetTimeStamp(pCmdLst1, "Begin Frame"); - - // Clear GBuffer and depth stencil - // - pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_PRESENT, D3D12_RESOURCE_STATE_RENDER_TARGET)); - - // Clears ----------------------------------------------------------------------- - // - pCmdLst1->ClearDepthStencilView(m_ShadowMapDSV.GetCPU(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); - m_GPUTimer.GetTimeStamp(pCmdLst1, "Clear Shadow Map"); - - float clearColor[] = { 0.0f, 0.0f, 0.0f, 0.0f }; - pCmdLst1->ClearRenderTargetView(m_HDRRTVMSAA.GetCPU(), clearColor, 0, nullptr); - m_GPUTimer.GetTimeStamp(pCmdLst1, "Clear HDR"); - - pCmdLst1->ClearDepthStencilView(m_DepthBufferDSV.GetCPU(), D3D12_CLEAR_FLAG_DEPTH, 1.0f, 0, 0, nullptr); - m_GPUTimer.GetTimeStamp(pCmdLst1, "Clear Depth"); - - // Render to shadow map atlas --------------------------------------------------- - // - if (m_gltfDepth && pPerFrame != NULL) - { - uint32_t shadowMapIndex = 0; - for (uint32_t i = 0; i < pPerFrame->lightCount; i++) - { - if (pPerFrame->lights[i].type != LightType_Spot) - continue; - - // Set the RT's quadrant where to render the shadomap (these viewport offsets need to match the ones in shadowFiltering.h) - uint32_t viewportOffsetsX[4] = { 0, 1, 0, 1 }; - uint32_t viewportOffsetsY[4] = { 0, 0, 1, 1 }; - uint32_t viewportWidth = m_shadowMap.GetWidth() / 2; - uint32_t viewportHeight = m_shadowMap.GetHeight() / 2; - SetViewportAndScissor(pCmdLst1, viewportOffsetsX[i] * viewportWidth, viewportOffsetsY[i] * viewportHeight, viewportWidth, viewportHeight); - pCmdLst1->OMSetRenderTargets(0, NULL, true, &m_ShadowMapDSV.GetCPU()); - - GltfDepthPass::per_frame *cbDepthPerFrame = m_gltfDepth->SetPerFrameConstants(); - cbDepthPerFrame->mViewProj = pPerFrame->lights[i].mLightViewProj; - - m_gltfDepth->Draw(pCmdLst1); - - m_GPUTimer.GetTimeStamp(pCmdLst1, "Shadow map"); - shadowMapIndex++; - } - } - pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowMap.GetResource(), D3D12_RESOURCE_STATE_DEPTH_WRITE, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE)); - - // Render Scene to the MSAA HDR RT ------------------------------------------------ - // - pCmdLst1->RSSetViewports(1, &m_ViewPort); - pCmdLst1->RSSetScissorRects(1, &m_RectScissor); - pCmdLst1->OMSetRenderTargets(1, &m_HDRRTVMSAA.GetCPU(), true, &m_DepthBufferDSV.GetCPU()); - - if (pPerFrame != NULL) - { - // Render scene to color buffer - // - if (m_gltfPBR && pPerFrame != NULL) - { - //set per frame constant buffer values - m_gltfPBR->Draw(pCmdLst1, &m_ShadowMapSRV); - m_CampfireAnimation.Draw(pCmdLst1, pState->time, pState->camera.GetPosition(), pState->camera.GetView() * pState->camera.GetProjection()); - } - } - pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_shadowMap.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_DEPTH_WRITE)); - - m_GPUTimer.GetTimeStamp(pCmdLst1, "Rendering Scene"); - - // Resolve MSAA ------------------------------------------------------------------------ - // - { - UserMarker marker(pCmdLst1, "Resolving MSAA"); - - D3D12_RESOURCE_BARRIER preResolve[2] = { - CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_DEST), - CD3DX12_RESOURCE_BARRIER::Transition(m_HDRMSAA.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_RESOLVE_SOURCE) - }; - pCmdLst1->ResourceBarrier(2, preResolve); - - pCmdLst1->ResolveSubresource(m_HDR.GetResource(), 0, m_HDRMSAA.GetResource(), 0, DXGI_FORMAT_R16G16B16A16_FLOAT); - - D3D12_RESOURCE_BARRIER postResolve[2] = { - CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_RESOLVE_DEST, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE), - CD3DX12_RESOURCE_BARRIER::Transition(m_HDRMSAA.GetResource(), D3D12_RESOURCE_STATE_RESOLVE_SOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET) - }; - pCmdLst1->ResourceBarrier(2, postResolve); - - m_GPUTimer.GetTimeStamp(pCmdLst1, "Resolve MSAA"); - } - - // Post proc--------------------------------------------------------------------------- - // - { - m_downSample.Draw(pCmdLst1); - //m_downSample.Gui(); - m_GPUTimer.GetTimeStamp(pCmdLst1, "Downsample"); - - m_bloom.Draw(pCmdLst1, &m_HDR); - //m_bloom.Gui(); - m_GPUTimer.GetTimeStamp(pCmdLst1, "Bloom"); - } - - // Render TestPattern ------------------------------------------------------------------------ - // - { - pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); - if (pState->testPattern) - { - pCmdLst1->RSSetViewports(1, &m_ViewPort); - pCmdLst1->RSSetScissorRects(1, &m_RectScissor); - pCmdLst1->OMSetRenderTargets(1, &m_HDRRTV.GetCPU(), true, NULL); - - m_testImages.Draw(pCmdLst1, pState->testPattern); - m_GPUTimer.GetTimeStamp(pCmdLst1, "Test Pattern Rendering"); - } - } - - // Apply Exposure ------------------------------------------------------------------------ - // - { - pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_UNORDERED_ACCESS)); - - m_exposureMultiplierCS.Draw(pCmdLst1, &m_HDRUAV, pState->exposure, m_Width, m_Height); - - pCmdLst1->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_RENDER_TARGET)); - - m_GPUTimer.GetTimeStamp(pCmdLst1, "Apply Exposure"); - } - - // Render HUD ------------------------------------------------------------------------ - // - { - pCmdLst1->RSSetViewports(1, &m_ViewPort); - pCmdLst1->RSSetScissorRects(1, &m_RectScissor); - pCmdLst1->OMSetRenderTargets(1, &m_HDRRTV.GetCPU(), true, NULL); - - m_ImGUI.Draw(pCmdLst1); - - m_GPUTimer.GetTimeStamp(pCmdLst1, "ImGUI Rendering"); - - D3D12_RESOURCE_BARRIER hdrToSRV = CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - pCmdLst1->ResourceBarrier(1, &hdrToSRV); - } - - // If using FreeSync2 we need to to the tonemapping in-place and then later we'll apply the color conversion into the swapchain - // We need to skip this step if using LPM tonemapper that does the color conversion along with tone and gamut mapping - if (pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR && pState->toneMapper < 6) - { - D3D12_RESOURCE_BARRIER hdrToUAV = CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_UNORDERED_ACCESS); - pCmdLst1->ResourceBarrier(1, &hdrToUAV); - - m_toneMappingCS.Draw(pCmdLst1, &m_HDRUAV, pState->unusedExposure, pState->toneMapper, m_Width, m_Height); - - D3D12_RESOURCE_BARRIER hdrToSRV = CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_UNORDERED_ACCESS, D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE); - pCmdLst1->ResourceBarrier(1, &hdrToSRV); - - m_GPUTimer.GetTimeStamp(pCmdLst1, "Tone mapping"); - } - - // submit command buffer - ThrowIfFailed(pCmdLst1->Close()); - ID3D12CommandList* CmdListList1[] = { pCmdLst1 }; - m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList1); - - // Wait for swapchain (we are going to render to it) ----------------------------------- - // - pSwapChain->WaitForSwapChain(); - - m_CommandListRing.OnBeginFrame(); - - ID3D12GraphicsCommandList* pCmdLst2 = m_CommandListRing.GetNewCommandList(); - - pCmdLst2->RSSetViewports(1, &m_ViewPort); - pCmdLst2->RSSetScissorRects(1, &m_RectScissor); - pCmdLst2->OMSetRenderTargets(1, pSwapChain->GetCurrentBackBufferRTV(), true, NULL); - - // Tonemapping LPM ------------------------------------------------------------------------ - // - if (pState->toneMapper == 6) - { - m_lpmPS.Draw(pCmdLst2, &m_HDRSRV); - m_GPUTimer.GetTimeStamp(pCmdLst2, "Tone mapping LPM"); - } - else - { - if (pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR) - { - // FS2 mode! Apply color conversion now. - // - m_colorConversionPS.Draw(pCmdLst2, &m_HDRSRV); - } - else - { - // non FS2 mode, that is SDR, here we apply the tonemapping from the HDR into the swapchain - // - // Tonemapping ------------------------------------------------------------------------ - // - m_toneMappingPS.Draw(pCmdLst2, &m_HDRSRV, pState->unusedExposure, pState->toneMapper); - m_GPUTimer.GetTimeStamp(pCmdLst2, "Tone mapping"); - } - } - - pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(m_HDR.GetResource(), D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE, D3D12_RESOURCE_STATE_RENDER_TARGET)); - - // Transition swapchain into present mode - pCmdLst2->ResourceBarrier(1, &CD3DX12_RESOURCE_BARRIER::Transition(pSwapChain->GetCurrentBackBufferResource(), D3D12_RESOURCE_STATE_RENDER_TARGET, D3D12_RESOURCE_STATE_PRESENT)); - - m_GPUTimer.OnEndFrame(); - - m_GPUTimer.CollectTimings(pCmdLst2); - - // Close & Submit the command list ---------------------------------------------------- - // - ThrowIfFailed(pCmdLst2->Close()); - - ID3D12CommandList* CmdListList2[] = { pCmdLst2 }; - m_pDevice->GetGraphicsQueue()->ExecuteCommandLists(1, CmdListList2); -} diff --git a/sample/src/DX12/SampleRenderer.h b/sample/src/DX12/SampleRenderer.h deleted file mode 100644 index ded49c1..0000000 --- a/sample/src/DX12/SampleRenderer.h +++ /dev/null @@ -1,123 +0,0 @@ -// AMD LPMSample sample code -// -// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -#pragma once - -static const int backBufferCount = 3; - -#define USE_VID_MEM true -#define USE_SHADOWMASK false - -using namespace CAULDRON_DX12; - -// -// This class deals with the GPU side of the sample. -// -class SampleRenderer -{ -public: - - struct State - { - float time; - Camera camera; - - float exposure; - float unusedExposure; - float emmisiveFactor; - - int testPattern; - ColorSpace colorSpace; - int toneMapper; - float lightIntensity; - }; - - void OnCreate(Device* pDevice, SwapChain *pSwapChain); - void OnDestroy(); - - void OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height, State *pState); - void OnDestroyWindowSizeDependentResources(); - - int LoadScene(GLTFCommon *pGLTFCommon, int stage = 0); - void UnloadScene(); - - const std::vector &GetTimingValues() { return m_TimeStamps; } - - void OnRender(State *pState, SwapChain *pSwapChain); - -private: - Device *m_pDevice; - - uint32_t m_Width; - uint32_t m_Height; - - D3D12_VIEWPORT m_ViewPort; - D3D12_RECT m_RectScissor; - - // Initialize helper classes - ResourceViewHeaps m_resourceViewHeaps; - UploadHeap m_UploadHeap; - DynamicBufferRing m_ConstantBufferRing; - StaticBufferPool m_VidMemBufferPool; - CommandListRing m_CommandListRing; - GPUTimestamps m_GPUTimer; - - //gltf passes - GLTFTexturesAndBuffers *m_pGLTFTexturesAndBuffers; - GltfPbrPass *m_gltfPBR; - GltfDepthPass *m_gltfDepth; - - FlipBookAnimation m_CampfireAnimation; - - // effects - Bloom m_bloom; - DownSamplePS m_downSample; - TestImages m_testImages; - ExposureMultiplierCS m_exposureMultiplierCS; - ToneMapping m_toneMappingPS; - ToneMappingCS m_toneMappingCS; - ColorConversionPS m_colorConversionPS; - LPMPS m_lpmPS; - - // GUI - ImGUI m_ImGUI; - - // Temporary render targets - - // depth buffer - Texture m_depthBuffer; - DSV m_DepthBufferDSV; - - // shadowmap - Texture m_shadowMap; - CBV_SRV_UAV m_ShadowMapSRV; - DSV m_ShadowMapDSV; - - // MSAA RT - Texture m_HDRMSAA; - RTV m_HDRRTVMSAA; - - // Resolved RT - Texture m_HDR; - CBV_SRV_UAV m_HDRSRV; - CBV_SRV_UAV m_HDRUAV; - RTV m_HDRRTV; - - std::vector m_TimeStamps; -}; - diff --git a/sample/src/DX12/TestImages.cpp b/sample/src/DX12/TestImages.cpp index 72b4657..d9cb378 100644 --- a/sample/src/DX12/TestImages.cpp +++ b/sample/src/DX12/TestImages.cpp @@ -41,35 +41,41 @@ namespace CAULDRON_DX12 SamplerDesc.RegisterSpace = 0; SamplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - for (int i = 0; i < NUM_TEXTURES; ++i) + static const char* s_TextureNameList[_countof(m_testImagesData)] = { + "..\\media\\color_ramp_bt2020_dcip3\\LuxoDoubleChecker_EXR_ARGB_16F_1.DDS", + "..\\media\\color_ramp_bt2020_dcip3\\dcip3_1000_EXR_ARGB_16F_1.DDS", + "..\\media\\color_ramp_bt2020_dcip3\\bt2020_1000_EXR_ARGB_16F_1.DDS" + }; + + for (int i = 0; i < _countof(m_testImagesData); ++i) { - m_testImageTexture[i].InitFromFile(pDevice, pUploadHeap, m_TextureNameList[i].c_str(), false); + m_testImagesData[i].m_testImageTexture.InitFromFile(pDevice, pUploadHeap, s_TextureNameList[i], false); pUploadHeap->FlushAndFinish(); - pResourceViewHeaps->AllocCBV_SRV_UAVDescriptor(1, &m_testImageTextureSRV[i]); - m_testImageTexture[i].CreateSRV(0, &m_testImageTextureSRV[i]); + pResourceViewHeaps->AllocCBV_SRV_UAVDescriptor(1, &m_testImagesData[i].m_testImageTextureSRV); + m_testImagesData[i].m_testImageTexture.CreateSRV(0, &m_testImagesData[i].m_testImageTextureSRV); } m_testImagePS.OnCreate(pDevice, "TestImagesPS.hlsl", pResourceViewHeaps, pStaticBufferPool, 1, 1, &SamplerDesc, outFormat); - } + } void TestImages::OnDestroy() { - for (int i = 0; i < NUM_TEXTURES; ++i) + for (int i = 0; i < _countof(m_testImagesData); ++i) { - m_testImageTexture[i].OnDestroy(); + m_testImagesData[i].m_testImageTexture.OnDestroy(); } m_testImagePS.OnDestroy(); } void TestImages::Draw(ID3D12GraphicsCommandList* pCommandList, int testPattern) - { + { D3D12_GPU_VIRTUAL_ADDRESS cbTestImagesHandle; TestImagesConsts *pTestImagesConsts; m_pDynamicBufferRing->AllocConstantBuffer(sizeof(TestImagesConsts), (void **)&pTestImagesConsts, &cbTestImagesHandle); pTestImagesConsts->testPattern = testPattern - 1; - m_testImagePS.Draw(pCommandList, 1, &m_testImageTextureSRV[pTestImagesConsts->testPattern % NUM_TEXTURES], cbTestImagesHandle); + m_testImagePS.Draw(pCommandList, 1, &m_testImagesData[pTestImagesConsts->testPattern % _countof(m_testImagesData)].m_testImageTextureSRV, cbTestImagesHandle); } } diff --git a/sample/src/DX12/TestImages.h b/sample/src/DX12/TestImages.h index 88ab1df..4533f29 100644 --- a/sample/src/DX12/TestImages.h +++ b/sample/src/DX12/TestImages.h @@ -21,8 +21,6 @@ #include "PostProc\PostProcPS.h" -#define NUM_TEXTURES 3 - namespace CAULDRON_DX12 { class TestImages @@ -33,20 +31,19 @@ namespace CAULDRON_DX12 void Draw(ID3D12GraphicsCommandList* pCommandList, int testPattern); private: + + struct TestImagesData { + CBV_SRV_UAV m_testImageTextureSRV; + Texture m_testImageTexture; + }; + DynamicBufferRing *m_pDynamicBufferRing = NULL; - CBV_SRV_UAV m_testImageTextureSRV[NUM_TEXTURES]; - Texture m_testImageTexture[NUM_TEXTURES]; + TestImagesData m_testImagesData[3]; PostProcPS m_testImagePS; struct TestImagesConsts { int testPattern; }; - - std::vector m_TextureNameList = { - "..\\media\\color_ramp_bt2020_dcip3\\LuxoDoubleChecker_EXR_ARGB_16F_1.DDS", - "..\\media\\color_ramp_bt2020_dcip3\\dcip3_1000_EXR_ARGB_16F_1.DDS", - "..\\media\\color_ramp_bt2020_dcip3\\bt2020_1000_EXR_ARGB_16F_1.DDS" - }; }; } \ No newline at end of file diff --git a/sample/src/DX12/UI.cpp b/sample/src/DX12/UI.cpp new file mode 100644 index 0000000..49b63cf --- /dev/null +++ b/sample/src/DX12/UI.cpp @@ -0,0 +1,498 @@ +// AMD SampleDX12 sample code +// +// Copyright(c) 2020 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "UI.h" +#include "LPMSample.h" +#include "imgui.h" +#include "base/FrameworkWindows.h" + +// To use the 'disabled UI state' functionality (ImGuiItemFlags_Disabled), include internal header +// https://github.com/ocornut/imgui/issues/211#issuecomment-339241929 +#include "imgui_internal.h" +static void DisableUIStateBegin(const bool& bEnable) +{ + if (!bEnable) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } +}; +static void DisableUIStateEnd(const bool& bEnable) +{ + if (!bEnable) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } +}; + +// Some constants and utility functions +static constexpr float MAGNIFICATION_AMOUNT_MIN = 1.0f; +static constexpr float MAGNIFICATION_AMOUNT_MAX = 32.0f; +static constexpr float MAGNIFIER_RADIUS_MIN = 0.01f; +static constexpr float MAGNIFIER_RADIUS_MAX = 0.85f; +static constexpr float MAGNIFIER_BORDER_COLOR__LOCKED[3] = { 0.002f, 0.72f, 0.0f }; // G +static constexpr float MAGNIFIER_BORDER_COLOR__FREE [3] = { 0.72f, 0.002f, 0.0f }; // R +template static T clamped(const T& v, const T& min, const T& max) +{ + if (v < min) return min; + else if (v > max) return max; + else return v; +} + + +static bool bSceneChanged = false; + +void LPMSample::BuildUI() +{ + // if we haven't initialized GLTFLoader yet, don't draw UI. + if (m_pGltfLoader == nullptr) + { + LoadScene(0); + bSceneChanged = true; + return; + } + + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + style.FrameBorderSize = 1.0f; + + const uint32_t W = this->GetWidth(); + const uint32_t H = this->GetHeight(); + + const uint32_t PROFILER_WINDOW_PADDIG_X = 10; + const uint32_t PROFILER_WINDOW_PADDIG_Y = 10; + const uint32_t PROFILER_WINDOW_SIZE_X = 330; + const uint32_t PROFILER_WINDOW_SIZE_Y = 450; + const uint32_t PROFILER_WINDOW_POS_X = W - PROFILER_WINDOW_PADDIG_X - PROFILER_WINDOW_SIZE_X; + const uint32_t PROFILER_WINDOW_POS_Y = PROFILER_WINDOW_PADDIG_Y; + + const uint32_t CONTROLS_WINDOW_POS_X = 10; + const uint32_t CONTROLS_WINDOW_POS_Y = 10; + const uint32_t CONTROLW_WINDOW_SIZE_X = 350; + const uint32_t CONTROLW_WINDOW_SIZE_Y = 780; // assuming > 720p + + // Render CONTROLS window + // + ImGui::SetNextWindowPos(ImVec2(CONTROLS_WINDOW_POS_X, CONTROLS_WINDOW_POS_Y), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(CONTROLW_WINDOW_SIZE_X, CONTROLW_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); + + if (m_UIState.bShowControlsWindow) + { + ImGui::Begin("CONTROLS (F1)", &m_UIState.bShowControlsWindow); + + if (m_activeScene == 0) + { + if (ImGui::CollapsingHeader("Animation", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Checkbox("Play", &m_bPlay); + } + + ImGui::Spacing(); + ImGui::Spacing(); + } + + if (ImGui::CollapsingHeader("Scene", ImGuiTreeNodeFlags_DefaultOpen)) + { + auto getterLambda = [](void* data, int idx, const char** out_str)->bool { *out_str = ((std::vector *)data)->at(idx).c_str(); return true; }; + bSceneChanged |= ImGui::Combo("Model", &m_activeScene, getterLambda, &m_sceneNames, (int)m_sceneNames.size()); + if (bSceneChanged) + { + m_UIState.TestPattern = m_activeScene; + switch (m_activeScene) + { + // Campfire + case 0: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 0.0f; + m_UIState.HdrMax = 8.0f; + m_UIState.LpmExposure = 3.0f; + m_UIState.Contrast = 0.3f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC709; + break; + } + // Lamp + case 1: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 0.0f; + m_UIState.HdrMax = 1024.0f; + m_UIState.LpmExposure = 10.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f; m_UIState.Crosstalk[2] = 1.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC709; + break; + } + // P3 1000 nits + case 2: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 1.0f / 16.0f; + m_UIState.HdrMax = 16.0f; + m_UIState.LpmExposure = 4.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_P3; + break; + } + // Rec2020 1000 nits + case 3: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 1.0f / 32.0f; + m_UIState.HdrMax = 16.0f; + m_UIState.LpmExposure = 4.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC2020; + break; + } + // Rec709 5000 nits + case 4: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 0.0f; + m_UIState.HdrMax = 64.0f; + m_UIState.LpmExposure = 6.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC709; + break; + } + } + + bSceneChanged = false; + + m_device.GPUFlush(); + OnUpdateDisplay(); + } + + if (m_activeScene == 0) + { + char* cameraControl[] = { "Orbit", "WASD" }; + ImGui::Combo("Camera", &m_activeCamera, cameraControl, _countof(cameraControl)); + + ImGui::SliderFloat("Emissive Intensity", &m_UIState.EmissiveFactor, 1.0f, 2.0f, NULL, 1.0f); + + for (int i = 0; i < m_pGltfLoader->m_lights.size(); i++) + { + ImGui::SliderFloat(format("Light %i Intensity", i).c_str(), &m_pGltfLoader->m_lights[i].m_intensity, 0.0f, 20.0f); + } + } + } + + ImGui::Spacing(); + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("PostProcessing", ImGuiTreeNodeFlags_DefaultOpen)) + { + const char* tonemappers[] = { "FidelityFX LPM", "AMD Tonemapper", "DX11DSK", "Reinhard", "Uncharted2Tonemap", "ACES", "No tonemapper" }; + ImGui::Combo("Tonemapper", &m_UIState.SelectedTonemapperIndex, tonemappers, _countof(tonemappers)); + + static float exposureStep = 0.0f; + ImGui::SliderFloat("Exposure", &exposureStep, -4.0f, +1.0f, NULL, 1.0f); + m_UIState.Exposure = (float)pow(2, exposureStep); + } + + ImGui::Spacing(); + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("FreeSync HDR", ImGuiTreeNodeFlags_DefaultOpen)) + { + const char* fullscreenModes[] = { "Windowed", "BorderlessFullscreen", "ExclusiveFulscreen" }; + if (ImGui::Combo("Fullscreen Mode", (int*)&m_fullscreenMode, fullscreenModes, _countof(fullscreenModes))) + { + if (m_previousFullscreenMode != m_fullscreenMode) + { + HandleFullScreen(); + m_previousFullscreenMode = m_fullscreenMode; + } + } + + static bool openWarning = false; + const char** displayModeNames = &m_displayModesNamesAvailable[0]; + if (ImGui::Combo("Display Mode", (int*)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) + { + if (m_fullscreenMode != PRESENTATIONMODE_WINDOWED) + { + UpdateDisplay(m_displayModesAvailable[m_currentDisplayModeNamesIndex], m_disableLocalDimming); + m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; + } + else if (CheckIfWindowModeHdrOn() && + (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_SDR || + m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_2084 || + m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_SCRGB)) + { + UpdateDisplay(m_displayModesAvailable[m_currentDisplayModeNamesIndex], m_disableLocalDimming); + m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; + } + else + { + openWarning = true; + m_currentDisplayModeNamesIndex = m_previousDisplayModeNamesIndex; + } + } + + if (openWarning) + { + ImGui::OpenPopup("Display Modes Warning"); + ImGui::BeginPopupModal("Display Modes Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize); + 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"); + if (ImGui::Button("Cancel", ImVec2(120, 0))) { openWarning = false; ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); + } + + if (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_Gamma22 || + m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_SCRGB) + { + static bool selectedDisableLocaldimmingSetting = false; + if (ImGui::Checkbox("Disable Local Dimming", &selectedDisableLocaldimmingSetting)) + UpdateDisplay(m_displayModesAvailable[m_currentDisplayModeNamesIndex], selectedDisableLocaldimmingSetting); + } + } + + ImGui::Spacing(); + ImGui::Spacing(); + + #define LPM_CONFIG 0 + #if LPM_CONFIG + if (m_UIState.SelectedTonemapperIndex == 0) + { + ImGui::Spacing(); + ImGui::Spacing(); + static bool bLPMConfigChanged = false; + if (ImGui::CollapsingHeader("LPM Config", ImGuiTreeNodeFlags_DefaultOpen)) + { + bLPMConfigChanged |= ImGui::Checkbox("Shoulder", &m_UIState.bShoulder); + bLPMConfigChanged |= ImGui::SliderFloat("Soft Gap", &m_UIState.SoftGap, 0.0f, 0.5f); + bLPMConfigChanged |= ImGui::SliderFloat("HDR Max", &m_UIState.HdrMax, 8.0f, 2048.0f); + bLPMConfigChanged |= ImGui::SliderFloat("LPM Exposure", &m_UIState.LpmExposure, 3.0f, 11.0f); + bLPMConfigChanged |= ImGui::SliderFloat("Contrast", &m_UIState.Contrast, 0.0f, 1.0f); + bLPMConfigChanged |= ImGui::SliderFloat("Shoulder Contrast", &m_UIState.ShoulderContrast, 1.0f, 1.2f); + bLPMConfigChanged |= ImGui::SliderFloat3("Saturation", &m_UIState.Saturation[0], 0.0f, 1.0f); + bLPMConfigChanged |= ImGui::SliderFloat3("Crosstalk", &m_UIState.Crosstalk[0], 0.0f, 1.0f); + + if (bLPMConfigChanged) + { + bLPMConfigChanged = false; + + m_device.GPUFlush(); + OnUpdateDisplay(); + } + + if (ImGui::Button("Reset Scene defaults (R)")) + { + m_UIState.ResetLPMSceneDefaults(); + } + } + } + #endif + + ImGui::Spacing(); + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("Magnifier", ImGuiTreeNodeFlags_DefaultOpen)) + { + // read in Magnifier pass parameters from the UI & app state + MagnifierPS::PassParameters& params = m_UIState.MagnifierParams; + params.uImageHeight = m_Height; + params.uImageWidth = m_Width; + params.iMousePos[0] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionX : static_cast(io.MousePos.x); + params.iMousePos[1] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionY : static_cast(io.MousePos.y); + + ImGui::Checkbox("Show Magnifier (M)", &m_UIState.bUseMagnifier); + + DisableUIStateBegin(m_UIState.bUseMagnifier); + { + // Use a local bool state here to track locked state through the UI widget, + // and then call ToggleMagnifierLockedState() to update the persistent state (m_UIstate). + // The keyboard input for toggling lock directly operates on the persistent state. + const bool bIsMagnifierCurrentlyLocked = m_UIState.bLockMagnifierPosition; + ImGui::Checkbox("Lock Position (L)", &m_UIState.bLockMagnifierPosition); + const bool bWeJustLockedPosition = m_UIState.bLockMagnifierPosition && !bIsMagnifierCurrentlyLocked; + if (bWeJustLockedPosition) + { + m_UIState.ToggleMagnifierLock(); + } + + ImGui::SliderFloat("Screen Size", ¶ms.fMagnifierScreenRadius, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); + ImGui::SliderFloat("Magnification", ¶ms.fMagnificationAmount, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); + ImGui::SliderInt("OffsetX", ¶ms.iMagnifierOffset[0], -m_Width, m_Width); + ImGui::SliderInt("OffsetY", ¶ms.iMagnifierOffset[1], -m_Height, m_Height); + } + DisableUIStateEnd(m_UIState.bUseMagnifier); + } + + ImGui::End(); // CONTROLS + } + + // Render PROFILER window + // + if (m_UIState.bShowProfilerWindow) + { + constexpr size_t NUM_FRAMES = 128; + static float FRAME_TIME_ARRAY[NUM_FRAMES] = { 0 }; + + // track highest frame rate and determine the max value of the graph based on the measured highest value + static float RECENT_HIGHEST_FRAME_TIME = 0.0f; + constexpr int FRAME_TIME_GRAPH_MAX_FPS[] = { 800, 240, 120, 90, 60, 45, 30, 15, 10, 5, 4, 3, 2, 1 }; + static float FRAME_TIME_GRAPH_MAX_VALUES[_countof(FRAME_TIME_GRAPH_MAX_FPS)] = { 0 }; // us + 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]; } + + //scrolling data and average FPS computing + const std::vector& timeStamps = m_pRenderer->GetTimingValues(); + const bool bTimeStampsAvailable = timeStamps.size() > 0; + if (bTimeStampsAvailable) + { + RECENT_HIGHEST_FRAME_TIME = 0; + FRAME_TIME_ARRAY[NUM_FRAMES - 1] = timeStamps.back().m_microseconds; + for (uint32_t i = 0; i < NUM_FRAMES - 1; i++) + { + FRAME_TIME_ARRAY[i] = FRAME_TIME_ARRAY[i + 1]; + } + RECENT_HIGHEST_FRAME_TIME = max(RECENT_HIGHEST_FRAME_TIME, FRAME_TIME_ARRAY[NUM_FRAMES - 1]); + } + const float& frameTime_us = FRAME_TIME_ARRAY[NUM_FRAMES - 1]; + const float frameTime_ms = frameTime_us * 0.001f; + const int fps = bTimeStampsAvailable ? static_cast(1000000.0f / frameTime_us) : 0; + + // UI + ImGui::SetNextWindowPos(ImVec2((float)PROFILER_WINDOW_POS_X, (float)PROFILER_WINDOW_POS_Y), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(PROFILER_WINDOW_SIZE_X, PROFILER_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); + ImGui::Begin("PROFILER (F2)", &m_UIState.bShowProfilerWindow); + + ImGui::Text("Resolution : %ix%i", m_Width, m_Height); + ImGui::Text("API : %s", m_systemInfo.mGfxAPI.c_str()); + ImGui::Text("GPU : %s", m_systemInfo.mGPUName.c_str()); + ImGui::Text("CPU : %s", m_systemInfo.mCPUName.c_str()); + ImGui::Text("FPS : %d (%.2f ms)", fps, frameTime_ms); + + if (ImGui::CollapsingHeader("GPU Timings", ImGuiTreeNodeFlags_DefaultOpen)) + { + std::string msOrUsButtonText = m_UIState.bShowMilliseconds ? "Switch to microseconds" : "Switch to milliseconds"; + if (ImGui::Button(msOrUsButtonText.c_str())) { + m_UIState.bShowMilliseconds = !m_UIState.bShowMilliseconds; + } + ImGui::Spacing(); + + // find the index of the FrameTimeGraphMaxValue as the next higher-than-recent-highest-frame-time in the pre-determined value list + size_t iFrameTimeGraphMaxValue = 0; + for (int i = 0; i < _countof(FRAME_TIME_GRAPH_MAX_VALUES); ++i) + { + if (RECENT_HIGHEST_FRAME_TIME < FRAME_TIME_GRAPH_MAX_VALUES[i]) // FRAME_TIME_GRAPH_MAX_VALUES are in increasing order + { + iFrameTimeGraphMaxValue = min(_countof(FRAME_TIME_GRAPH_MAX_VALUES) - 1, i + 1); + break; + } + } + ImGui::PlotLines("", FRAME_TIME_ARRAY, NUM_FRAMES, 0, "GPU frame time (us)", 0.0f, FRAME_TIME_GRAPH_MAX_VALUES[iFrameTimeGraphMaxValue], ImVec2(0, 80)); + + for (uint32_t i = 0; i < timeStamps.size(); i++) + { + float value = m_UIState.bShowMilliseconds ? timeStamps[i].m_microseconds / 1000.0f : timeStamps[i].m_microseconds; + const char* pStrUnit = m_UIState.bShowMilliseconds ? "ms" : "us"; + ImGui::Text("%-18s: %7.2f %s", timeStamps[i].m_label.c_str(), value, pStrUnit); + } + } + ImGui::End(); // PROFILER + } +} + +void UIState::Initialize() +{ + // init magnifier params + for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; // start at 'free' state + + // init GUI state + this->SelectedTonemapperIndex = 0; + this->bUseMagnifier = false; + this->bLockMagnifierPosition = this->bLockMagnifierPositionHistory = false; + this->Exposure = 1.0f; + this->UnusedExposure = 1.0f; + this->EmissiveFactor = 1.0f; + this->bShowControlsWindow = true; + this->bShowProfilerWindow = false; + this->TestPattern = 0; + this->ColorSpace = ColorSpace::ColorSpace_REC709; + this->bShoulder = 1; + this->SoftGap = 0.0f; + this->HdrMax = 8.0f; + this->LpmExposure = 3.0f; + this->Contrast = 0.3f; + this->ShoulderContrast = 1.0f; + this->Saturation[0] = 0.0f; this->Saturation[1] = 0.0f; this->Saturation[2] = 0.0f; + this->Crosstalk[0] = 1.0f; this->Crosstalk[1] = 1.0f / 2.0f; this->Crosstalk[2] = 1.0f / 32.0f; +} + + + +// +// Magnifier UI Controls +// +void UIState::ToggleMagnifierLock() +{ + if (this->bUseMagnifier) + { + this->bLockMagnifierPositionHistory = this->bLockMagnifierPosition; // record histroy + this->bLockMagnifierPosition = !this->bLockMagnifierPosition; // flip state + const bool bLockSwitchedOn = !this->bLockMagnifierPositionHistory && this->bLockMagnifierPosition; + const bool bLockSwitchedOff = this->bLockMagnifierPositionHistory && !this->bLockMagnifierPosition; + if (bLockSwitchedOn) + { + const ImGuiIO& io = ImGui::GetIO(); + this->LockedMagnifiedScreenPositionX = static_cast(io.MousePos.x); + this->LockedMagnifiedScreenPositionY = static_cast(io.MousePos.y); + for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__LOCKED[ch]; + } + else if (bLockSwitchedOff) + { + for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; + } + } +} + +// These are currently not bound to any mouse input and are here for convenience/reference. +// Mouse scroll is currently wired up to camera for panning and moving in the local Z direction. +// Any application that would prefer otherwise can utilize these for easily controlling the magnifier parameters through the desired input. +void UIState::AdjustMagnifierSize (float increment /*= 0.05f*/){ MagnifierParams.fMagnifierScreenRadius = clamped(MagnifierParams.fMagnifierScreenRadius + increment, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); } +void UIState::AdjustMagnifierMagnification(float increment /*= 1.00f*/){ MagnifierParams.fMagnificationAmount = clamped(MagnifierParams.fMagnificationAmount + increment, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); } + +void UIState::ResetLPMSceneDefaults() +{ + if (SelectedTonemapperIndex == 0) + { + bSceneChanged = true; + } +} diff --git a/sample/src/DX12/UI.h b/sample/src/DX12/UI.h new file mode 100644 index 0000000..d0fa2b4 --- /dev/null +++ b/sample/src/DX12/UI.h @@ -0,0 +1,85 @@ +// AMD SampleDX12 sample code +// +// Copyright(c) 2020 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once + +#include "Misc/ColorConversion.h" +#include "PostProc/MagnifierPS.h" +#include + +struct UIState +{ + // + // WINDOW MANAGEMENT + // + bool bShowControlsWindow; + bool bShowProfilerWindow; + + // + // POST PROCESS CONTROLS + // + int SelectedTonemapperIndex; + float Exposure; + float UnusedExposure; + + bool bUseMagnifier; + bool bLockMagnifierPosition; + bool bLockMagnifierPositionHistory; + int LockedMagnifiedScreenPositionX; + int LockedMagnifiedScreenPositionY; + CAULDRON_DX12::MagnifierPS::PassParameters MagnifierParams; + + // + // APP/SCENE CONTROLS + // + float EmissiveFactor; + + // + // PROFILER CONTROLS + // + bool bShowMilliseconds; + + // + // TEST PATTERN + // + int TestPattern; + ColorSpace ColorSpace; + + // + // LPM CONFIG + // + bool bShoulder; // Use optional extra shoulderContrast tuning (set to false if shoulderContrast is 1.0). + float SoftGap; // Range of 0 to a little over zero, controls how much feather region in out-of-gamut mapping, 0=clip. + float HdrMax; // Maximum input value. + float LpmExposure; // Number of stops between 'hdrMax' and 18% mid-level on input. + float Contrast; // Input range {0.0 (no extra contrast) to 1.0 (maximum contrast)}. + float ShoulderContrast; // Shoulder shaping, 1.0 = no change (fast path). + float Saturation[3]; // A per channel adjustment, use <0 decrease, 0=no change, >0 increase. + float Crosstalk[3]; // One channel must be 1.0, the rest can be <= 1.0 but not zero. + + // ----------------------------------------------- + + void Initialize(); + + void ToggleMagnifierLock(); + void AdjustMagnifierSize(float increment = 0.05f); + void AdjustMagnifierMagnification(float increment = 1.00f); + + void ResetLPMSceneDefaults(); +}; \ No newline at end of file diff --git a/sample/src/DX12/dpiawarescaling.manifest b/sample/src/DX12/dpiawarescaling.manifest new file mode 100644 index 0000000..8dd8cd9 --- /dev/null +++ b/sample/src/DX12/dpiawarescaling.manifest @@ -0,0 +1,8 @@ + + + + + true/PM + + + \ No newline at end of file diff --git a/sample/src/DX12/shaders/FlipBookAnimationPS.hlsl b/sample/src/DX12/shaders/FlipBookAnimationPS.hlsl index 127ef5a..b9daaad 100644 --- a/sample/src/DX12/shaders/FlipBookAnimationPS.hlsl +++ b/sample/src/DX12/shaders/FlipBookAnimationPS.hlsl @@ -22,13 +22,13 @@ //-------------------------------------------------------------------------------------- cbuffer cbPerFrame : register(b0) { - uint u_row; - uint u_cols; - float u_time; - float u_angle; - float4 u_camPos; - matrix u_mWorld; - matrix u_mCameraViewProj; + uint u_row; + uint u_cols; + float u_time; + float u_angle; + float4 u_camPos; + matrix u_mWorld; + matrix u_mCameraViewProj; }; //-------------------------------------------------------------------------------------- @@ -36,8 +36,8 @@ cbuffer cbPerFrame : register(b0) //-------------------------------------------------------------------------------------- struct VERTEX { - float4 vPosition : SV_POSITION; - float2 vTexcoord : TEXCOORD; + float4 vPosition : SV_POSITION; + float2 vTexcoord : TEXCOORD; }; //-------------------------------------------------------------------------------------- @@ -51,7 +51,7 @@ SamplerState samLinearClamp :register(s0); //-------------------------------------------------------------------------------------- float4 mainPS(VERTEX Input) : SV_Target { - float4 color = sceneTexture.Sample(samLinearClamp, Input.vTexcoord); - color.rgb *= 2.0; - return color; + float4 color = sceneTexture.Sample(samLinearClamp, Input.vTexcoord); + color.rgb *= 2.0; + return color; } \ No newline at end of file diff --git a/sample/src/DX12/shaders/FlipBookAnimationVS.hlsl b/sample/src/DX12/shaders/FlipBookAnimationVS.hlsl index 8662eb1..5f73430 100644 --- a/sample/src/DX12/shaders/FlipBookAnimationVS.hlsl +++ b/sample/src/DX12/shaders/FlipBookAnimationVS.hlsl @@ -22,25 +22,25 @@ //-------------------------------------------------------------------------------------- cbuffer cbPerFrame : register(b0) { - uint u_row; - uint u_cols; - float u_time; - float u_angle; - float4 u_camPos; - matrix u_mWorld; - matrix u_mCameraViewProj; + uint u_row; + uint u_cols; + float u_time; + float u_angle; + float4 u_camPos; + matrix u_mWorld; + matrix u_mCameraViewProj; }; struct VERTEX_IN { - float4 vPosition : POSITION; - float2 vTexcoord : TEXCOORD; + float4 vPosition : POSITION; + float2 vTexcoord : TEXCOORD; }; struct VERTEX_OUT { - float4 vPosition : SV_POSITION; - float2 vTexcoord : TEXCOORD; + float4 vPosition : SV_POSITION; + float2 vTexcoord : TEXCOORD; }; VERTEX_OUT mainVS(VERTEX_IN Input) @@ -61,20 +61,20 @@ VERTEX_OUT mainVS(VERTEX_IN Input) float2 size = float2(1.0f / u_cols, 1.0f / u_row); uint totalFrames = u_row * u_cols; - + // use timer to increment index uint index = (u_time * 60) % totalFrames; - + // wrap x and y indexes uint indexX = index % u_cols; uint indexY = index / u_cols; - + // get offsets to our sprite index float2 offset = float2(size.x*indexX, size.y*indexY); - + // get single sprite UV float2 newUV = Input.vTexcoord * size; - + // Slight offset in Y because of visual seam newUV.y += 0.001; diff --git a/sample/src/DX12/shaders/TestImagesPS.hlsl b/sample/src/DX12/shaders/TestImagesPS.hlsl index c0fbf66..db3c33d 100644 --- a/sample/src/DX12/shaders/TestImagesPS.hlsl +++ b/sample/src/DX12/shaders/TestImagesPS.hlsl @@ -30,7 +30,7 @@ cbuffer cbPerFrame : register(b0) //-------------------------------------------------------------------------------------- struct VERTEX { - float2 vTexcoord : TEXCOORD; + float2 vTexcoord : TEXCOORD; }; //-------------------------------------------------------------------------------------- diff --git a/sample/src/DX12/stdafx.h b/sample/src/DX12/stdafx.h index 5afdaeb..cbe59a8 100644 --- a/sample/src/DX12/stdafx.h +++ b/sample/src/DX12/stdafx.h @@ -28,61 +28,67 @@ #include #include - // C RunTime Header Files #include #include #include #include #include -#include "..\..\libs\d3d12x\d3dx12.h" -// we are using DirectXMath -#include -using namespace DirectX; +#include "../../libs/d3d12x/d3dx12.h" + +// Pull in math library +#include "../../libs/vectormath/vectormath.hpp" // TODO: reference additional headers your program requires here -#include "base\Imgui.h" -#include "Base\ImguiHelper.h" -#include "base\Fence.h" -#include "Base\Helper.h" -#include "Base\Device.h" -#include "base\FreesyncHDR.h" -#include "base\Texture.h" -#include "base\SwapChain.h" -#include "base\UploadHeap.h" -#include "Base\UserMarkers.h" -#include "base\GPUTimestamps.h" -#include "base\CommandListRing.h" -#include "base\ShaderCompilerHelper.h" -#include "base\StaticBufferPool.h" -#include "base\DynamicBufferRing.h" -#include "base\ResourceViewHeaps.h" -#include "base\StaticConstantBufferPool.h" +#include "Base/Imgui.h" +#include "Base/ImguiHelper.h" +#include "Base/Fence.h" +#include "Base/Helper.h" +#include "Base/Device.h" +#include "Base/Texture.h" +#include "Base/FrameworkWindows.h" +#include "Base/FreeSyncHDR.h" +#include "Base/SwapChain.h" +#include "Base/UploadHeap.h" +#include "Base/SaveTexture.h" +#include "Base/UserMarkers.h" +#include "Base/GPUTimestamps.h" +#include "Base/CommandListRing.h" +#include "Base/StaticBufferPool.h" +#include "Base/DynamicBufferRing.h" +#include "Base/ResourceViewHeaps.h" +#include "Base/ShaderCompilerCache.h" +#include "Base/ShaderCompilerHelper.h" +#include "Base/StaticConstantBufferPool.h" -#include "Misc\Misc.h" -#include "Misc\Error.h" -#include "Misc\Camera.h" -#include "Misc\FrameworkWindows.h" -#include "Misc\ColorConversion.h" +#include "GLTF/GltfPbrPass.h" +#include "GLTF/GltfBBoxPass.h" +#include "GLTF/GltfDepthPass.h" +#include "GLTF/GltfMotionVectorsPass.h" -#include "GLTF\GltfPbrPass.h" -#include "GLTF\GltfDepthPass.h" -#include "GLTF\GltfBBoxPass.h" +#include "Misc/Misc.h" +#include "Misc/Error.h" +#include "Misc/Camera.h" +#include "Misc/ColorConversion.h" -#include "PostProc\ColorConversionPS.h" -#include "PostProc\ToneMapping.h" -#include "PostProc\ToneMappingCS.h" -#include "PostProc\DownSamplePS.h" -#include "PostProc\SkyDome.h" -#include "PostProc\SkyDomeProc.h" -#include "PostProc\BlurPS.h" -#include "PostProc\Bloom.h" +#include "PostProc/TAA.h" +#include "PostProc/Bloom.h" +#include "PostProc/BlurPS.h" +#include "PostProc/SkyDome.h" +#include "PostProc/SkyDomeProc.h" +#include "PostProc/PostProcCS.h" +#include "PostProc/ToneMapping.h" +#include "PostProc/ToneMappingCS.h" +#include "PostProc/ColorConversionPS.h" +#include "PostProc/DownSamplePS.h" +#include "PostProc/ShadowResolvePass.h" + +#include "Widgets/wireframe.h" -#include "TestImages.h" #include "FlipBookAnimation.h" -#include "LPMPS.h" +#include "TestImages.h" #include "ExposureMultiplierCS.h" +#include "LPMPS.h" -#include "Widgets\wireframe.h" -using namespace CAULDRON_DX12; \ No newline at end of file +using namespace CAULDRON_DX12; diff --git a/sample/src/VK/CMakeLists.txt b/sample/src/VK/CMakeLists.txt index 511915d..9906e9c 100644 --- a/sample/src/VK/CMakeLists.txt +++ b/sample/src/VK/CMakeLists.txt @@ -1,55 +1,63 @@ project (LPMSample_${GFX_API}) set(sources - LPMSample.cpp - LPMSample.h - SampleRenderer.cpp - SampleRenderer.h - TestImages.cpp - TestImages.h - FlipBookAnimation.cpp - FlipBookAnimation.h - ExposureMultiplierCS.h - ExposureMultiplierCS.cpp - LPMPS.cpp - LPMPS.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h - stdafx.cpp - stdafx.h) + LPMSample.cpp + LPMSample.h + Renderer.cpp + Renderer.h + UI.cpp + UI.h + TestImages.cpp + TestImages.h + FlipBookAnimation.cpp + FlipBookAnimation.h + ExposureMultiplierCS.h + ExposureMultiplierCS.cpp + LPMPS.cpp + LPMPS.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h + stdafx.cpp + stdafx.h + dpiawarescaling.manifest) set(LPM_Shaders_src - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/TestImagesPS.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationVS.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationPS.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/transferFunction.h - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/ExposureMultiplierCS.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/shaders/LPMPS.glsl - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h - ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h) - -source_group("Sources" FILES ${sources}) -source_group("LPM_Shaders_src" FILES ${LPM_Shaders_src}) - -add_executable(${PROJECT_NAME} WIN32 ${sources} ${LPM_Shaders_src}) -target_link_libraries (${PROJECT_NAME} LINK_PUBLIC Cauldron_VK ImGUI Vulkan::Vulkan) + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/TestImagesPS.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationVS.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/FlipBookAnimationPS.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/transferFunction.h + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/ExposureMultiplierCS.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/shaders/LPMPS.glsl + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_a.h + ${CMAKE_CURRENT_SOURCE_DIR}/../../../ffx-lpm/ffx_lpm.h) + +set(JSON_Data_src + ${CMAKE_CURRENT_SOURCE_DIR}/../Common/LPMSample.json) + +source_group("Sources" FILES ${sources}) +source_group("LPM_Shaders_src" FILES ${LPM_Shaders_src}) +source_group("Icon" FILES ${icon_src}) # defined in top-level CMakeLists.txt +source_group("JSON_Data" FILES ${JSON_Data_src}) + +add_executable(${PROJECT_NAME} WIN32 ${sources} ${LPM_Shaders_src} ${icon_src} ${JSON_Data_src}) +target_link_libraries (${PROJECT_NAME} LINK_PUBLIC LPMSample_Common Cauldron_VK ImGUI Vulkan::Vulkan) set_target_properties(${PROJECT_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${CMAKE_HOME_DIRECTORY}/bin") set_source_files_properties(${LPM_Shaders_src} PROPERTIES VS_TOOL_OVERRIDE "Text") function(copyCommand list dest) - foreach(fullFileName ${list}) - get_filename_component(file ${fullFileName} NAME) - message("Generating custom command for ${fullFileName}") - add_custom_command( - OUTPUT ${dest}/${file} - PRE_BUILD - COMMAND cmake -E make_directory ${dest} - COMMAND cmake -E copy ${fullFileName} ${dest} - MAIN_DEPENDENCY ${fullFileName} - COMMENT "Updating ${file} into ${dest}" - ) - endforeach() + foreach(fullFileName ${list}) + get_filename_component(file ${fullFileName} NAME) + message("Generating custom command for ${fullFileName}") + add_custom_command( + OUTPUT ${dest}/${file} + PRE_BUILD + COMMAND cmake -E make_directory ${dest} + COMMAND cmake -E copy ${fullFileName} ${dest} + MAIN_DEPENDENCY ${fullFileName} + COMMENT "Updating ${file} into ${dest}" + ) + endforeach() endfunction() copyCommand("${LPM_Shaders_src}" ${CMAKE_HOME_DIRECTORY}/bin/ShaderLibVK) \ No newline at end of file diff --git a/sample/src/VK/ExposureMultiplierCS.cpp b/sample/src/VK/ExposureMultiplierCS.cpp index df2b2fa..45f3279 100644 --- a/sample/src/VK/ExposureMultiplierCS.cpp +++ b/sample/src/VK/ExposureMultiplierCS.cpp @@ -20,7 +20,6 @@ #include "stdafx.h" #include "Base/DynamicBufferRing.h" #include "Base/StaticBufferPool.h" -#include "Base/ExtDebugMarkers.h" #include "Base/UploadHeap.h" #include "Base/Helper.h" #include "ExposureMultiplierCS.h" @@ -82,7 +81,7 @@ namespace CAULDRON_VK SetDescriptorSet(m_pDevice->GetDevice(), 1, HDRSRV, descriptorSet); m_pDynamicBufferRing->SetDescriptorSet(0, sizeof(ExposureMultiplierConsts), descriptorSet); - m_ExposureMultiplier.Draw(cmd_buf, cbExposureMultiplierHandle, descriptorSet, (width + 7) / 8, (height + 7) / 8, 1); + m_ExposureMultiplier.Draw(cmd_buf, &cbExposureMultiplierHandle, descriptorSet, (width + 7) / 8, (height + 7) / 8, 1); SetPerfMarkerEnd(cmd_buf); } diff --git a/sample/src/VK/FlipBookAnimation.cpp b/sample/src/VK/FlipBookAnimation.cpp index 5ebdaeb..ba5e852 100644 --- a/sample/src/VK/FlipBookAnimation.cpp +++ b/sample/src/VK/FlipBookAnimation.cpp @@ -31,7 +31,7 @@ namespace CAULDRON_VK DynamicBufferRing *pDynamicBufferRing, StaticBufferPool *pStaticBufferPool, VkSampleCountFlagBits sampleDescCount, - UINT numRows, UINT numColms, std::string flipBookAnimationTexture, XMMATRIX worldMatrix) + UINT numRows, UINT numColms, std::string flipBookAnimationTexture, math::Matrix4 worldMatrix) { m_pDevice = pDevice; m_pResourceViewHeaps = pResourceViewHeaps; @@ -54,10 +54,10 @@ namespace CAULDRON_VK float vertices[] = { // pos // uv - -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, - 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, - -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f + -1.0f, 1.0f, 0.0f, 1.0f, 0.0f, 0.0f, + 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 0.0f, + 1.0f, -1.0f, 0.0f, 1.0f, 1.0f, 1.0f, + -1.0f, -1.0f, 0.0f, 1.0f, 0.0f, 1.0f }; m_pStaticBufferPool->AllocBuffer(24, 6 * sizeof(float), vertices, &m_VBV); @@ -309,7 +309,7 @@ namespace CAULDRON_VK vkDestroySampler(m_pDevice->GetDevice(), m_sampler, nullptr); } - void FlipBookAnimation::Draw(VkCommandBuffer cmd_buf, float time, XMVECTOR camPos, XMMATRIX viewProjMat) + void FlipBookAnimation::Draw(VkCommandBuffer cmd_buf, float time, math::Vector4 camPos, math::Matrix4 viewProjMat) { VkDescriptorBufferInfo cbFlipBookAnimation; FlipBookAnimationCBuffer *pFlipBookAnimation; @@ -318,9 +318,8 @@ namespace CAULDRON_VK pFlipBookAnimation->cols = m_numColms; pFlipBookAnimation->time = time; - XMFLOAT4 dist; - XMStoreFloat4(&dist, camPos - m_worldMatrix.r[3]); - float angle = atan2(dist.x, dist.z); + math::Vector4 dist = camPos - m_worldMatrix.getCol3(); + float angle = atan2(dist.getX(), dist.getZ()); pFlipBookAnimation->angle = -angle; pFlipBookAnimation->camPos = camPos; @@ -337,5 +336,5 @@ namespace CAULDRON_VK vkCmdBindPipeline(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipeline); vkCmdDrawIndexed(cmd_buf, m_NumIndices, 1, 0, 0, 0); - } + } } diff --git a/sample/src/VK/FlipBookAnimation.h b/sample/src/VK/FlipBookAnimation.h index f7b2d90..e2e90c5 100644 --- a/sample/src/VK/FlipBookAnimation.h +++ b/sample/src/VK/FlipBookAnimation.h @@ -38,9 +38,9 @@ namespace CAULDRON_VK DynamicBufferRing *pDynamicBufferRing, StaticBufferPool *pStaticBufferPool, VkSampleCountFlagBits sampleDescCount, - UINT numRows, UINT numColms, std::string flipBookAnimationTexture, XMMATRIX worldMatrix); + UINT numRows, UINT numColms, std::string flipBookAnimationTexture, math::Matrix4 worldMatrix); void OnDestroy(); - void Draw(VkCommandBuffer cmd_buf, float time, XMVECTOR camPos, XMMATRIX viewProjMat); + void Draw(VkCommandBuffer cmd_buf, float time, math::Vector4 camPos, math::Matrix4 viewProjMat); private: Device * m_pDevice; @@ -69,16 +69,16 @@ namespace CAULDRON_VK UINT m_numRows; UINT m_numColms; - XMMATRIX m_worldMatrix; + math::Matrix4 m_worldMatrix; struct FlipBookAnimationCBuffer { UINT row; UINT cols; float time; float angle; - XMVECTOR camPos; - XMMATRIX worldMat; - XMMATRIX viewProjMat; + math::Vector4 camPos; + math::Matrix4 worldMat; + math::Matrix4 viewProjMat; }; }; } \ No newline at end of file diff --git a/sample/src/VK/LPMPS.cpp b/sample/src/VK/LPMPS.cpp index a89fa15..27bb553 100644 --- a/sample/src/VK/LPMPS.cpp +++ b/sample/src/VK/LPMPS.cpp @@ -20,7 +20,6 @@ #include "stdafx.h" #include "Base/DynamicBufferRing.h" #include "Base/ShaderCompiler.h" -#include "Base/ExtDebugMarkers.h" #include "Base/UploadHeap.h" #include "Base/FreeSyncHDR.h" #include "Base/Helper.h" @@ -131,7 +130,15 @@ namespace CAULDRON_VK m_scaleC = scaleC; } - void LPMPS::UpdatePipelines(VkRenderPass renderPass, DisplayModes displayMode, ColorSpace colorSpace) + void LPMPS::UpdatePipelines(VkRenderPass renderPass, DisplayMode displayMode, ColorSpace colorSpace, + bool shoulder, + float softGap, + float hdrMax, + float lpmExposure, + float contrast, + float shoulderContrast, + float saturation[3], + float crosstalk[3]) { m_lpm.UpdatePipeline(renderPass, NULL, VK_SAMPLE_COUNT_1_BIT); @@ -167,14 +174,14 @@ namespace CAULDRON_VK displayMinMaxLuminance[0] = pHDRMetatData->minLuminance; displayMinMaxLuminance[1] = pHDRMetatData->maxLuminance; } - m_shoulder = 0; - m_softGap = 1.0f / 32.0f; - m_hdrMax = 256.0f; // Controls brightness. Need to tune according to display mode - m_exposure = 8.0f; // Controls brightness. Need to tune according to display mode - m_contrast = 0.3f; - m_shoulderContrast = 1.0f; - m_saturation[0] = 0.0f; m_saturation[1] = 0.0f; m_saturation[2] = 0.0f; - m_crosstalk[0] = 1.0f; m_crosstalk[1] = 1.0f / 2.0f; m_crosstalk[2] = 1.0f / 32.0f; + m_shoulder = shoulder; + m_softGap = softGap; + m_hdrMax = hdrMax; + m_exposure = lpmExposure; + m_contrast = contrast; + m_shoulderContrast = shoulderContrast; + m_saturation[0] = saturation[0]; m_saturation[1] = saturation[1]; m_saturation[2] = saturation[2]; + m_crosstalk[0] = crosstalk[0]; m_crosstalk[1] = crosstalk[1]; m_crosstalk[2] = crosstalk[2]; switch (colorSpace) { @@ -336,7 +343,7 @@ namespace CAULDRON_VK m_pDynamicBufferRing->SetDescriptorSet(0, sizeof(LPMConsts), descriptorSet); // Draw! - m_lpm.Draw(cmd_buf, cbLPMHandle, descriptorSet); + m_lpm.Draw(cmd_buf, &cbLPMHandle, descriptorSet); SetPerfMarkerEnd(cmd_buf); } diff --git a/sample/src/VK/LPMPS.h b/sample/src/VK/LPMPS.h index 5cabfd4..4991664 100644 --- a/sample/src/VK/LPMPS.h +++ b/sample/src/VK/LPMPS.h @@ -30,7 +30,15 @@ namespace CAULDRON_VK void OnCreate(Device* pDevice, VkRenderPass renderPass, ResourceViewHeaps *pResourceViewHeaps, StaticBufferPool *pStaticBufferPool, DynamicBufferRing *pDynamicBufferRing); void OnDestroy(); - void UpdatePipelines(VkRenderPass renderPass, DisplayModes displayMode, ColorSpace colorSpace); + void UpdatePipelines(VkRenderPass renderPass, DisplayMode displayMode, ColorSpace colorSpace, + bool shoulder, + float softGap, + float hdrMax, + float lpmExposure, + float contrast, + float shoulderContrast, + float saturation[3], + float crosstalk[3]); void Draw(VkCommandBuffer cmd_buf, VkImageView HDRSRV); @@ -76,8 +84,8 @@ namespace CAULDRON_VK VkDescriptorSet m_descriptorSet[s_descriptorBuffers]; VkDescriptorSetLayout m_descriptorSetLayout; - DisplayModes m_displayMode; - XMMATRIX m_inputToOutputMatrix; + DisplayMode m_displayMode; + math::Matrix4 m_inputToOutputMatrix; struct LPMConsts { UINT shoulder; @@ -88,7 +96,7 @@ namespace CAULDRON_VK UINT scaleOnly; UINT displayMode; UINT pad; - XMMATRIX inputToOutputMatrix; + math::Matrix4 inputToOutputMatrix; uint32_t ctl[24 * 4]; }; }; diff --git a/sample/src/VK/LPMSample.cpp b/sample/src/VK/LPMSample.cpp index b696fc0..163f6ac 100644 --- a/sample/src/VK/LPMSample.cpp +++ b/sample/src/VK/LPMSample.cpp @@ -18,19 +18,16 @@ // THE SOFTWARE. #include "stdafx.h" +#include #include "LPMSample.h" - LPMSample::LPMSample(LPCSTR name) : FrameworkWindows(name) { - m_lastFrameTime = MillisecondsNow(); m_time = 0; m_bPlay = true; m_pGltfLoader = NULL; - m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; - m_enableLocalDimming = true; } //-------------------------------------------------------------------------------------- @@ -38,12 +35,80 @@ LPMSample::LPMSample(LPCSTR name) : FrameworkWindows(name) // OnParseCommandLine // //-------------------------------------------------------------------------------------- -void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight, bool* pbFullScreen) +void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight) { // set some default values *pWidth = 1920; *pHeight = 1080; - *pbFullScreen = false; + m_activeScene = 0; //load the first one by default + m_VsyncEnabled = false; + m_bIsBenchmarking = false; + m_fontSize = 13.f; // default value overridden by a json file if available + m_isCpuValidationLayerEnabled = false; + m_isGpuValidationLayerEnabled = false; + m_activeCamera = 0; + m_stablePowerState = false; + + //read globals + auto process = [&](json jData) + { + *pWidth = jData.value("width", *pWidth); + *pHeight = jData.value("height", *pHeight); + m_fullscreenMode = jData.value("presentationMode", m_fullscreenMode); + m_activeScene = jData.value("activeScene", m_activeScene); + m_activeCamera = jData.value("activeCamera", m_activeCamera); + m_isCpuValidationLayerEnabled = jData.value("CpuValidationLayerEnabled", m_isCpuValidationLayerEnabled); + m_isGpuValidationLayerEnabled = jData.value("GpuValidationLayerEnabled", m_isGpuValidationLayerEnabled); + m_VsyncEnabled = jData.value("vsync", m_VsyncEnabled); + m_bIsBenchmarking = jData.value("benchmark", m_bIsBenchmarking); + m_stablePowerState = jData.value("stablePowerState", m_stablePowerState); + m_fontSize = jData.value("fontsize", m_fontSize); + }; + + //read json globals from commandline + // + try + { + if (strlen(lpCmdLine) > 0) + { + auto j3 = json::parse(lpCmdLine); + process(j3); + } + } + catch (json::parse_error) + { + Trace("Error parsing commandline\n"); + exit(0); + } + + // read config file (and override values from commandline if so) + // + { + std::ifstream f("LPMSample.json"); + if (!f) + { + MessageBox(NULL, "Config file not found!\n", "Cauldron Panic!", MB_ICONERROR); + exit(0); + } + + try + { + f >> m_jsonConfigFile; + } + catch (json::parse_error) + { + MessageBox(NULL, "Error parsing LPMSample.json!\n", "Cauldron Panic!", MB_ICONERROR); + exit(0); + } + } + + + json globals = m_jsonConfigFile["globals"]; + process(globals); + + // get the list of scenes + for (const auto & scene : m_jsonConfigFile["scenes"]) + m_sceneNames.push_back(scene["name"]); } //-------------------------------------------------------------------------------------- @@ -51,41 +116,25 @@ void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* // OnCreate // //-------------------------------------------------------------------------------------- -void LPMSample::OnCreate(HWND hWnd) +void LPMSample::OnCreate() { - // Create Device - // - m_device.OnCreate("myapp", "myEngine", m_isCpuValidationLayerEnabled, m_isGpuValidationLayerEnabled, hWnd); - m_device.CreatePipelineCache(); - //init the shader compiler + InitDirectXCompiler(); CreateShaderCache(); - // Create Swapchain - // - uint32_t dwNumberOfBackBuffers = 2; - m_swapChain.OnCreate(&m_device, dwNumberOfBackBuffers, hWnd); - // Create a instance of the renderer and initialize it, we need to do that for each GPU - // - m_Node = new SampleRenderer(); - m_Node->OnCreate(&m_device, &m_swapChain); + m_pRenderer = new Renderer(); + m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); // init GUI (non gfx stuff) - // - ImGUI_Init((void *)hWnd); - - // init GUI state - m_state.testPattern = 0; - m_state.colorSpace = ColorSpace::ColorSpace_REC709; - m_state.toneMapper = 6; - m_state.exposure = 0.5f; - m_state.unusedExposure = 1.0f; - m_state.emmisiveFactor = 1.0f; - m_state.camera.LookAt(10.0f, 0.0f, 3.5f, XMVectorSet(-52.0f, -26.0f, -47.0f, 0)); - m_state.lightIntensity = 10.0f; - - m_swapChain.EnumerateDisplayModes(&m_displayModesAvailable, &m_displayModesNamesAvailable); + ImGUI_Init((void*)m_windowHwnd); + m_UIState.Initialize(); + + OnResize(); + OnUpdateDisplay(); + + // Init Camera, looking at the origin + m_camera.LookAt(math::Vector4(0, 0, 5, 0), math::Vector4(0, 0, 0, 0)); } //-------------------------------------------------------------------------------------- @@ -99,21 +148,12 @@ void LPMSample::OnDestroy() m_device.GPUFlush(); - // Set display mode to SDR before quitting. - m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; - - // Fullscreen state should always be false before exiting the app. - SetFullScreen(false); - - m_Node->UnloadScene(); - m_Node->OnDestroyWindowSizeDependentResources(); - m_Node->OnDestroy(); + m_pRenderer->UnloadScene(); + m_pRenderer->OnDestroyWindowSizeDependentResources(); + m_pRenderer->OnDestroy(); - delete m_Node; + delete m_pRenderer; - m_swapChain.OnDestroyWindowSizeDependentResources(); - m_swapChain.OnDestroy(); - //shut down the shader compiler DestroyShaderCache(&m_device); @@ -122,303 +162,280 @@ void LPMSample::OnDestroy() delete m_pGltfLoader; m_pGltfLoader = NULL; } - - m_device.DestroyPipelineCache(); - m_device.OnDestroy(); } //-------------------------------------------------------------------------------------- // -// OnEvent +// OnEvent, win32 sends us events and we forward them to ImGUI // //-------------------------------------------------------------------------------------- +static void ToggleBool(bool& b) { b = !b; } bool LPMSample::OnEvent(MSG msg) { if (ImGUI_WndProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam)) return true; + // handle function keys (F1, F2...) here, rest of the input is handled + // by imGUI later in HandleInput() function + const WPARAM& KeyPressed = msg.wParam; + switch (msg.message) + { + case WM_KEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + + /* WINDOW TOGGLES */ + if (KeyPressed == VK_F1) ToggleBool(m_UIState.bShowControlsWindow); + if (KeyPressed == VK_F2) ToggleBool(m_UIState.bShowProfilerWindow); + break; + } + return true; } //-------------------------------------------------------------------------------------- // -// SetFullScreen +// OnResize // //-------------------------------------------------------------------------------------- -void LPMSample::SetFullScreen(bool fullscreen) +void LPMSample::OnResize() { - m_device.GPUFlush(); + // Destroy resources (if we are not minimized) + if (m_Width && m_Height && m_pRenderer) + { + m_pRenderer->OnDestroyWindowSizeDependentResources(); + m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); + } - // when going to windowed make sure we are always using SDR - if ((fullscreen == false) && (m_currentDisplayMode != DISPLAYMODE_SDR)) - m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; + m_camera.SetFov(AMD_PI_OVER_4, m_Width, m_Height, 0.1f, 1000.0f); +} - m_swapChain.SetFullScreen(fullscreen); +//-------------------------------------------------------------------------------------- +// +// UpdateDisplay +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnUpdateDisplay() +{ + // Update resources that depend on display mode changed + if (m_pRenderer) + { + m_pRenderer->OnUpdateDisplayDependentResources(&m_swapChain, &m_UIState); + } } //-------------------------------------------------------------------------------------- // -// OnResize +// LoadScene // //-------------------------------------------------------------------------------------- -void LPMSample::OnResize(uint32_t width, uint32_t height) +void LPMSample::LoadScene(int sceneIndex) { - // Flush GPU - // - m_device.GPUFlush(); + json scene = m_jsonConfigFile["scenes"][sceneIndex]; - // If resizing but no minimizing - // - if (m_Width > 0 && m_Height > 0) + // release everything and load the GLTF, just the light json data, the rest (textures and geometry) will be done in the main loop + if (m_pGltfLoader != NULL) { - if (m_Node != NULL) - { - m_Node->OnDestroyWindowSizeDependentResources(); - } - m_swapChain.OnDestroyWindowSizeDependentResources(); + m_pRenderer->UnloadScene(); + m_pRenderer->OnDestroyWindowSizeDependentResources(); + m_pRenderer->OnDestroy(); + m_pGltfLoader->Unload(); + m_pRenderer->OnCreate(&m_device, &m_swapChain, m_fontSize); + m_pRenderer->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height); } - m_swapChain.EnumerateDisplayModes(&m_displayModesAvailable, &m_displayModesNamesAvailable); - - m_Width = width; - m_Height = height; + delete(m_pGltfLoader); + m_pGltfLoader = new GLTFCommon(); + if (m_pGltfLoader->Load(scene["directory"], scene["filename"]) == false) + { + MessageBox(NULL, "The selected model couldn't be found, please check the documentation", "Cauldron Panic!", MB_ICONERROR); + exit(0); + } - // if resizing but not minimizing the recreate it with the new size - // - if (m_Width > 0 && m_Height > 0) + // Load the UI settings, and also some defaults cameras and lights, in case the GLTF has none { - m_swapChain.OnCreateWindowSizeDependentResources(m_Width, m_Height, false, m_currentDisplayMode); - if (m_Node != NULL) +#define LOAD(j, key, val) val = j.value(key, val) + + // global settings + LOAD(scene, "toneMapper", m_UIState.SelectedTonemapperIndex); + LOAD(scene, "exposure", m_UIState.Exposure); + LOAD(scene, "emmisiveFactor", m_UIState.EmissiveFactor); + + // Add a default light in case there are none + // + if (m_pGltfLoader->m_lights.size() == 0) { - m_Node->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height, &m_state); + tfNode n; + n.m_tranform.LookAt(PolarToVector(AMD_PI_OVER_2, 0.58f) * 3.5f, math::Vector4(0, 0, 0, 0)); + + tfLight l; + l.m_type = tfLight::LIGHT_SPOTLIGHT; + l.m_intensity = scene.value("intensity", 1.0f); + l.m_color = math::Vector4(1.0f, 1.0f, 1.0f, 0.0f); + l.m_range = 15; + l.m_outerConeAngle = AMD_PI_OVER_4; + l.m_innerConeAngle = AMD_PI_OVER_4 * 0.9f; + + m_pGltfLoader->AddLight(n, l); } - } - m_state.camera.SetFov(XM_PI / 4, m_Width, m_Height, 0.1f, 1000.0f); + // Allocate shadow information (if any) + m_pRenderer->AllocateShadowMaps(m_pGltfLoader); -} + // set default camera + // + json camera = scene["camera"]; + m_activeCamera = scene.value("activeCamera", m_activeCamera); + math::Vector4 from = GetVector(GetElementJsonArray(camera, "defaultFrom", { 0.0, 0.0, 10.0 })); + math::Vector4 to = GetVector(GetElementJsonArray(camera, "defaultTo", { 0.0, 0.0, 0.0 })); + m_camera.LookAt(from, to); -//-------------------------------------------------------------------------------------- -// -// OnActivate -// -//-------------------------------------------------------------------------------------- -void LPMSample::OnActivate(bool windowActive) -{ - if (m_previousDisplayMode == DisplayModes::DISPLAYMODE_SDR && m_currentDisplayMode == DisplayModes::DISPLAYMODE_SDR) - return; + // set benchmarking state if enabled + // + if (m_bIsBenchmarking) + { + std::string deviceName; + std::string driverVersion; + m_device.GetDeviceInfo(&deviceName, &driverVersion); + BenchmarkConfig(scene["BenchmarkSettings"], m_activeCamera, m_pGltfLoader, deviceName, driverVersion); + } - m_currentDisplayMode = windowActive && m_swapChain.IsFullScreen() ? m_previousDisplayMode : DisplayModes::DISPLAYMODE_SDR; - m_currentDisplayModeNamesIndex = windowActive && m_swapChain.IsFullScreen() ? m_previousDisplayModeNamesIndex : DisplayModes::DISPLAYMODE_SDR; - OnResize(m_Width, m_Height); + // indicate the mainloop we started loading a GLTF and it needs to load the rest (textures and geometry) + m_loadingScene = true; + } } - //-------------------------------------------------------------------------------------- // -// OnLocalDimmingChanged +// OnUpdate // //-------------------------------------------------------------------------------------- -void LPMSample::OnLocalDimmingChanged() +void LPMSample::OnUpdate() { - // Flush GPU - // - m_device.GPUFlush(); + ImGuiIO& io = ImGui::GetIO(); - fsHdrSetLocalDimmingMode(m_swapChain.GetSwapChain(), m_enableLocalDimming); + //If the mouse was not used by the GUI then it's for the camera + if (io.WantCaptureMouse) + { + io.MouseDelta.x = 0; + io.MouseDelta.y = 0; + io.MouseWheel = 0; + } - m_Node->OnUpdateLocalDimmingChangedResources(&m_swapChain, &m_state); -} + // Update Camera + UpdateCamera(m_camera, io); -//-------------------------------------------------------------------------------------- -// -// OnRender -// -//-------------------------------------------------------------------------------------- -void LPMSample::OnRender() -{ - // Get timings - // - double timeNow = MillisecondsNow(); - m_deltaTime = timeNow - m_lastFrameTime; - m_lastFrameTime = timeNow; + // Keyboard & Mouse + HandleInput(io); - // Build UI and set the scene state. Note that the rendering of the UI happens later. - // - ImGUI_UpdateIO(); - ImGui::NewFrame(); + // Animation Update + if (m_bPlay) + m_time += (float)m_deltaTime / 1000.0f; // animation time in seconds - static int cameraControlSelected = 1; - static int loadingStage = 0; - if (loadingStage >= 0) + if (m_pGltfLoader) { - // LoadScene needs to be called a number of times, the scene is not fully loaded until it returns -1 - // This is done so we can display a progress bar when the scene is loading - if (m_pGltfLoader == NULL) - { - m_pGltfLoader = new GLTFCommon(); - m_pGltfLoader->Load("..\\media\\campfire\\", "Campfire_scene_groundscaled.gltf"); - } - - loadingStage = m_Node->LoadScene(m_pGltfLoader, loadingStage); + m_pGltfLoader->SetAnimationTime(0, m_time); + m_pGltfLoader->TransformScene(0, math::Matrix4::identity()); } - else - { - ImGuiStyle& style = ImGui::GetStyle(); - style.FrameBorderSize = 1.0f; +} +void LPMSample::HandleInput(const ImGuiIO& io) +{ + auto fnIsKeyTriggered = [&io](char key) { return io.KeysDown[key] && io.KeysDownDuration[key] == 0.0f; }; - bool opened = true; - ImGui::Begin("Stats", &opened); + // Handle Keyboard/Mouse input here - if (ImGui::CollapsingHeader("Info", ImGuiTreeNodeFlags_DefaultOpen)) - { - ImGui::Text("Resolution : %ix%i", m_Width, m_Height); - const std::vector timeStamps = m_Node->GetTimingValues(); - if (timeStamps.size() > 0) - { - static float values[128]; - values[127] = (float)(timeStamps.back().m_microseconds - timeStamps.front().m_microseconds); - float average = values[0]; - for (int i = 0; i < 128 - 1; i++) { values[i] = values[i + 1]; average += values[i]; } - average /= 128; - - ImGui::Text("%-17s:%7.1f FPS", "Framerate", (1.0f / average) * 1000000.0f); - } - } + /* MAGNIFIER CONTROLS */ + if (fnIsKeyTriggered('L')) m_UIState.ToggleMagnifierLock(); + if (fnIsKeyTriggered('M') || io.MouseClicked[2]) ToggleBool(m_UIState.bUseMagnifier); // middle mouse / M key toggles magnifier - if (ImGui::CollapsingHeader("Scene Setup", ImGuiTreeNodeFlags_DefaultOpen)) - { - static float exposureStep = 0.0f; - ImGui::SliderFloat("Exposure", &exposureStep, -4.0f, +1.0f, NULL, 1.0f); - m_state.exposure = (float)pow(2, exposureStep); - ImGui::SliderFloat("Emmisive", &m_state.emmisiveFactor, 0.0f, 2.0f, NULL, 1.0f); - ImGui::SliderFloat("PointLightIntensity", &m_state.lightIntensity, 0.0f, 20.0f); - - const char * tonemappers[] = { "Timothy", "DX11DSK", "Reinhard", "Uncharted2Tonemap", "ACES", "No tonemapper", "FidelityFX LPM" }; - ImGui::Combo("Tone mapper", &m_state.toneMapper, tonemappers, _countof(tonemappers)); - - static bool openWarning = false; - - const char **displayModeNames = &m_displayModesNamesAvailable[0]; - if (ImGui::Combo("Display Mode", (int *)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) - { - if (m_swapChain.IsFullScreen()) - { - m_previousDisplayMode = m_currentDisplayMode = m_displayModesAvailable[m_currentDisplayModeNamesIndex]; - m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; - OnResize(m_Width, m_Height); - } - else - { - openWarning = true; - m_previousDisplayMode = m_currentDisplayMode = DisplayModes::DISPLAYMODE_SDR; - m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DisplayModes::DISPLAYMODE_SDR; - } - } - - if (openWarning) - { - ImGui::OpenPopup("Display Modes Warning"); - ImGui::BeginPopupModal("Display Modes Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize); - ImGui::Text("\nChanging display modes is only available in fullscreen, please press ALT + ENTER for fun!\n\n"); - if (ImGui::Button("Cancel", ImVec2(120, 0))) { openWarning = false; ImGui::CloseCurrentPopup(); } - ImGui::EndPopup(); - } - - if (m_currentDisplayMode == DisplayModes::DISPLAYMODE_FSHDR_Gamma22 || m_currentDisplayMode == DisplayModes::DISPLAYMODE_FSHDR_SCRGB) - { - if (ImGui::Checkbox("Enable Local Dimming", &m_enableLocalDimming)) - { - OnLocalDimmingChanged(); - } - } - - const char * testPatterns[] = { "None", "Luxo Double Checker", "DCI P3 1000 Nits", "REC 2020 1000 Nits", "Rec 709 5000 Nits" }; - if (ImGui::Combo("Test Patterns", &m_state.testPattern, testPatterns, _countof(testPatterns))) - { - if (m_state.testPattern == 2) // P3 - m_state.colorSpace = ColorSpace::ColorSpace_P3; - else if (m_state.testPattern == 3) // rec2020 - m_state.colorSpace = ColorSpace::ColorSpace_REC2020; - else // Rec 709 - m_state.colorSpace = ColorSpace::ColorSpace_REC709; - - // Flush GPU - // - m_device.GPUFlush(); - - if (m_Node != NULL) - { - m_Node->OnDestroyWindowSizeDependentResources(); - m_Node->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height, &m_state); - } - } - - const char * cameraControl[] = { "WASD", "Orbit" }; - ImGui::Combo("Camera", &cameraControlSelected, cameraControl, _countof(cameraControl)); - } + if (io.MouseClicked[1] && m_UIState.bUseMagnifier) // right mouse click + m_UIState.ToggleMagnifierLock(); + + if (fnIsKeyTriggered('R')) + m_UIState.ResetLPMSceneDefaults(); +} +void LPMSample::UpdateCamera(Camera& cam, const ImGuiIO& io) +{ + float yaw = cam.GetYaw(); + float pitch = cam.GetPitch(); + float distance = cam.GetDistance(); + + cam.UpdatePreviousMatrices(); // set previous view matrix - ImGui::End(); + // Sets Camera based on UI selection (WASD, Orbit or any of the GLTF cameras) + if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) + { + yaw -= io.MouseDelta.x / 100.f; + pitch += io.MouseDelta.y / 100.f; } - // If the mouse was not used by the GUI then it's for the camera - // - ImGuiIO& io = ImGui::GetIO(); - if (io.WantCaptureMouse == false) + // Choose camera movement depending on setting + if (m_activeCamera == 0) { - float yaw = m_state.camera.GetYaw(); - float pitch = m_state.camera.GetPitch(); - float distance = m_state.camera.GetDistance(); + // Orbiting + distance -= (float)io.MouseWheel / 3.0f; + distance = std::max(distance, 0.1f); - if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) - { - yaw -= io.MouseDelta.x / 100.f; - pitch += io.MouseDelta.y / 100.f; - } + bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); - // Choose camera movement depending on setting - // + cam.UpdateCameraPolar(yaw, pitch, + panning ? -io.MouseDelta.x / 100.0f : 0.0f, + panning ? io.MouseDelta.y / 100.0f : 0.0f, + distance); + } + else if (m_activeCamera == 1) + { + // WASD + cam.UpdateCameraWASD(yaw, pitch, io.KeysDown, io.DeltaTime); + } + else if (m_activeCamera > 1) + { + // Use a camera from the GLTF + m_pGltfLoader->GetCamera(m_activeCamera - 2, &cam); + } +} - if (cameraControlSelected == 0) - { - // WASD - // - m_state.camera.UpdateCameraWASD(yaw, pitch, io.KeysDown, io.DeltaTime); - } - else - { - // Orbiting - // - distance -= (float)io.MouseWheel / 3.0f; - distance = std::max(distance, 0.1f); +//-------------------------------------------------------------------------------------- +// +// OnRender +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnRender() +{ + // Do any start of frame necessities + BeginFrame(); - bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); + ImGUI_UpdateIO(); + ImGui::NewFrame(); - m_state.camera.UpdateCameraPolar(yaw, pitch, panning ? -io.MouseDelta.x / 100.0f : 0.0f, panning ? io.MouseDelta.y / 100.0f : 0.0f, distance); + if (m_loadingScene) + { + // the scene loads in chunks, that way we can show a progress bar + static int loadingStage = 0; + loadingStage = m_pRenderer->LoadScene(m_pGltfLoader, loadingStage); + if (loadingStage == 0) + { + m_time = 0; + m_loadingScene = false; } } - - // Set animation time - // - if (m_bPlay) + else if (m_pGltfLoader && m_bIsBenchmarking) { - m_time += (float)m_deltaTime / 1000.0f; + // Benchmarking takes control of the time, and exits the app when the animation is done + std::vector timeStamps = m_pRenderer->GetTimingValues(); + std::string DummyFileName; // Cauldron_VK doesn't support 'SaveTexture' yet. + m_time = BenchmarkLoop(timeStamps, &m_camera, DummyFileName); } - - // transform scene - // - if (m_pGltfLoader) + else { - m_pGltfLoader->SetAnimationTime(0, m_time); - m_pGltfLoader->TransformScene(0, XMMatrixIdentity()); + BuildUI(); // UI logic. Note that the rendering of the UI happens later. + OnUpdate(); // Update camera, handle keyboard/mouse input } - m_state.time = m_time; - - // Do Render frame using AFR - // - m_Node->OnRender(&m_state, &m_swapChain); + // Do Render frame using AFR + m_pRenderer->OnRender(&m_UIState, m_camera, &m_swapChain, m_time); - m_swapChain.Present(); + // Framework will handle Present and some other end of frame logic + EndFrame(); } @@ -432,7 +449,7 @@ int WINAPI WinMain(HINSTANCE hInstance, LPSTR lpCmdLine, int nCmdShow) { - LPCSTR Name = "LPMSample VK v1.0"; + LPCSTR Name = "LPMSample VK v1.2"; // create new Vulkan sample return RunFramework(hInstance, lpCmdLine, nCmdShow, new LPMSample(Name)); diff --git a/sample/src/VK/LPMSample.h b/sample/src/VK/LPMSample.h index 54613a8..b2e1af2 100644 --- a/sample/src/VK/LPMSample.h +++ b/sample/src/VK/LPMSample.h @@ -18,63 +18,52 @@ // THE SOFTWARE. #pragma once +#include "base/FrameworkWindows.h" +#include "Renderer.h" +#include "UI.h" -#include "SampleRenderer.h" - - -// -// This is the main class, it manages the state of the sample and does all the high level work without touching the GPU directly. -// This class uses the GPU via the the SampleRenderer class. We would have a SampleRenderer instance for each GPU. -// -// This class takes care of: -// -// - loading a scene (just the CPU data) -// - updating the camera -// - keeping track of time -// - handling the keyboard -// - updating the animation -// - building the UI (but do not renders it) -// - uses the SampleRenderer to update all the state to the GPU and do the rendering -// +// This class encapsulates the 'application' and is responsible for handling window events and scene updates (simulation) +// Rendering and rendering resource management is done by the Renderer class class LPMSample : public FrameworkWindows { public: LPMSample(LPCSTR name); - void OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight, bool* pbFullScreen); - void OnCreate(HWND hWnd); - void OnDestroy(); - void OnRender(); - bool OnEvent(MSG msg); - void OnResize(uint32_t Width, uint32_t Height); - void OnLocalDimmingChanged(); - void OnActivate(bool windowActive); - void SetFullScreen(bool fullscreen); + void OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight) override; + void OnCreate() override; + void OnDestroy() override; + void OnRender() override; + bool OnEvent(MSG msg) override; + void OnResize() override; + void OnUpdateDisplay() override; -private: + void BuildUI(); + void LoadScene(int sceneIndex); - Device m_device; - SwapChain m_swapChain; + void OnUpdate(); + + void HandleInput(const ImGuiIO& io); + void UpdateCamera(Camera& cam, const ImGuiIO& io); + +private: - DisplayModes m_previousDisplayMode; - DisplayModes m_currentDisplayMode; - DisplayModes m_previousDisplayModeNamesIndex; - DisplayModes m_currentDisplayModeNamesIndex; - std::vector m_displayModesAvailable; - std::vector m_displayModesNamesAvailable; - bool m_enableLocalDimming; + bool m_bIsBenchmarking; - GLTFCommon *m_pGltfLoader; + GLTFCommon *m_pGltfLoader = NULL; + bool m_loadingScene = false; - SampleRenderer *m_Node; - SampleRenderer::State m_state; + Renderer *m_pRenderer = NULL; + UIState m_UIState; + float m_fontSize; + Camera m_camera; - float m_time; - double m_deltaTime; // The elapsed time in milliseconds since the previous frame. - double m_lastFrameTime; + float m_time; // Time accumulator in seconds, used for animation. - bool m_isCpuValidationLayerEnabled = false; - bool m_isGpuValidationLayerEnabled = false; + // json config file + json m_jsonConfigFile; + std::vector m_sceneNames; + int m_activeScene; + int m_activeCamera; - bool m_bPlay; -}; \ No newline at end of file + bool m_bPlay; +}; diff --git a/sample/src/VK/Renderer.cpp b/sample/src/VK/Renderer.cpp new file mode 100644 index 0000000..1025964 --- /dev/null +++ b/sample/src/VK/Renderer.cpp @@ -0,0 +1,1026 @@ +// AMD LPMSample sample code +// +// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "Renderer.h" +#include "UI.h" + + +//-------------------------------------------------------------------------------------- +// +// OnCreate +// +//-------------------------------------------------------------------------------------- +void Renderer::OnCreate(Device* pDevice, SwapChain* pSwapChain, float fontSize) +{ + m_pDevice = pDevice; + + // Initialize helpers + + // Create all the heaps for the resources views + const uint32_t cbvDescriptorCount = 2000; + const uint32_t srvDescriptorCount = 8000; + const uint32_t uavDescriptorCount = 10; + const uint32_t samplerDescriptorCount = 20; + m_resourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, samplerDescriptorCount); + + // Create a commandlist ring for the Direct queue + uint32_t commandListsPerBackBuffer = 8; + m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer); + + // Create a 'dynamic' constant buffer + const uint32_t constantBuffersMemSize = 200 * 1024 * 1024; + m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, "Uniforms"); + + // Create a 'static' pool for vertices and indices + const uint32_t staticGeometryMemSize = (1 * 128) * 1024 * 1024; + m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, true, "StaticGeom"); + + // Create a 'static' pool for vertices and indices in system memory + const uint32_t systemGeometryMemSize = 32 * 1024; + m_SysMemBufferPool.OnCreate(pDevice, systemGeometryMemSize, false, "PostProcGeom"); + + // initialize the GPU time stamps module + m_GPUTimer.OnCreate(pDevice, backBufferCount); + + // Quick helper to upload resources, it has it's own commandList and uses suballocation. + // for 4K textures we'll need 100Megs + const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024; + m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results) + + // Create GBuffer and render passes + // + { + m_GBuffer.OnCreate( + pDevice, + &m_resourceViewHeaps, + { + { GBUFFER_DEPTH, VK_FORMAT_D32_SFLOAT}, + { GBUFFER_FORWARD, VK_FORMAT_R16G16B16A16_SFLOAT}, + }, + 1 + ); + + GBufferFlags fullGBuffer = GBUFFER_DEPTH | GBUFFER_FORWARD; + bool bClear = true; + m_renderPassFullGBufferWithClear.OnCreate(&m_GBuffer, fullGBuffer, bClear,"m_renderPassFullGBufferWithClear"); + m_renderPassFullGBuffer.OnCreate(&m_GBuffer, fullGBuffer, !bClear, "m_renderPassFullGBuffer"); + m_renderPassJustDepthAndHdr.OnCreate(&m_GBuffer, GBUFFER_DEPTH | GBUFFER_FORWARD, !bClear, "m_renderPassJustDepthAndHdr"); + } + + // Create render pass shadow, will clear contents + // + { + VkAttachmentDescription depthAttachments; + AttachClearBeforeUse(VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &depthAttachments); + m_render_pass_shadow = CreateRenderPassOptimal(m_pDevice->GetDevice(), 0, NULL, &depthAttachments); + } + + m_downSample.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); + m_bloom.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); + m_magnifierPS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); + + // Create tonemapping pass + m_toneMappingCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); + m_toneMappingPS.OnCreate(m_pDevice, pSwapChain->GetRenderPass(), &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); + m_colorConversionPS.OnCreate(pDevice, pSwapChain->GetRenderPass(), &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); + + // Initialize UI rendering resources + m_ImGUI.OnCreate(m_pDevice, m_renderPassJustDepthAndHdr.GetRenderPass(), &m_UploadHeap, &m_ConstantBufferRing, fontSize); + + math::Matrix4 campfireWorldMatrix = math::Matrix4(math::Vector4(0.5f, 0.0f, 0.0f, 0.0f), + math::Vector4(0.0f, 0.5f, 0.0f, 0.0f), + math::Vector4(0.0f, 0.0f, 0.5f, 0.0f), + math::Vector4(-47.3f, -26.5f, -40.425f, 1.0f)); + m_CampfireAnimation.OnCreate(pDevice, m_renderPassFullGBufferWithClear.GetRenderPass(), &m_UploadHeap, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_SAMPLE_COUNT_1_BIT, 12, 12, "..\\media\\FlipBookAnimationTextures\\cf_loop_comp_v1_mosaic.png", campfireWorldMatrix); + // Create test pattern render pass + { + m_render_pass_TestPattern = SimpleColorWriteRenderPass(m_pDevice->GetDevice(), VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL); + } + m_testImages.OnCreate(pDevice, m_render_pass_TestPattern, &m_UploadHeap, &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); + + // Create tonemapping pass + m_exposureMultiplierCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); + m_lpmPS.OnCreate(pDevice, pSwapChain->GetRenderPass(), &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); + + // Make sure upload heap has finished uploading before continuing + m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); + m_UploadHeap.FlushAndFinish(); +} + +//-------------------------------------------------------------------------------------- +// +// OnDestroy +// +//-------------------------------------------------------------------------------------- +void Renderer::OnDestroy() +{ + m_lpmPS.OnDestroy(); + m_exposureMultiplierCS.OnDestroy(); + m_testImages.OnDestroy(); + vkDestroyRenderPass(m_pDevice->GetDevice(), m_render_pass_TestPattern, nullptr); + m_CampfireAnimation.OnDestroy(); + + m_asyncPool.Flush(); + + m_ImGUI.OnDestroy(); + m_colorConversionPS.OnDestroy(); + m_toneMappingPS.OnDestroy(); + m_toneMappingCS.OnDestroy(); + m_bloom.OnDestroy(); + m_downSample.OnDestroy(); + m_magnifierPS.OnDestroy(); + + m_renderPassFullGBufferWithClear.OnDestroy(); + m_renderPassJustDepthAndHdr.OnDestroy(); + m_renderPassFullGBuffer.OnDestroy(); + m_GBuffer.OnDestroy(); + + vkDestroyRenderPass(m_pDevice->GetDevice(), m_render_pass_shadow, nullptr); + + m_UploadHeap.OnDestroy(); + m_GPUTimer.OnDestroy(); + m_VidMemBufferPool.OnDestroy(); + m_SysMemBufferPool.OnDestroy(); + m_ConstantBufferRing.OnDestroy(); + m_resourceViewHeaps.OnDestroy(); + m_CommandListRing.OnDestroy(); +} + +//-------------------------------------------------------------------------------------- +// +// OnCreateWindowSizeDependentResources +// +//-------------------------------------------------------------------------------------- +void Renderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height) +{ + m_Width = Width; + m_Height = Height; + + // Set the viewport + // + m_viewport.x = 0; + m_viewport.y = (float)Height; + m_viewport.width = (float)Width; + m_viewport.height = -(float)(Height); + m_viewport.minDepth = (float)0.0f; + m_viewport.maxDepth = (float)1.0f; + + // Create scissor rectangle + // + m_rectScissor.extent.width = Width; + m_rectScissor.extent.height = Height; + m_rectScissor.offset.x = 0; + m_rectScissor.offset.y = 0; + + // Create GBuffer + // + m_GBuffer.OnCreateWindowSizeDependentResources(pSwapChain, Width, Height); + + // Create frame buffers for the GBuffer render passes + // + m_renderPassFullGBufferWithClear.OnCreateWindowSizeDependentResources(Width, Height); + m_renderPassJustDepthAndHdr.OnCreateWindowSizeDependentResources(Width, Height); + m_renderPassFullGBuffer.OnCreateWindowSizeDependentResources(Width, Height); + + // Update PostProcessing passes + // + m_downSample.OnCreateWindowSizeDependentResources(Width, Height, &m_GBuffer.m_HDR, 6); //downsample the HDR texture 6 times + m_bloom.OnCreateWindowSizeDependentResources(Width / 2, Height / 2, m_downSample.GetTexture(), 6, &m_GBuffer.m_HDR); + m_magnifierPS.OnCreateWindowSizeDependentResources(&m_GBuffer.m_HDR); + + // Create test pasttern framebuffer + std::vector pAttachments; + pAttachments.push_back(m_GBuffer.m_HDRSRV); + m_pFrameBuffer_TestPattern = CreateFrameBuffer(m_pDevice->GetDevice(), m_render_pass_TestPattern, &pAttachments, Width, Height); +} + +//-------------------------------------------------------------------------------------- +// +// OnDestroyWindowSizeDependentResources +// +//-------------------------------------------------------------------------------------- +void Renderer::OnDestroyWindowSizeDependentResources() +{ + vkDestroyFramebuffer(m_pDevice->GetDevice(), m_pFrameBuffer_TestPattern, nullptr); + + m_bloom.OnDestroyWindowSizeDependentResources(); + m_downSample.OnDestroyWindowSizeDependentResources(); + m_magnifierPS.OnDestroyWindowSizeDependentResources(); + + m_renderPassFullGBufferWithClear.OnDestroyWindowSizeDependentResources(); + m_renderPassJustDepthAndHdr.OnDestroyWindowSizeDependentResources(); + m_renderPassFullGBuffer.OnDestroyWindowSizeDependentResources(); + m_GBuffer.OnDestroyWindowSizeDependentResources(); +} + +//-------------------------------------------------------------------------------------- +// +// OnUpdateDisplayDependentResources +// +//-------------------------------------------------------------------------------------- +void Renderer::OnUpdateDisplayDependentResources(SwapChain* pSwapChain, const UIState* pState) +{ + // update the pipelines if the swapchain render pass has changed (for example when the format of the swapchain changes) + // + m_toneMappingPS.UpdatePipelines(pSwapChain->GetRenderPass()); + OnUpdateLocalDimmingChangedResources(pSwapChain, pState); +} + +//-------------------------------------------------------------------------------------- +// +// OnUpdateLocalDimmingChangedResources +// +//-------------------------------------------------------------------------------------- +void Renderer::OnUpdateLocalDimmingChangedResources(SwapChain *pSwapChain, const UIState* pState) +{ + m_colorConversionPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode()); + m_lpmPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode(), pState->ColorSpace, + pState->bShoulder, + pState->SoftGap, + pState->HdrMax, + pState->LpmExposure, + pState->Contrast, + pState->ShoulderContrast, + (float *) pState->Saturation, + (float *) pState->Crosstalk); +} + +//-------------------------------------------------------------------------------------- +// +// LoadScene +// +//-------------------------------------------------------------------------------------- +int Renderer::LoadScene(GLTFCommon *pGLTFCommon, int stage) +{ + // show loading progress + // + ImGui::OpenPopup("Loading"); + if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize)) + { + float progress = (float)stage / 10.0f; + ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL); + ImGui::EndPopup(); + } + + // use multi threading + AsyncPool *pAsyncPool = &m_asyncPool; + + // Loading stages + // + if (stage == 0) + { + } + else if (stage == 5) + { + Profile p("m_pGltfLoader->Load"); + + m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers(); + m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing); + } + else if (stage == 6) + { + Profile p("LoadTextures"); + + // here we are loading onto the GPU all the textures and the inverse matrices + // this data will be used to create the PBR and Depth passes + m_pGLTFTexturesAndBuffers->LoadTextures(pAsyncPool); + } + else if (stage == 7) + { + Profile p("m_gltfDepth->OnCreate"); + + //create the glTF's textures, VBs, IBs, shaders and descriptors for this particular pass + m_gltfDepth = new GltfDepthPass(); + m_gltfDepth->OnCreate( + m_pDevice, + m_render_pass_shadow, + &m_UploadHeap, + &m_resourceViewHeaps, + &m_ConstantBufferRing, + &m_VidMemBufferPool, + m_pGLTFTexturesAndBuffers, + pAsyncPool + ); + + m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); + m_UploadHeap.FlushAndFinish(); + } + else if (stage == 8) + { + Profile p("m_gltfPBR->OnCreate"); + + // same thing as above but for the PBR pass + m_gltfPBR = new GltfPbrPass(); + m_gltfPBR->OnCreate( + m_pDevice, + &m_UploadHeap, + &m_resourceViewHeaps, + &m_ConstantBufferRing, + &m_VidMemBufferPool, + m_pGLTFTexturesAndBuffers, + nullptr, + false, // use SSAO mask + m_ShadowSRVPool, + &m_renderPassFullGBufferWithClear, + pAsyncPool + ); + + m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); + } + else if (stage == 9) + { + Profile p("Flush"); + + m_UploadHeap.FlushAndFinish(); + + //once everything is uploaded we dont need the upload heaps anymore + m_VidMemBufferPool.FreeUploadHeap(); + + // tell caller that we are done loading the map + return 0; + } + + stage++; + return stage; +} + +//-------------------------------------------------------------------------------------- +// +// UnloadScene +// +//-------------------------------------------------------------------------------------- +void Renderer::UnloadScene() +{ + // wait for all the async loading operations to finish + m_asyncPool.Flush(); + + m_pDevice->GPUFlush(); + + if (m_gltfPBR) + { + m_gltfPBR->OnDestroy(); + delete m_gltfPBR; + m_gltfPBR = NULL; + } + + if (m_gltfDepth) + { + m_gltfDepth->OnDestroy(); + delete m_gltfDepth; + m_gltfDepth = NULL; + } + + if (m_pGLTFTexturesAndBuffers) + { + m_pGLTFTexturesAndBuffers->OnDestroy(); + delete m_pGLTFTexturesAndBuffers; + m_pGLTFTexturesAndBuffers = NULL; + } + + assert(m_shadowMapPool.size() == m_ShadowSRVPool.size()); + while (!m_shadowMapPool.empty()) + { + m_shadowMapPool.back().ShadowMap.OnDestroy(); + vkDestroyFramebuffer(m_pDevice->GetDevice(), m_shadowMapPool.back().ShadowFrameBuffer, nullptr); + vkDestroyImageView(m_pDevice->GetDevice(), m_ShadowSRVPool.back(), nullptr); + vkDestroyImageView(m_pDevice->GetDevice(), m_shadowMapPool.back().ShadowDSV, nullptr); + m_ShadowSRVPool.pop_back(); + m_shadowMapPool.pop_back(); + } +} + +void Renderer::AllocateShadowMaps(GLTFCommon* pGLTFCommon) +{ + // Go through the lights and allocate shadow information + uint32_t NumShadows = 0; + for (int i = 0; i < pGLTFCommon->m_lightInstances.size(); ++i) + { + const tfLight& lightData = pGLTFCommon->m_lights[pGLTFCommon->m_lightInstances[i].m_lightId]; + if (lightData.m_shadowResolution) + { + SceneShadowInfo ShadowInfo; + ShadowInfo.ShadowResolution = lightData.m_shadowResolution; + ShadowInfo.ShadowIndex = NumShadows++; + ShadowInfo.LightIndex = i; + m_shadowMapPool.push_back(ShadowInfo); + } + } + + if (NumShadows > MaxShadowInstances) + { + Trace("Number of shadows has exceeded maximum supported. Please grow value in gltfCommon.h/perFrameStruct.h"); + throw; + } + + // If we had shadow information, allocate all required maps and bindings + if (!m_shadowMapPool.empty()) + { + std::vector::iterator CurrentShadow = m_shadowMapPool.begin(); + for (uint32_t i = 0; CurrentShadow < m_shadowMapPool.end(); ++i, ++CurrentShadow) + { + CurrentShadow->ShadowMap.InitDepthStencil(m_pDevice, CurrentShadow->ShadowResolution, CurrentShadow->ShadowResolution, VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, "ShadowMap"); + CurrentShadow->ShadowMap.CreateDSV(&CurrentShadow->ShadowDSV); + + // Create render pass shadow, will clear contents + { + VkAttachmentDescription depthAttachments; + AttachClearBeforeUse(VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, VK_IMAGE_LAYOUT_UNDEFINED, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL, &depthAttachments); + + // Create frame buffer + VkImageView attachmentViews[1] = { CurrentShadow->ShadowDSV }; + VkFramebufferCreateInfo fb_info = {}; + fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; + fb_info.pNext = NULL; + fb_info.renderPass = m_render_pass_shadow; + fb_info.attachmentCount = 1; + fb_info.pAttachments = attachmentViews; + fb_info.width = CurrentShadow->ShadowResolution; + fb_info.height = CurrentShadow->ShadowResolution; + fb_info.layers = 1; + VkResult res = vkCreateFramebuffer(m_pDevice->GetDevice(), &fb_info, NULL, &CurrentShadow->ShadowFrameBuffer); + assert(res == VK_SUCCESS); + } + + VkImageView ShadowSRV; + CurrentShadow->ShadowMap.CreateSRV(&ShadowSRV); + m_ShadowSRVPool.push_back(ShadowSRV); + } + } +} + +//-------------------------------------------------------------------------------------- +// +// OnRender +// +//-------------------------------------------------------------------------------------- +void Renderer::OnRender(const UIState* pState, const Camera& cam, SwapChain* pSwapChain, float time) +{ + // Let our resource managers do some house keeping + m_ConstantBufferRing.OnBeginFrame(); + + // command buffer calls + VkCommandBuffer cmdBuf1 = m_CommandListRing.GetNewCommandList(); + + { + VkCommandBufferBeginInfo cmd_buf_info; + cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmd_buf_info.pNext = NULL; + cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmd_buf_info.pInheritanceInfo = NULL; + VkResult res = vkBeginCommandBuffer(cmdBuf1, &cmd_buf_info); + assert(res == VK_SUCCESS); + } + + m_GPUTimer.OnBeginFrame(cmdBuf1, &m_TimeStamps); + + // Sets the perFrame data + per_frame *pPerFrame = NULL; + if (m_pGLTFTexturesAndBuffers) + { + // fill as much as possible using the GLTF (camera, lights, ...) + pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(cam); + + // Set some lighting factors + pPerFrame->emmisiveFactor = pState->EmissiveFactor; + pPerFrame->invScreenResolution[0] = 1.0f / ((float)m_Width); + pPerFrame->invScreenResolution[1] = 1.0f / ((float)m_Height); + + m_pGLTFTexturesAndBuffers->SetPerFrameConstants(); + m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons(); + } + + // Render all shadow maps + if (m_gltfDepth && pPerFrame != NULL) + { + SetPerfMarkerBegin(cmdBuf1, "ShadowPass"); + + VkClearValue depth_clear_values[1]; + depth_clear_values[0].depthStencil.depth = 1.0f; + depth_clear_values[0].depthStencil.stencil = 0; + + VkRenderPassBeginInfo rp_begin; + rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin.pNext = NULL; + rp_begin.renderPass = m_render_pass_shadow; + rp_begin.renderArea.offset.x = 0; + rp_begin.renderArea.offset.y = 0; + rp_begin.clearValueCount = 1; + rp_begin.pClearValues = depth_clear_values; + + std::vector::iterator ShadowMap = m_shadowMapPool.begin(); + while (ShadowMap < m_shadowMapPool.end()) + { + // Clear shadow map + rp_begin.framebuffer = ShadowMap->ShadowFrameBuffer; + rp_begin.renderArea.extent.width = ShadowMap->ShadowResolution; + rp_begin.renderArea.extent.height = ShadowMap->ShadowResolution; + vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); + + // Render to shadow map + SetViewportAndScissor(cmdBuf1, 0, 0, ShadowMap->ShadowResolution, ShadowMap->ShadowResolution); + + // Set per frame constant buffer values + GltfDepthPass::per_frame* cbPerFrame = m_gltfDepth->SetPerFrameConstants(); + cbPerFrame->mViewProj = pPerFrame->lights[ShadowMap->LightIndex].mLightViewProj; + + m_gltfDepth->Draw(cmdBuf1); + + m_GPUTimer.GetTimeStamp(cmdBuf1, "Shadow Map Render"); + + vkCmdEndRenderPass(cmdBuf1); + ++ShadowMap; + } + + SetPerfMarkerEnd(cmdBuf1); + } + + // Render Scene to the GBuffer ------------------------------------------------ + SetPerfMarkerBegin(cmdBuf1, "Color pass"); + + VkRect2D renderArea = { 0, 0, m_Width, m_Height }; + + if (pPerFrame != NULL && m_gltfPBR) + { + std::vector opaque, transparent; + m_gltfPBR->BuildBatchLists(&opaque, &transparent); + + // Render opaque + { + m_renderPassFullGBufferWithClear.BeginPass(cmdBuf1, renderArea); + + m_gltfPBR->DrawBatchList(cmdBuf1, &opaque); + m_GPUTimer.GetTimeStamp(cmdBuf1, "PBR Opaque"); + + // Draw campfire + m_CampfireAnimation.Draw(cmdBuf1, time, cam.GetPosition(), cam.GetProjection() * cam.GetView()); + + m_renderPassFullGBufferWithClear.EndPass(cmdBuf1); + } + + // draw transparent geometry + { + m_renderPassFullGBuffer.BeginPass(cmdBuf1, renderArea); + + std::sort(transparent.begin(), transparent.end()); + m_gltfPBR->DrawBatchList(cmdBuf1, &transparent); + m_GPUTimer.GetTimeStamp(cmdBuf1, "PBR Transparent"); + + //m_GBuffer.EndPass(cmdBuf1); + m_renderPassFullGBuffer.EndPass(cmdBuf1); + } + } + else + { + m_renderPassFullGBufferWithClear.BeginPass(cmdBuf1, renderArea); + m_renderPassFullGBufferWithClear.EndPass(cmdBuf1); + m_renderPassJustDepthAndHdr.BeginPass(cmdBuf1, renderArea); + m_renderPassJustDepthAndHdr.EndPass(cmdBuf1); + } + + VkImageMemoryBarrier barrier[1] = {}; + barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier[0].pNext = NULL; + barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier[0].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier[0].subresourceRange.baseMipLevel = 0; + barrier[0].subresourceRange.levelCount = 1; + barrier[0].subresourceRange.baseArrayLayer = 0; + barrier[0].subresourceRange.layerCount = 1; + barrier[0].image = m_GBuffer.m_HDR.Resource(); + 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); + + SetPerfMarkerEnd(cmdBuf1); + + // Post proc--------------------------------------------------------------------------- + + // Bloom, takes HDR as input and applies bloom to it. + { + SetPerfMarkerBegin(cmdBuf1, "PostProcess"); + + // Downsample pass + m_downSample.Draw(cmdBuf1); + // m_downSample.Gui(); + m_GPUTimer.GetTimeStamp(cmdBuf1, "Downsample"); + + // Bloom pass (needs the downsampled data) + m_bloom.Draw(cmdBuf1); + // m_bloom.Gui(); + m_GPUTimer.GetTimeStamp(cmdBuf1, "Bloom"); + + SetPerfMarkerEnd(cmdBuf1); + } + + barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier[0].pNext = NULL; + barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; + barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier[0].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier[0].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier[0].subresourceRange.baseMipLevel = 0; + barrier[0].subresourceRange.levelCount = 1; + barrier[0].subresourceRange.baseArrayLayer = 0; + barrier[0].subresourceRange.layerCount = 1; + barrier[0].image = m_GBuffer.m_HDR.Resource(); + 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); + + // Render TestPattern ------------------------------------------------------------------------ + // + { + SetPerfMarkerBegin(cmdBuf1, "TestPattern"); + + // prepare render pass + { + VkRenderPassBeginInfo rp_begin = {}; + rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin.pNext = NULL; + rp_begin.renderPass = m_render_pass_TestPattern; + rp_begin.framebuffer = m_pFrameBuffer_TestPattern; + rp_begin.renderArea.offset.x = 0; + rp_begin.renderArea.offset.y = 0; + rp_begin.renderArea.extent.width = m_Width; + rp_begin.renderArea.extent.height = m_Height; + rp_begin.clearValueCount = 0; + rp_begin.pClearValues = NULL; + vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); + } + + vkCmdSetScissor(cmdBuf1, 0, 1, &m_rectScissor); + vkCmdSetViewport(cmdBuf1, 0, 1, &m_viewport); + + if (pState->TestPattern) + { + m_testImages.Draw(cmdBuf1, pState->TestPattern); + } + + vkCmdEndRenderPass(cmdBuf1); + + m_GPUTimer.GetTimeStamp(cmdBuf1, "TestPattern"); + + SetPerfMarkerEnd(cmdBuf1); + } + + // Apply Exposure ------------------------------------------------------------------------ + // + { + SetPerfMarkerBegin(cmdBuf1, "Exposure Multiplier"); + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = NULL; + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; // we need to read from it for the post-processing + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.image = m_GBuffer.m_HDR.Resource(); + vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + } + + m_exposureMultiplierCS.Draw(cmdBuf1, m_GBuffer.m_HDRSRV, pState->Exposure, m_Width, m_Height); + + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = NULL; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.image = m_GBuffer.m_HDR.Resource(); + vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + } + + m_GPUTimer.GetTimeStamp(cmdBuf1, "Exposure Multiplier"); + + SetPerfMarkerEnd(cmdBuf1); + } + + // Render HUD ------------------------------------------------------------------------ + // + { + SetPerfMarkerBegin(cmdBuf1, "ImGUI Rendering"); + + // prepare render pass + { + VkRenderPassBeginInfo rp_begin = {}; + rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin.pNext = NULL; + rp_begin.renderPass = m_renderPassJustDepthAndHdr.GetRenderPass(); + rp_begin.framebuffer = m_renderPassJustDepthAndHdr.GetFramebuffer(); + rp_begin.renderArea.offset.x = 0; + rp_begin.renderArea.offset.y = 0; + rp_begin.renderArea.extent.width = m_Width; + rp_begin.renderArea.extent.height = m_Height; + rp_begin.clearValueCount = 0; + rp_begin.pClearValues = NULL; + vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); + } + + vkCmdSetScissor(cmdBuf1, 0, 1, &m_rectScissor); + vkCmdSetViewport(cmdBuf1, 0, 1, &m_viewport); + + m_ImGUI.Draw(cmdBuf1); + + vkCmdEndRenderPass(cmdBuf1); + + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = NULL; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // we need to read from it for the post-processing + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.image = m_GBuffer.m_HDR.Resource(); + vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + } + + m_GPUTimer.GetTimeStamp(cmdBuf1, "ImGUI Rendering"); + + SetPerfMarkerEnd(cmdBuf1); + } + + // Magnifier Pass: m_HDR as input, pass' own output + // + if (pState->bUseMagnifier) + { + vkCmdSetScissor(cmdBuf1, 0, 1, &m_rectScissor); + vkCmdSetViewport(cmdBuf1, 0, 1, &m_viewport); + + // Note: assumes m_GBuffer.HDR is in D3D12_RESOURCE_STATE_PIXEL_SHADER_RESOURCE + m_magnifierPS.Draw(cmdBuf1, pState->MagnifierParams); + m_GPUTimer.GetTimeStamp(cmdBuf1, "Magnifier"); + + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = NULL; + barrier.srcAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_DEPTH_READ_ONLY_STENCIL_ATTACHMENT_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.image = m_GBuffer.m_HDR.Resource(); + + VkImageMemoryBarrier barriers[2]; + barriers[0] = barrier; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].image = m_GBuffer.m_HDR.Resource(); + + barriers[1] = barrier; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barriers[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[1].image = m_magnifierPS.GetPassOutputResource(); + + vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, barriers); + + VkImageCopy imageCopyRegion{}; + imageCopyRegion.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageCopyRegion.srcSubresource.layerCount = 1; + imageCopyRegion.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + imageCopyRegion.dstSubresource.layerCount = 1; + imageCopyRegion.extent.width = m_GBuffer.m_HDR.GetWidth(); + imageCopyRegion.extent.height = m_GBuffer.m_HDR.GetHeight(); + imageCopyRegion.extent.depth = 1; + + vkCmdCopyImage(cmdBuf1, m_magnifierPS.GetPassOutputResource(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_GBuffer.m_HDR.Resource(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &imageCopyRegion); + + barriers[0] = barrier; + barriers[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; + barriers[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barriers[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[0].image = m_GBuffer.m_HDR.Resource(); + + barriers[1] = barrier; + barriers[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; + barriers[1].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; + barriers[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barriers[1].image = m_magnifierPS.GetPassOutputResource(); + + vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_TRANSFER_BIT, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, 0, 0, NULL, 0, NULL, 2, barriers); + } + + // If using FreeSync HDR we need to to the tonemapping in-place and then apply the GUI, later we'll apply the color conversion into the swapchain + // + if (pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR && pState->SelectedTonemapperIndex > 0) + { + // In place Tonemapping ------------------------------------------------------------------------ + // + { + SetPerfMarkerBegin(cmdBuf1, "Tonemapping"); + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = NULL; + barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; + barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.image = m_GBuffer.m_HDR.Resource(); + vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + } + + m_toneMappingCS.Draw(cmdBuf1, m_GBuffer.m_HDRSRV, pState->UnusedExposure, pState->SelectedTonemapperIndex - 1, m_Width, m_Height); + + { + VkImageMemoryBarrier barrier = {}; + barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; + barrier.pNext = NULL; + barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; + barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; + barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; + barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // we need to read from it for the post-processing + barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; + barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; + barrier.subresourceRange.baseMipLevel = 0; + barrier.subresourceRange.levelCount = 1; + barrier.subresourceRange.baseArrayLayer = 0; + barrier.subresourceRange.layerCount = 1; + barrier.image = m_GBuffer.m_HDR.Resource(); + vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); + } + + m_GPUTimer.GetTimeStamp(cmdBuf1, "Tonemapping"); + + SetPerfMarkerEnd(cmdBuf1); + } + } + // submit command buffer + { + VkResult res = vkEndCommandBuffer(cmdBuf1); + assert(res == VK_SUCCESS); + + VkSubmitInfo submit_info; + submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info.pNext = NULL; + submit_info.waitSemaphoreCount = 0; + submit_info.pWaitSemaphores = NULL; + submit_info.pWaitDstStageMask = NULL; + submit_info.commandBufferCount = 1; + submit_info.pCommandBuffers = &cmdBuf1; + submit_info.signalSemaphoreCount = 0; + submit_info.pSignalSemaphores = NULL; + res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE); + assert(res == VK_SUCCESS); + } + + // Wait for swapchain (we are going to render to it) ----------------------------------- + // + int imageIndex = pSwapChain->WaitForSwapChain(); + + m_CommandListRing.OnBeginFrame(); + + VkCommandBuffer cmdBuf2 = m_CommandListRing.GetNewCommandList(); + { + VkCommandBufferBeginInfo cmd_buf_info; + cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; + cmd_buf_info.pNext = NULL; + cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; + cmd_buf_info.pInheritanceInfo = NULL; + VkResult res = vkBeginCommandBuffer(cmdBuf2, &cmd_buf_info); + assert(res == VK_SUCCESS); + } + + SetPerfMarkerBegin(cmdBuf2, "rendering to swap chain"); + + // prepare render pass + { + VkRenderPassBeginInfo rp_begin = {}; + rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; + rp_begin.pNext = NULL; + rp_begin.renderPass = pSwapChain->GetRenderPass(); + rp_begin.framebuffer = pSwapChain->GetFramebuffer(imageIndex); + rp_begin.renderArea.offset.x = 0; + rp_begin.renderArea.offset.y = 0; + rp_begin.renderArea.extent.width = m_Width; + rp_begin.renderArea.extent.height = m_Height; + rp_begin.clearValueCount = 0; + rp_begin.pClearValues = NULL; + vkCmdBeginRenderPass(cmdBuf2, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); + } + + vkCmdSetScissor(cmdBuf2, 0, 1, &m_rectScissor); + vkCmdSetViewport(cmdBuf2, 0, 1, &m_viewport); + + // Tonemapping LPM ------------------------------------------------------------------------ + // + if (pState->SelectedTonemapperIndex == 0) + { + m_lpmPS.Draw(cmdBuf2, m_GBuffer.m_HDRSRV); + m_GPUTimer.GetTimeStamp(cmdBuf2, "Tone mapping LPM"); + } + else + { + if (pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR) + { + // FS2 mode! Apply color conversion now. + // + m_colorConversionPS.Draw(cmdBuf2, m_GBuffer.m_HDRSRV); + m_GPUTimer.GetTimeStamp(cmdBuf2, "Color conversion"); + } + else + { + // non FS2 mode, that is SDR, here we apply the tonemapping from the HDR into the swapchain + // + // Tonemapping ------------------------------------------------------------------------ + // + { + m_toneMappingPS.Draw(cmdBuf2, m_GBuffer.m_HDRSRV, pState->UnusedExposure, pState->SelectedTonemapperIndex - 1); + m_GPUTimer.GetTimeStamp(cmdBuf2, "Tone mapping"); + } + } + } + + SetPerfMarkerEnd(cmdBuf2); + + m_GPUTimer.OnEndFrame(); + + vkCmdEndRenderPass(cmdBuf2); + + // Close & Submit the command list ---------------------------------------------------- + // + { + VkResult res = vkEndCommandBuffer(cmdBuf2); + assert(res == VK_SUCCESS); + + VkSemaphore ImageAvailableSemaphore; + VkSemaphore RenderFinishedSemaphores; + VkFence CmdBufExecutedFences; + pSwapChain->GetSemaphores(&ImageAvailableSemaphore, &RenderFinishedSemaphores, &CmdBufExecutedFences); + + VkPipelineStageFlags submitWaitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; + VkSubmitInfo submit_info2; + submit_info2.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; + submit_info2.pNext = NULL; + submit_info2.waitSemaphoreCount = 1; + submit_info2.pWaitSemaphores = &ImageAvailableSemaphore; + submit_info2.pWaitDstStageMask = &submitWaitStage; + submit_info2.commandBufferCount = 1; + submit_info2.pCommandBuffers = &cmdBuf2; + submit_info2.signalSemaphoreCount = 1; + submit_info2.pSignalSemaphores = &RenderFinishedSemaphores; + + res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info2, CmdBufExecutedFences); + assert(res == VK_SUCCESS); + } +} diff --git a/sample/src/VK/Renderer.h b/sample/src/VK/Renderer.h new file mode 100644 index 0000000..5ac7c36 --- /dev/null +++ b/sample/src/VK/Renderer.h @@ -0,0 +1,128 @@ +// AMD LPMSample sample code +// +// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. +#pragma once + +#include "stdafx.h" + +#include "base/GBuffer.h" +#include "PostProc/MagnifierPS.h" + +// We are queuing (backBufferCount + 0.5) frames, so we need to triple buffer the resources that get modified each frame +static const int backBufferCount = 3; + +using namespace CAULDRON_VK; + +struct UIState; + +// +// Renderer class is responsible for rendering resources management and recording command buffers. +class Renderer +{ +public: + + void OnCreate(Device *pDevice, SwapChain *pSwapChain, float fontSize); + void OnDestroy(); + + void OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height); + void OnDestroyWindowSizeDependentResources(); + + void OnUpdateDisplayDependentResources(SwapChain *pSwapChain, const UIState *pState); + + void OnUpdateLocalDimmingChangedResources(SwapChain *pSwapChain, const UIState *pState); + + int LoadScene(GLTFCommon *pGLTFCommon, int stage = 0); + void UnloadScene(); + + void AllocateShadowMaps(GLTFCommon* pGLTFCommon); + + const std::vector &GetTimingValues() { return m_TimeStamps; } + const std::string*& GetScreenshotFileNamePointer() { return m_pScreenShotName; } + + void OnRender(const UIState* pState, const Camera& cam, SwapChain* pSwapChain, float time); + +private: + Device *m_pDevice; + + uint32_t m_Width; + uint32_t m_Height; + + VkRect2D m_rectScissor; + VkViewport m_viewport; + + // Initialize helper classes + ResourceViewHeaps m_resourceViewHeaps; + UploadHeap m_UploadHeap; + DynamicBufferRing m_ConstantBufferRing; + StaticBufferPool m_VidMemBufferPool; + StaticBufferPool m_SysMemBufferPool; + CommandListRing m_CommandListRing; + GPUTimestamps m_GPUTimer; + + //gltf passes + GltfPbrPass *m_gltfPBR; + GltfDepthPass *m_gltfDepth; + GLTFTexturesAndBuffers *m_pGLTFTexturesAndBuffers; + + // effects + Bloom m_bloom; + DownSamplePS m_downSample; + ToneMapping m_toneMappingPS; + ToneMappingCS m_toneMappingCS; + ColorConversionPS m_colorConversionPS; + MagnifierPS m_magnifierPS; + + // GUI + ImGUI m_ImGUI; + + // GBuffer and render passes + GBuffer m_GBuffer; + GBufferRenderPass m_renderPassFullGBufferWithClear; + GBufferRenderPass m_renderPassJustDepthAndHdr; + GBufferRenderPass m_renderPassFullGBuffer; + + // shadowmaps + typedef struct { + Texture ShadowMap; + uint32_t ShadowIndex; + uint32_t ShadowResolution; + uint32_t LightIndex; + VkImageView ShadowDSV; + VkFramebuffer ShadowFrameBuffer; + } SceneShadowInfo; + + std::vector m_shadowMapPool; + std::vector< VkImageView> m_ShadowSRVPool; + + VkRenderPass m_render_pass_shadow; + + std::vector m_TimeStamps; + + // screen shot + const std::string *m_pScreenShotName = NULL; + AsyncPool m_asyncPool; + + FlipBookAnimation m_CampfireAnimation; + TestImages m_testImages; + ExposureMultiplierCS m_exposureMultiplierCS; + LPMPS m_lpmPS; + + VkRenderPass m_render_pass_TestPattern; + VkFramebuffer m_pFrameBuffer_TestPattern; +}; + diff --git a/sample/src/VK/SampleRenderer.cpp b/sample/src/VK/SampleRenderer.cpp deleted file mode 100644 index 4d59d2b..0000000 --- a/sample/src/VK/SampleRenderer.cpp +++ /dev/null @@ -1,1148 +0,0 @@ -// AMD LPMSample sample code -// -// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. - -#include "stdafx.h" - -#include "SampleRenderer.h" - -//-------------------------------------------------------------------------------------- -// -// OnCreate -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnCreate(Device *pDevice, SwapChain *pSwapChain) -{ - VkResult res; - m_pDevice = pDevice; - - // Initialize helpers - - // Create all the heaps for the resources views - const uint32_t cbvDescriptorCount = 2000; - const uint32_t srvDescriptorCount = 2000; - const uint32_t uavDescriptorCount = 10; - const uint32_t samplerDescriptorCount = 20; - m_resourceViewHeaps.OnCreate(pDevice, cbvDescriptorCount, srvDescriptorCount, uavDescriptorCount, samplerDescriptorCount); - - // Create a commandlist ring for the Direct queue - // We are queuing (backBufferCount + 0.5) frames, so we need to triple buffer the command lists - uint32_t commandListsPerBackBuffer = 8; - m_CommandListRing.OnCreate(pDevice, backBufferCount, commandListsPerBackBuffer); - - // Create a 'dynamic' constant buffer - const uint32_t constantBuffersMemSize = 20 * 1024 * 1024; - m_ConstantBufferRing.OnCreate(pDevice, backBufferCount, constantBuffersMemSize, "Uniforms"); - - // Create a 'static' pool for vertices and indices - const uint32_t staticGeometryMemSize = 128 * 1024 * 1024; - m_VidMemBufferPool.OnCreate(pDevice, staticGeometryMemSize, USE_VID_MEM, "StaticGeom"); - - // initialize the GPU time stamps module - m_GPUTimer.OnCreate(pDevice, backBufferCount); - - // Quick helper to upload resources, it has it's own commandList and uses suballocation. - // for 4K textures we'll need 100Megs - const uint32_t uploadHeapMemSize = 1000 * 1024 * 1024; - m_UploadHeap.OnCreate(pDevice, uploadHeapMemSize); // initialize an upload heap (uses suballocation for faster results) - - // Create a Shadowmap atlas to hold 4 cascades/spotlights - m_shadowMap.InitDepthStencil(m_pDevice, 2 * 1024, 2 * 1024, VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_1_BIT, "ShadowMap"); - m_shadowMap.CreateSRV(&m_shadowMapSRV); - m_shadowMap.CreateDSV(&m_shadowMapDSV); - - // Create render pass shadow - // - { - /* Need attachments for render target and depth buffer */ - VkAttachmentDescription attachments[1]; - - // depth RT - attachments[0].format = m_shadowMap.GetFormat(); - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - attachments[0].flags = 0; - - VkAttachmentReference depth_reference = { 0, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = 0; - subpass.pColorAttachments = NULL; - subpass.pResolveAttachments = NULL; - subpass.pDepthStencilAttachment = &depth_reference; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - VkRenderPassCreateInfo rp_info = {}; - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.pNext = NULL; - rp_info.attachmentCount = 1; - rp_info.pAttachments = attachments; - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - rp_info.dependencyCount = 0; - rp_info.pDependencies = NULL; - - res = vkCreateRenderPass(m_pDevice->GetDevice(), &rp_info, NULL, &m_render_pass_shadow); - assert(res == VK_SUCCESS); - - // Create frame buffer - // - VkImageView attachmentViews[1] = { m_shadowMapDSV }; - VkFramebufferCreateInfo fb_info = {}; - fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_info.pNext = NULL; - fb_info.renderPass = m_render_pass_shadow; - fb_info.attachmentCount = 1; - fb_info.pAttachments = attachmentViews; - fb_info.width = m_shadowMap.GetWidth(); - fb_info.height = m_shadowMap.GetHeight(); - fb_info.layers = 1; - res = vkCreateFramebuffer(m_pDevice->GetDevice(), &fb_info, NULL, &m_pShadowMapBuffers); - assert(res == VK_SUCCESS); - } - - // Create HDR MSAA render pass color with clear - // - { - /* Need attachments for render target and depth buffer */ - VkAttachmentDescription attachments[2]; - - // color MSAA RT - attachments[0].format = VK_FORMAT_R16G16B16A16_SFLOAT; - attachments[0].samples = VK_SAMPLE_COUNT_4_BIT; - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - attachments[0].flags = 0; - - // depth RT - attachments[1].format = VK_FORMAT_D32_SFLOAT; - attachments[1].samples = VK_SAMPLE_COUNT_4_BIT; - attachments[1].loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR; - attachments[1].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[1].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[1].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[1].initialLayout = VK_IMAGE_LAYOUT_UNDEFINED; - attachments[1].finalLayout = VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL; - attachments[1].flags = 0; - - VkAttachmentReference color_reference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - VkAttachmentReference depth_reference = { 1, VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL }; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_reference; - subpass.pResolveAttachments = NULL; - subpass.pDepthStencilAttachment = &depth_reference; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - VkRenderPassCreateInfo rp_info = {}; - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.pNext = NULL; - rp_info.attachmentCount = 2; - rp_info.pAttachments = attachments; - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - rp_info.dependencyCount = 0; - rp_info.pDependencies = NULL; - - res = vkCreateRenderPass(m_pDevice->GetDevice(), &rp_info, NULL, &m_render_pass_HDR_MSAA); - assert(res == VK_SUCCESS); - } - - // Create HDR render pass color - // - { - /* Need attachments for render target and depth buffer */ - VkAttachmentDescription attachments[1]; - - // color HDR RT - attachments[0].format = VK_FORMAT_R16G16B16A16_SFLOAT; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_LOAD; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - attachments[0].flags = 0; - - VkAttachmentReference color_reference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_reference; - subpass.pResolveAttachments = NULL; - subpass.pDepthStencilAttachment = NULL; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - VkRenderPassCreateInfo rp_info = {}; - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.pNext = NULL; - rp_info.attachmentCount = 1; - rp_info.pAttachments = attachments; - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - rp_info.dependencyCount = 0; - rp_info.pDependencies = NULL; - - VkResult res = vkCreateRenderPass(m_pDevice->GetDevice(), &rp_info, NULL, &m_render_pass_HDR); - assert(res == VK_SUCCESS); - } - - // Create test pattern render pass - { - // color RT - VkAttachmentDescription attachments[1]; - attachments[0].format = VK_FORMAT_R16G16B16A16_SFLOAT; - attachments[0].samples = VK_SAMPLE_COUNT_1_BIT; - attachments[0].loadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].storeOp = VK_ATTACHMENT_STORE_OP_STORE; - attachments[0].stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE; - attachments[0].stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE; - attachments[0].initialLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - attachments[0].finalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - attachments[0].flags = 0; - - VkAttachmentReference color_reference = { 0, VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL }; - - VkSubpassDescription subpass = {}; - subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS; - subpass.flags = 0; - subpass.inputAttachmentCount = 0; - subpass.pInputAttachments = NULL; - subpass.colorAttachmentCount = 1; - subpass.pColorAttachments = &color_reference; - subpass.pResolveAttachments = NULL; - subpass.pDepthStencilAttachment = NULL; - subpass.preserveAttachmentCount = 0; - subpass.pPreserveAttachments = NULL; - - VkRenderPassCreateInfo rp_info = {}; - rp_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO; - rp_info.pNext = NULL; - rp_info.attachmentCount = 1; - rp_info.pAttachments = attachments; - rp_info.subpassCount = 1; - rp_info.pSubpasses = &subpass; - rp_info.dependencyCount = 0; - rp_info.pDependencies = NULL; - - res = vkCreateRenderPass(m_pDevice->GetDevice(), &rp_info, NULL, &m_render_pass_TestPattern); - assert(res == VK_SUCCESS); - } - - - XMMATRIX campfireWorldMatrix = XMMATRIX(0.5f, 0.0f, 0.0f, 0.0f, - 0.0f, 0.5f, 0.0f, 0.0f, - 0.0f, 0.0f, 0.5f, 0.0f, - -47.3f, -26.5f, -40.425f, 1.0f); - m_CampfireAnimation.OnCreate(pDevice, m_render_pass_HDR_MSAA, &m_UploadHeap, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_SAMPLE_COUNT_4_BIT, 12, 12, "..\\media\\FlipBookAnimationTextures\\cf_loop_comp_v1_mosaic.png", campfireWorldMatrix); - m_downSample.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); - m_bloom.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing, &m_VidMemBufferPool, VK_FORMAT_R16G16B16A16_SFLOAT); - - m_testImages.OnCreate(pDevice, m_render_pass_TestPattern, &m_UploadHeap, &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); - - // Create tonemapping pass - m_exposureMultiplierCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); - m_toneMappingCS.OnCreate(pDevice, &m_resourceViewHeaps, &m_ConstantBufferRing); - m_toneMappingPS.OnCreate(pDevice, pSwapChain->GetRenderPass(), &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); - m_colorConversionPS.OnCreate(pDevice, pSwapChain->GetRenderPass(), &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); - m_lpmPS.OnCreate(pDevice, pSwapChain->GetRenderPass(), &m_resourceViewHeaps, &m_VidMemBufferPool, &m_ConstantBufferRing); - - // Initialize UI rendering resources - m_ImGUI.OnCreate(m_pDevice, m_render_pass_HDR, &m_UploadHeap, &m_ConstantBufferRing); - -#if (USE_VID_MEM==true) - m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); - m_UploadHeap.FlushAndFinish(); -#endif -} - -//-------------------------------------------------------------------------------------- -// -// OnDestroy -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnDestroy() -{ - m_lpmPS.OnDestroy(); - m_colorConversionPS.OnDestroy(); - m_toneMappingPS.OnDestroy(); - m_toneMappingCS.OnDestroy(); - m_exposureMultiplierCS.OnDestroy(); - m_ImGUI.OnDestroy(); - m_testImages.OnDestroy(); - m_bloom.OnDestroy(); - m_downSample.OnDestroy(); - m_CampfireAnimation.OnDestroy(); - m_shadowMap.OnDestroy(); - - vkDestroyImageView(m_pDevice->GetDevice(), m_shadowMapDSV, nullptr); - vkDestroyImageView(m_pDevice->GetDevice(), m_shadowMapSRV, nullptr); - - vkDestroyRenderPass(m_pDevice->GetDevice(), m_render_pass_shadow, nullptr); - vkDestroyRenderPass(m_pDevice->GetDevice(), m_render_pass_HDR_MSAA, nullptr); - vkDestroyRenderPass(m_pDevice->GetDevice(), m_render_pass_TestPattern, nullptr); - vkDestroyFramebuffer(m_pDevice->GetDevice(), m_pShadowMapBuffers, nullptr); - - m_UploadHeap.OnDestroy(); - m_GPUTimer.OnDestroy(); - m_VidMemBufferPool.OnDestroy(); - m_ConstantBufferRing.OnDestroy(); - m_resourceViewHeaps.OnDestroy(); - m_CommandListRing.OnDestroy(); -} - -//-------------------------------------------------------------------------------------- -// -// OnCreateWindowSizeDependentResources -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height, State *pState) -{ - VkResult res; - - m_Width = Width; - m_Height = Height; - - // Set the viewport - // - m_ViewPort.x = 0; - m_ViewPort.y = (float)Height; - m_ViewPort.width = (float)Width; - m_ViewPort.height = -(float)(Height); - m_ViewPort.minDepth = (float)0.0f; - m_ViewPort.maxDepth = (float)1.0f; - - // Create scissor rectangle - // - m_RectScissor = { 0, 0, Width, Height }; - - // Create depth buffer - // - m_depthBuffer.InitDepthStencil(m_pDevice, Width, Height, VK_FORMAT_D32_SFLOAT, VK_SAMPLE_COUNT_4_BIT, "DepthBuffer"); - m_depthBuffer.CreateDSV(&m_DepthBufferDSV); - - // Create Texture + RTV with x4 MSAA - // - m_HDRMSAA.InitRenderTarget(m_pDevice, m_Width, m_Height, VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_4_BIT, (VkImageUsageFlags)(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_SRC_BIT), false, "HDRMSAA"); - m_HDRMSAA.CreateRTV(&m_HDRMSAASRV); - - // Create Texture + RTV, to hold the resolved scene - // - m_HDR.InitRenderTarget(m_pDevice, m_Width, m_Height, VK_FORMAT_R16G16B16A16_SFLOAT, VK_SAMPLE_COUNT_1_BIT, (VkImageUsageFlags)(VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT | VK_IMAGE_USAGE_SAMPLED_BIT | VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_STORAGE_BIT), false, "HDR"); - m_HDR.CreateSRV(&m_HDRSRV); - m_HDR.CreateSRV(&m_HDRUAV); - - // Create framebuffer for the MSAA RT - // - { - VkImageView attachments[2] = { m_HDRMSAASRV, m_DepthBufferDSV }; - - VkFramebufferCreateInfo fb_info = {}; - fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_info.pNext = NULL; - fb_info.renderPass = m_render_pass_HDR_MSAA; - fb_info.attachmentCount = 2; - fb_info.pAttachments = attachments; - fb_info.width = Width; - fb_info.height = Height; - fb_info.layers = 1; - - res = vkCreateFramebuffer(m_pDevice->GetDevice(), &fb_info, NULL, &m_pFrameBuffer_HDR_MSAA); - assert(res == VK_SUCCESS); - } - - // Create framebuffer for the HDR RT - // - { - VkImageView attachments[1] = { m_HDRSRV }; - - VkFramebufferCreateInfo fb_info = {}; - fb_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO; - fb_info.pNext = NULL; - fb_info.renderPass = m_render_pass_HDR; - fb_info.attachmentCount = 1; - fb_info.pAttachments = attachments; - fb_info.width = Width; - fb_info.height = Height; - fb_info.layers = 1; - - VkResult res = vkCreateFramebuffer(m_pDevice->GetDevice(), &fb_info, NULL, &m_pFrameBuffer_HDR); - assert(res == VK_SUCCESS); - } - - // update bloom and downscaling effect - // - { - m_downSample.OnCreateWindowSizeDependentResources(m_Width, m_Height, &m_HDR, 5); //downsample the HDR texture 5 times - m_bloom.OnCreateWindowSizeDependentResources(m_Width / 2, m_Height / 2, m_downSample.GetTexture(), 5, &m_HDR); - } - - // update the pipelines if the swapchain render pass has changed (for example when the format of the swapchain changes) - // - m_colorConversionPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode()); - m_toneMappingPS.UpdatePipelines(pSwapChain->GetRenderPass()); - m_lpmPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode(), pState->colorSpace); -} - -//-------------------------------------------------------------------------------------- -// -// OnDestroyWindowSizeDependentResources -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnDestroyWindowSizeDependentResources() -{ - m_bloom.OnDestroyWindowSizeDependentResources(); - m_downSample.OnDestroyWindowSizeDependentResources(); - - m_HDR.OnDestroy(); - m_HDRMSAA.OnDestroy(); - m_depthBuffer.OnDestroy(); - - vkDestroyFramebuffer(m_pDevice->GetDevice(), m_pFrameBuffer_HDR_MSAA, nullptr); - vkDestroyFramebuffer(m_pDevice->GetDevice(), m_pFrameBuffer_HDR, nullptr); - - vkDestroyImageView(m_pDevice->GetDevice(), m_DepthBufferDSV, nullptr); - vkDestroyImageView(m_pDevice->GetDevice(), m_HDRMSAASRV, nullptr); - vkDestroyImageView(m_pDevice->GetDevice(), m_HDRSRV, nullptr); - vkDestroyImageView(m_pDevice->GetDevice(), m_HDRUAV, nullptr); -} - -//-------------------------------------------------------------------------------------- -// -// OnUpdateLocalDimmingChangedResources -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnUpdateLocalDimmingChangedResources(SwapChain *pSwapChain, State *pState) -{ - m_colorConversionPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode()); - m_lpmPS.UpdatePipelines(pSwapChain->GetRenderPass(), pSwapChain->GetDisplayMode(), pState->colorSpace); -} - -//-------------------------------------------------------------------------------------- -// -// LoadScene -// -//-------------------------------------------------------------------------------------- -int SampleRenderer::LoadScene(GLTFCommon *pGLTFCommon, int stage) -{ - // show loading progress - // - ImGui::OpenPopup("Loading"); - if (ImGui::BeginPopupModal("Loading", NULL, ImGuiWindowFlags_AlwaysAutoResize)) - { - float progress = (float)stage / 10.0f; - ImGui::ProgressBar(progress, ImVec2(0.f, 0.f), NULL); - ImGui::EndPopup(); - } - - // Loading stages - // - if (stage == 0) - { - } - else if (stage == 5) - { - Profile p("m_pGltfLoader->Load"); - - m_pGLTFTexturesAndBuffers = new GLTFTexturesAndBuffers(); - m_pGLTFTexturesAndBuffers->OnCreate(m_pDevice, pGLTFCommon, &m_UploadHeap, &m_VidMemBufferPool, &m_ConstantBufferRing); - } - else if (stage == 6) - { - Profile p("LoadTextures"); - - // here we are loading onto the GPU all the textures and the inverse matrices - // this data will be used to create the PBR and Depth passes - m_pGLTFTexturesAndBuffers->LoadTextures(); - } - else if (stage == 7) - { - Profile p("m_gltfDepth->OnCreate"); - - //create the glTF's textures, VBs, IBs, shaders and descriptors - m_gltfDepth = new GltfDepthPass(); - m_gltfDepth->OnCreate( - m_pDevice, - m_render_pass_shadow, - &m_UploadHeap, - &m_resourceViewHeaps, - &m_ConstantBufferRing, - &m_VidMemBufferPool, - m_pGLTFTexturesAndBuffers - ); - } - else if (stage == 8) - { - Profile p("m_gltfPBR->OnCreate"); - m_gltfPBR = new GltfPbrPass(); - m_gltfPBR->OnCreate( - m_pDevice, - m_render_pass_HDR_MSAA, - &m_UploadHeap, - &m_resourceViewHeaps, - &m_ConstantBufferRing, - &m_VidMemBufferPool, - m_pGLTFTexturesAndBuffers, - nullptr, - false, - m_shadowMapSRV, - m_bExportForwardPass, - m_bExportSpecularRoughness, - m_bExportDiffuseColor, - m_bExportNormals, - VK_SAMPLE_COUNT_4_BIT - ); -#if (USE_VID_MEM==true) - m_VidMemBufferPool.UploadData(m_UploadHeap.GetCommandList()); - m_UploadHeap.FlushAndFinish(); -#endif - } - else if (stage == 10) - { - Profile p("Flush"); - - m_UploadHeap.FlushAndFinish(); - -#if (USE_VID_MEM==true) - //once everything is uploaded we dont need he upload heaps anymore - m_VidMemBufferPool.FreeUploadHeap(); -#endif - - // tell caller that we are done loading the map - return -1; - } - - stage++; - return stage; -} - -//-------------------------------------------------------------------------------------- -// -// UnloadScene -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::UnloadScene() -{ - if (m_gltfPBR) - { - m_gltfPBR->OnDestroy(); - delete m_gltfPBR; - m_gltfPBR = NULL; - } - - if (m_gltfDepth) - { - m_gltfDepth->OnDestroy(); - delete m_gltfDepth; - m_gltfDepth = NULL; - } - - if (m_pGLTFTexturesAndBuffers) - { - m_pGLTFTexturesAndBuffers->OnDestroy(); - delete m_pGLTFTexturesAndBuffers; - m_pGLTFTexturesAndBuffers = NULL; - } -} - -//-------------------------------------------------------------------------------------- -// -// OnRender -// -//-------------------------------------------------------------------------------------- -void SampleRenderer::OnRender(State *pState, SwapChain *pSwapChain) -{ - VkResult res; - - // Let our resource managers do some house keeping - // - m_ConstantBufferRing.OnBeginFrame(); - - // command buffer calls - // - VkCommandBuffer cmdBuf1 = m_CommandListRing.GetNewCommandList(); - - { - VkCommandBufferBeginInfo cmd_buf_info; - cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmd_buf_info.pNext = NULL; - cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - cmd_buf_info.pInheritanceInfo = NULL; - res = vkBeginCommandBuffer(cmdBuf1, &cmd_buf_info); - assert(res == VK_SUCCESS); - } - - m_GPUTimer.OnBeginFrame(cmdBuf1, &m_TimeStamps); - - // Sets the perFrame data (Camera and lights data), override as necessary and set them as constant buffers -------------- - // - per_frame *pPerFrame = NULL; - if (m_pGLTFTexturesAndBuffers) - { - pPerFrame = m_pGLTFTexturesAndBuffers->m_pGLTFCommon->SetPerFrameData(pState->camera); - - //override gltf camera with ours - pPerFrame->mCameraViewProj = pState->camera.GetView() * pState->camera.GetProjection(); - pPerFrame->cameraPos = pState->camera.GetPosition(); - pPerFrame->emmisiveFactor = pState->emmisiveFactor; - - pPerFrame->lights[0].intensity = pState->lightIntensity; - - // Up to 4 spotlights can have shadowmaps. Each spot the light has a shadowMap index which is used to find the sadowmap in the atlas - uint32_t shadowMapIndex = 0; - for (uint32_t i = 0; i < pPerFrame->lightCount; i++) - { - if ((shadowMapIndex < 4) && (pPerFrame->lights[i].type == LightType_Spot)) - { - pPerFrame->lights[i].shadowMapIndex = shadowMapIndex++; //set the shadowmap index so the color pass knows which shadow map to use - pPerFrame->lights[i].depthBias = 70.0f / 100000.0f; - } - } - - m_pGLTFTexturesAndBuffers->SetPerFrameConstants(); - - m_pGLTFTexturesAndBuffers->SetSkinningMatricesForSkeletons(); - } - - // Render to shadow map atlas for spot lights ------------------------------------------ - // - if (m_gltfDepth && pPerFrame != NULL) - { - SetPerfMarkerBegin(cmdBuf1, "ShadowPass"); - - VkClearValue depth_clear_values[1]; - depth_clear_values[0].depthStencil.depth = 1.0f; - depth_clear_values[0].depthStencil.stencil = 0; - - { - VkRenderPassBeginInfo rp_begin; - rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin.pNext = NULL; - rp_begin.renderPass = m_render_pass_shadow; - rp_begin.framebuffer = m_pShadowMapBuffers; - rp_begin.renderArea.offset.x = 0; - rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = m_shadowMap.GetWidth(); - rp_begin.renderArea.extent.height = m_shadowMap.GetHeight(); - rp_begin.clearValueCount = 1; - rp_begin.pClearValues = depth_clear_values; - - vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); - m_GPUTimer.GetTimeStamp(cmdBuf1, "Clear Shadow Map"); - } - - uint32_t shadowMapIndex = 0; - for (uint32_t i = 0; i < pPerFrame->lightCount; i++) - { - if (pPerFrame->lights[i].type != LightType_Spot) - continue; - - // Set the RT's quadrant where to render the shadomap (these viewport offsets need to match the ones in shadowFiltering.h) - uint32_t viewportOffsetsX[4] = { 0, 1, 0, 1 }; - uint32_t viewportOffsetsY[4] = { 0, 0, 1, 1 }; - uint32_t viewportWidth = m_shadowMap.GetWidth() / 2; - uint32_t viewportHeight = m_shadowMap.GetHeight() / 2; - SetViewportAndScissor(cmdBuf1, viewportOffsetsX[shadowMapIndex] * viewportWidth, viewportOffsetsY[shadowMapIndex] * viewportHeight, viewportWidth, viewportHeight); - - //set per frame constant buffer values - GltfDepthPass::per_frame *cbPerFrame = m_gltfDepth->SetPerFrameConstants(); - cbPerFrame->mViewProj = pPerFrame->lights[i].mLightViewProj; - - m_gltfDepth->Draw(cmdBuf1); - - m_GPUTimer.GetTimeStamp(cmdBuf1, "Shadow maps"); - shadowMapIndex++; - } - vkCmdEndRenderPass(cmdBuf1); - - SetPerfMarkerEnd(cmdBuf1); - } - - - // Render Scene to the MSAA HDR RT ------------------------------------------------ - // - SetPerfMarkerBegin(cmdBuf1, "Color pass"); - if (pPerFrame != NULL) - { - { - m_GPUTimer.GetTimeStamp(cmdBuf1, "before color RP"); - VkClearValue clear_values[2]; - clear_values[0].color.float32[0] = 0.0f; - clear_values[0].color.float32[1] = 0.0f; - clear_values[0].color.float32[2] = 0.0f; - clear_values[0].color.float32[3] = 0.0f; - clear_values[1].depthStencil.depth = 1.0f; - clear_values[1].depthStencil.stencil = 0; - - VkRenderPassBeginInfo rp_begin; - rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin.pNext = NULL; - rp_begin.renderPass = m_render_pass_HDR_MSAA; - rp_begin.framebuffer = m_pFrameBuffer_HDR_MSAA; - rp_begin.renderArea.offset.x = 0; - rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = m_Width; - rp_begin.renderArea.extent.height = m_Height; - rp_begin.clearValueCount = 2; - rp_begin.pClearValues = clear_values; - - vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); - - vkCmdSetScissor(cmdBuf1, 0, 1, &m_RectScissor); - vkCmdSetViewport(cmdBuf1, 0, 1, &m_ViewPort); - m_GPUTimer.GetTimeStamp(cmdBuf1, "after color RP"); - } - - // Render scene to color buffer - // - if (m_gltfPBR) - { - SetPerfMarkerBegin(cmdBuf1, "gltfPBR"); - - { - m_gltfPBR->Draw(cmdBuf1); - m_CampfireAnimation.Draw(cmdBuf1, pState->time, pState->camera.GetPosition(), pState->camera.GetView() * pState->camera.GetProjection()); - m_GPUTimer.GetTimeStamp(cmdBuf1, "Rendering Scene"); - } - - SetPerfMarkerEnd(cmdBuf1); - } - - vkCmdEndRenderPass(cmdBuf1); - } - - SetPerfMarkerEnd(cmdBuf1); - - // Resolve MSAA ------------------------------------------------------------------------ - // - { - SetPerfMarkerBegin(cmdBuf1, "resolve MSAA"); - { - VkImageMemoryBarrier barrier[2] = {}; - barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier[0].pNext = NULL; - barrier[0].srcAccessMask = 0; - barrier[0].dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier[0].oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; - barrier[0].newLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier[0].subresourceRange.baseMipLevel = 0; - barrier[0].subresourceRange.levelCount = 1; - barrier[0].subresourceRange.baseArrayLayer = 0; - barrier[0].subresourceRange.layerCount = 1; - barrier[0].image = m_HDR.Resource(); - - barrier[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier[1].pNext = NULL; - barrier[1].srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier[1].dstAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier[1].oldLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier[1].newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier[1].subresourceRange.baseMipLevel = 0; - barrier[1].subresourceRange.levelCount = 1; - barrier[1].subresourceRange.baseArrayLayer = 0; - barrier[1].subresourceRange.layerCount = 1; - barrier[1].image = m_HDRMSAA.Resource(); - - vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_TRANSFER_BIT, 0, 0, NULL, 0, NULL, 2, barrier); - } - - { - VkImageResolve re = {}; - re.srcOffset.x = 0; - re.srcOffset.y = 0; - re.extent.width = m_Width; - re.extent.height = m_Height; - re.extent.depth = 1; - re.srcSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - re.srcSubresource.layerCount = 1; - re.dstOffset.x = 0; - re.dstOffset.y = 0; - re.dstSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - re.dstSubresource.layerCount = 1; - vkCmdResolveImage(cmdBuf1, m_HDRMSAA.Resource(), VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL, m_HDR.Resource(), VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, &re); - } - - { - VkImageMemoryBarrier barrier[2] = {}; - barrier[0].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier[0].pNext = NULL; - barrier[0].srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT; - barrier[0].dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - barrier[0].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL; - barrier[0].newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - barrier[0].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[0].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[0].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier[0].subresourceRange.baseMipLevel = 0; - barrier[0].subresourceRange.levelCount = 1; - barrier[0].subresourceRange.baseArrayLayer = 0; - barrier[0].subresourceRange.layerCount = 1; - barrier[0].image = m_HDR.Resource(); - - barrier[1].sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier[1].pNext = NULL; - barrier[1].srcAccessMask = VK_ACCESS_TRANSFER_READ_BIT; - barrier[1].dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier[1].oldLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; - barrier[1].newLayout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL; - barrier[1].srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[1].dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier[1].subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier[1].subresourceRange.baseMipLevel = 0; - barrier[1].subresourceRange.levelCount = 1; - barrier[1].subresourceRange.baseArrayLayer = 0; - barrier[1].subresourceRange.layerCount = 1; - barrier[1].image = m_HDRMSAA.Resource(); - - 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, 2, barrier); - } - - m_GPUTimer.GetTimeStamp(cmdBuf1, "Resolve"); - SetPerfMarkerEnd(cmdBuf1); - } - - // Post proc--------------------------------------------------------------------------- - // - { - SetPerfMarkerBegin(cmdBuf1, "post proc"); - - // Downsample pass - m_downSample.Draw(cmdBuf1); - //m_downSample.Gui(); - m_GPUTimer.GetTimeStamp(cmdBuf1, "Downsample"); - - // Bloom pass (needs the downsampled data) - m_bloom.Draw(cmdBuf1); - //m_bloom.Gui(); - m_GPUTimer.GetTimeStamp(cmdBuf1, "bloom"); - - SetPerfMarkerEnd(cmdBuf1); - } - - // Render TestPattern ------------------------------------------------------------------------ - // - { - SetPerfMarkerBegin(cmdBuf1, "TestPattern"); - - // prepare render pass - { - VkRenderPassBeginInfo rp_begin = {}; - rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin.pNext = NULL; - rp_begin.renderPass = m_render_pass_TestPattern; - rp_begin.framebuffer = m_pFrameBuffer_HDR; - rp_begin.renderArea.offset.x = 0; - rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = m_Width; - rp_begin.renderArea.extent.height = m_Height; - rp_begin.clearValueCount = 0; - rp_begin.pClearValues = NULL; - vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); - } - - vkCmdSetScissor(cmdBuf1, 0, 1, &m_RectScissor); - vkCmdSetViewport(cmdBuf1, 0, 1, &m_ViewPort); - - if (pState->testPattern) - { - m_testImages.Draw(cmdBuf1, pState->testPattern); - } - - vkCmdEndRenderPass(cmdBuf1); - - m_GPUTimer.GetTimeStamp(cmdBuf1, "TestPattern"); - - SetPerfMarkerEnd(cmdBuf1); - } - - // Apply Exposure ------------------------------------------------------------------------ - // - { - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.pNext = NULL; - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; // we need to read from it for the post-processing - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.image = m_HDR.Resource(); - vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); - } - - m_exposureMultiplierCS.Draw(cmdBuf1, m_HDRUAV, pState->exposure, m_Width, m_Height); - - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.pNext = NULL; - barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // we need to read from it for the post-processing - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.image = m_HDR.Resource(); - vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); - } - - m_GPUTimer.GetTimeStamp(cmdBuf1, "Exposure Multiplier"); - } - - // Render HUD ------------------------------------------------------------------------ - // - { - // prepare render pass - { - VkRenderPassBeginInfo rp_begin = {}; - rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin.pNext = NULL; - rp_begin.renderPass = m_render_pass_HDR; - rp_begin.framebuffer = m_pFrameBuffer_HDR; - rp_begin.renderArea.offset.x = 0; - rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = m_Width; - rp_begin.renderArea.extent.height = m_Height; - rp_begin.clearValueCount = 0; - rp_begin.pClearValues = NULL; - vkCmdBeginRenderPass(cmdBuf1, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); - } - - vkCmdSetScissor(cmdBuf1, 0, 1, &m_RectScissor); - vkCmdSetViewport(cmdBuf1, 0, 1, &m_ViewPort); - - m_ImGUI.Draw(cmdBuf1); - - vkCmdEndRenderPass(cmdBuf1); - - m_GPUTimer.GetTimeStamp(cmdBuf1, "ImGUI Rendering"); - } - - // If using FreeSync2 we need to to the tonemapping in-place and then apply the GUI, later we'll apply the color conversion into the swapchain - // - if (pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR && pState->toneMapper < 6) - { - // In place Tonemapping ------------------------------------------------------------------------ - // - { - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.pNext = NULL; - barrier.srcAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; - barrier.newLayout = VK_IMAGE_LAYOUT_GENERAL; // we need to read from it for the post-processing - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.image = m_HDR.Resource(); - vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); - } - - m_toneMappingCS.Draw(cmdBuf1, m_HDRUAV, pState->unusedExposure, pState->toneMapper, m_Width, m_Height); - - { - VkImageMemoryBarrier barrier = {}; - barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER; - barrier.pNext = NULL; - barrier.srcAccessMask = VK_ACCESS_SHADER_WRITE_BIT; - barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT; - barrier.oldLayout = VK_IMAGE_LAYOUT_GENERAL; - barrier.newLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // we need to read from it for the post-processing - barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED; - barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT; - barrier.subresourceRange.baseMipLevel = 0; - barrier.subresourceRange.levelCount = 1; - barrier.subresourceRange.baseArrayLayer = 0; - barrier.subresourceRange.layerCount = 1; - barrier.image = m_HDR.Resource(); - vkCmdPipelineBarrier(cmdBuf1, VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, 0, NULL, 0, NULL, 1, &barrier); - } - - m_GPUTimer.GetTimeStamp(cmdBuf1, "Tonemapping"); - } - } - // submit command buffer - { - VkResult res = vkEndCommandBuffer(cmdBuf1); - assert(res == VK_SUCCESS); - - VkSubmitInfo submit_info; - submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info.pNext = NULL; - submit_info.waitSemaphoreCount = 0; - submit_info.pWaitSemaphores = NULL; - submit_info.pWaitDstStageMask = NULL; - submit_info.commandBufferCount = 1; - submit_info.pCommandBuffers = &cmdBuf1; - submit_info.signalSemaphoreCount = 0; - submit_info.pSignalSemaphores = NULL; - res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info, VK_NULL_HANDLE); - assert(res == VK_SUCCESS); - } - - // Wait for swapchain (we are going to render to it) ----------------------------------- - // - int imageIndex = pSwapChain->WaitForSwapChain(); - - m_CommandListRing.OnBeginFrame(); - - VkCommandBuffer cmdBuf2 = m_CommandListRing.GetNewCommandList(); - { - VkCommandBufferBeginInfo cmd_buf_info; - cmd_buf_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO; - cmd_buf_info.pNext = NULL; - cmd_buf_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; - cmd_buf_info.pInheritanceInfo = NULL; - VkResult res = vkBeginCommandBuffer(cmdBuf2, &cmd_buf_info); - assert(res == VK_SUCCESS); - } - - SetPerfMarkerBegin(cmdBuf2, "rendering to swap chain"); - - // prepare render pass - { - VkRenderPassBeginInfo rp_begin = {}; - rp_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO; - rp_begin.pNext = NULL; - rp_begin.renderPass = pSwapChain->GetRenderPass(); - rp_begin.framebuffer = pSwapChain->GetFramebuffer(imageIndex); - rp_begin.renderArea.offset.x = 0; - rp_begin.renderArea.offset.y = 0; - rp_begin.renderArea.extent.width = m_Width; - rp_begin.renderArea.extent.height = m_Height; - rp_begin.clearValueCount = 0; - rp_begin.pClearValues = NULL; - vkCmdBeginRenderPass(cmdBuf2, &rp_begin, VK_SUBPASS_CONTENTS_INLINE); - } - - vkCmdSetScissor(cmdBuf2, 0, 1, &m_RectScissor); - vkCmdSetViewport(cmdBuf2, 0, 1, &m_ViewPort); - - // Tonemapping LPM ------------------------------------------------------------------------ - // - if (pState->toneMapper == 6) - { - m_lpmPS.Draw(cmdBuf2, m_HDRSRV); - m_GPUTimer.GetTimeStamp(cmdBuf2, "Tone mapping LPM"); - } - else - { - if (pSwapChain->GetDisplayMode() != DISPLAYMODE_SDR) - { - // FS2 mode! Apply color conversion now. - // - m_colorConversionPS.Draw(cmdBuf2, m_HDRSRV); - m_GPUTimer.GetTimeStamp(cmdBuf2, "Color conversion"); - } - else - { - // non FS2 mode, that is SDR, here we apply the tonemapping from the HDR into the swapchain - // - // Tonemapping ------------------------------------------------------------------------ - // - { - m_toneMappingPS.Draw(cmdBuf2, m_HDRSRV, pState->unusedExposure, pState->toneMapper); - m_GPUTimer.GetTimeStamp(cmdBuf2, "Tone mapping"); - } - } - } - - SetPerfMarkerEnd(cmdBuf2); - - m_GPUTimer.OnEndFrame(); - - vkCmdEndRenderPass(cmdBuf2); - - // Close & Submit the command list ---------------------------------------------------- - // - { - VkResult res = vkEndCommandBuffer(cmdBuf2); - assert(res == VK_SUCCESS); - - VkSemaphore ImageAvailableSemaphore; - VkSemaphore RenderFinishedSemaphores; - VkFence CmdBufExecutedFences; - pSwapChain->GetSemaphores(&ImageAvailableSemaphore, &RenderFinishedSemaphores, &CmdBufExecutedFences); - - VkPipelineStageFlags submitWaitStage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT; - VkSubmitInfo submit_info2; - submit_info2.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO; - submit_info2.pNext = NULL; - submit_info2.waitSemaphoreCount = 1; - submit_info2.pWaitSemaphores = &ImageAvailableSemaphore; - submit_info2.pWaitDstStageMask = &submitWaitStage; - submit_info2.commandBufferCount = 1; - submit_info2.pCommandBuffers = &cmdBuf2; - submit_info2.signalSemaphoreCount = 1; - submit_info2.pSignalSemaphores = &RenderFinishedSemaphores; - - res = vkQueueSubmit(m_pDevice->GetGraphicsQueue(), 1, &submit_info2, CmdBufExecutedFences); - assert(res == VK_SUCCESS); - } -} diff --git a/sample/src/VK/SampleRenderer.h b/sample/src/VK/SampleRenderer.h deleted file mode 100644 index 8b43d63..0000000 --- a/sample/src/VK/SampleRenderer.h +++ /dev/null @@ -1,138 +0,0 @@ -// AMD LPMSample sample code -// -// Copyright(c) 2019 Advanced Micro Devices, Inc.All rights reserved. -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files(the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions : -// The above copyright notice and this permission notice shall be included in -// all copies or substantial portions of the Software. -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN -// THE SOFTWARE. -#pragma once - -static const int backBufferCount = 3; - -#define USE_VID_MEM true - -using namespace CAULDRON_VK; - -// -// This class deals with the GPU side of the sample. -// - -class SampleRenderer -{ -public: - - struct State - { - float time; - Camera camera; - - float exposure; - float unusedExposure; - float emmisiveFactor; - - int testPattern; - ColorSpace colorSpace; - int toneMapper; - float lightIntensity; - }; - - void OnCreate(Device *pDevice, SwapChain *pSwapChain); - void OnDestroy(); - - void OnCreateWindowSizeDependentResources(SwapChain *pSwapChain, uint32_t Width, uint32_t Height, State *pState); - void OnDestroyWindowSizeDependentResources(); - - void OnUpdateLocalDimmingChangedResources(SwapChain *pSwapChain, State *pState); - - int LoadScene(GLTFCommon *pGLTFCommon, int stage = 0); - void UnloadScene(); - - const std::vector &GetTimingValues() { return m_TimeStamps; } - - void OnRender(State *pState, SwapChain *pSwapChain); - -private: - Device *m_pDevice; - - uint32_t m_Width; - uint32_t m_Height; - - VkViewport m_ViewPort; - VkRect2D m_RectScissor; - - // Initialize helper classes - ResourceViewHeaps m_resourceViewHeaps; - UploadHeap m_UploadHeap; - DynamicBufferRing m_ConstantBufferRing; - StaticBufferPool m_VidMemBufferPool; - CommandListRing m_CommandListRing; - GPUTimestamps m_GPUTimer; - - //gltf passes - GLTFTexturesAndBuffers *m_pGLTFTexturesAndBuffers; - GltfPbrPass *m_gltfPBR; - GltfDepthPass *m_gltfDepth; - - FlipBookAnimation m_CampfireAnimation; - - // effects - Bloom m_bloom; - DownSamplePS m_downSample; - TestImages m_testImages; - ExposureMultiplierCS m_exposureMultiplierCS; - ToneMapping m_toneMappingPS; - ToneMappingCS m_toneMappingCS; - ColorConversionPS m_colorConversionPS; - LPMPS m_lpmPS; - - // GUI - ImGUI m_ImGUI; - - // Temporary render targets - - // depth buffer - Texture m_depthBuffer; - VkImageView m_DepthBufferDSV; - - // shadowmap - Texture m_shadowMap; - VkImageView m_shadowMapDSV; - VkImageView m_shadowMapSRV; - - // MSAA RT - Texture m_HDRMSAA; - VkImageView m_HDRMSAASRV; - - bool m_bExportForwardPass = true; - bool m_bExportSpecularRoughness = false; - bool m_bExportDiffuseColor = false; - bool m_bExportNormals = false; - - // Resolved RT - Texture m_HDR; - VkImageView m_HDRSRV; - VkImageView m_HDRUAV; - - VkRenderPass m_render_pass_shadow; - VkRenderPass m_render_pass_HDR_MSAA; - VkRenderPass m_render_pass_HDR; - VkRenderPass m_render_pass_TestPattern; - - VkFramebuffer m_pShadowMapBuffers; - VkFramebuffer m_pFrameBuffer_HDR_MSAA; - VkFramebuffer m_pFrameBuffer_HDR; - - std::vector m_TimeStamps; -}; - diff --git a/sample/src/VK/TestImages.cpp b/sample/src/VK/TestImages.cpp index 49d6e30..1bdcb73 100644 --- a/sample/src/VK/TestImages.cpp +++ b/sample/src/VK/TestImages.cpp @@ -57,33 +57,39 @@ namespace CAULDRON_VK layoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; layoutBindings[1].pImmutableSamplers = NULL; - for (int i = 0; i < NUM_TEXTURES; ++i) + static const char* s_TextureNameList[_countof(m_testImagesData)] = { + "..\\media\\color_ramp_bt2020_dcip3\\LuxoDoubleChecker_EXR_ARGB_16F_1.DDS", + "..\\media\\color_ramp_bt2020_dcip3\\dcip3_1000_EXR_ARGB_16F_1.DDS", + "..\\media\\color_ramp_bt2020_dcip3\\bt2020_1000_EXR_ARGB_16F_1.DDS" + }; + + for (int i = 0; i < _countof(m_testImagesData); ++i) { - m_testImageTexture[i].InitFromFile(pDevice, pUploadHeap, m_TextureNameList[i].c_str(), false); + m_testImagesData[i].m_testImageTexture.InitFromFile(pDevice, pUploadHeap, s_TextureNameList[i], false); pUploadHeap->FlushAndFinish(); - m_testImageTexture[i].CreateSRV(&m_testImageTextureSRV[i]); - m_pResourceViewHeaps->CreateDescriptorSetLayoutAndAllocDescriptorSet(&layoutBindings, &m_descriptorSetLayout[i], &m_descriptorSet[i]); - m_pDynamicBufferRing->SetDescriptorSet(0, sizeof(TestImagesConsts), m_descriptorSet[i]); - SetDescriptorSet(m_pDevice->GetDevice(), 1, m_testImageTextureSRV[i], &m_sampler, m_descriptorSet[i]); + m_testImagesData[i].m_testImageTexture.CreateSRV(&m_testImagesData[i].m_testImageTextureSRV); + m_pResourceViewHeaps->CreateDescriptorSetLayoutAndAllocDescriptorSet(&layoutBindings, &m_testImagesData[i].m_descriptorSetLayout, &m_testImagesData[i].m_descriptorSet); + m_pDynamicBufferRing->SetDescriptorSet(0, sizeof(TestImagesConsts), m_testImagesData[i].m_descriptorSet); + SetDescriptorSet(m_pDevice->GetDevice(), 1, m_testImagesData[i].m_testImageTextureSRV, &m_sampler, m_testImagesData[i].m_descriptorSet); } - m_testImagePS.OnCreate(m_pDevice, renderPass, "TestImagesPS.glsl", "main", "", pStaticBufferPool, pDynamicBufferRing, m_descriptorSetLayout[0], NULL, VK_SAMPLE_COUNT_1_BIT); + m_testImagePS.OnCreate(m_pDevice, renderPass, "TestImagesPS.glsl", "main", "", pStaticBufferPool, pDynamicBufferRing, m_testImagesData[0].m_descriptorSetLayout, NULL, VK_SAMPLE_COUNT_1_BIT); } void TestImages::OnDestroy() { - for (int i = 0; i < NUM_TEXTURES; ++i) + for (int i = 0; i < _countof(m_testImagesData); ++i) { - vkDestroyImageView(m_pDevice->GetDevice(), m_testImageTextureSRV[i], NULL); - m_testImageTexture[i].OnDestroy(); - m_pResourceViewHeaps->FreeDescriptor(m_descriptorSet[i]); - vkDestroyDescriptorSetLayout(m_pDevice->GetDevice(), m_descriptorSetLayout[i], NULL); + vkDestroyImageView(m_pDevice->GetDevice(), m_testImagesData[i].m_testImageTextureSRV, NULL); + m_testImagesData[i].m_testImageTexture.OnDestroy(); + m_pResourceViewHeaps->FreeDescriptor(m_testImagesData[i].m_descriptorSet); + vkDestroyDescriptorSetLayout(m_pDevice->GetDevice(), m_testImagesData[i].m_descriptorSetLayout, NULL); } m_testImagePS.OnDestroy(); vkDestroySampler(m_pDevice->GetDevice(), m_sampler, nullptr); - } + } void TestImages::Draw(VkCommandBuffer cmd_buf, int testPattern) { @@ -93,6 +99,6 @@ namespace CAULDRON_VK pTestImagesConsts->testPattern = testPattern - 1; - m_testImagePS.Draw(cmd_buf, cbTestImagesHandle, m_descriptorSet[pTestImagesConsts->testPattern % NUM_TEXTURES]); + m_testImagePS.Draw(cmd_buf, &cbTestImagesHandle, m_testImagesData[pTestImagesConsts->testPattern % _countof(m_testImagesData)].m_descriptorSet); } } \ No newline at end of file diff --git a/sample/src/VK/TestImages.h b/sample/src/VK/TestImages.h index d877e4b..dd254bf 100644 --- a/sample/src/VK/TestImages.h +++ b/sample/src/VK/TestImages.h @@ -21,8 +21,6 @@ #include "PostProc\PostProcPS.h" -#define NUM_TEXTURES 3 - namespace CAULDRON_VK { class TestImages @@ -33,25 +31,23 @@ namespace CAULDRON_VK void Draw(VkCommandBuffer cmd_buf, int testPattern); private: + struct TestImagesData { + VkDescriptorSet m_descriptorSet; + VkDescriptorSetLayout m_descriptorSetLayout; + VkImageView m_testImageTextureSRV; + Texture m_testImageTexture; + }; + Device* m_pDevice; ResourceViewHeaps *m_pResourceViewHeaps; DynamicBufferRing *m_pDynamicBufferRing = NULL; VkSampler m_sampler; - VkDescriptorSet m_descriptorSet[NUM_TEXTURES]; - VkDescriptorSetLayout m_descriptorSetLayout[NUM_TEXTURES]; - VkImageView m_testImageTextureSRV[NUM_TEXTURES]; - Texture m_testImageTexture[NUM_TEXTURES]; + TestImagesData m_testImagesData[3]; PostProcPS m_testImagePS; struct TestImagesConsts { int testPattern; }; - - std::vector m_TextureNameList = { - "..\\media\\color_ramp_bt2020_dcip3\\LuxoDoubleChecker_EXR_ARGB_16F_1.DDS", - "..\\media\\color_ramp_bt2020_dcip3\\dcip3_1000_EXR_ARGB_16F_1.DDS", - "..\\media\\color_ramp_bt2020_dcip3\\bt2020_1000_EXR_ARGB_16F_1.DDS" - }; }; } \ No newline at end of file diff --git a/sample/src/VK/UI.cpp b/sample/src/VK/UI.cpp new file mode 100644 index 0000000..b874653 --- /dev/null +++ b/sample/src/VK/UI.cpp @@ -0,0 +1,507 @@ +// AMD SampleVK sample code +// +// Copyright(c) 2020 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#include "stdafx.h" + +#include "UI.h" +#include "LPMSample.h" +#include "imgui.h" + +#include "base/FrameworkWindows.h" + +// To use the 'disabled UI state' functionality (ImGuiItemFlags_Disabled), include internal header +// https://github.com/ocornut/imgui/issues/211#issuecomment-339241929 +#include "imgui_internal.h" +static void DisableUIStateBegin(const bool& bEnable) +{ + if (!bEnable) + { + ImGui::PushItemFlag(ImGuiItemFlags_Disabled, true); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, ImGui::GetStyle().Alpha * 0.5f); + } +}; +static void DisableUIStateEnd(const bool& bEnable) +{ + if (!bEnable) + { + ImGui::PopItemFlag(); + ImGui::PopStyleVar(); + } +}; + +// Some constants and utility functions +static constexpr float MAGNIFICATION_AMOUNT_MIN = 1.0f; +static constexpr float MAGNIFICATION_AMOUNT_MAX = 32.0f; +static constexpr float MAGNIFIER_RADIUS_MIN = 0.01f; +static constexpr float MAGNIFIER_RADIUS_MAX = 0.85f; +static constexpr float MAGNIFIER_BORDER_COLOR__LOCKED[3] = { 0.002f, 0.72f, 0.0f }; // G +static constexpr float MAGNIFIER_BORDER_COLOR__FREE[3] = { 0.72f, 0.002f, 0.0f }; // R +template static T clamped(const T& v, const T& min, const T& max) +{ + if (v < min) return min; + else if (v > max) return max; + else return v; +} + +static bool bSceneChanged = false; + +void LPMSample::BuildUI() +{ + // if we haven't initialized GLTFLoader yet, don't draw UI. + if (m_pGltfLoader == nullptr) + { + LoadScene(0); + bSceneChanged = true; + return; + } + + ImGuiIO& io = ImGui::GetIO(); + ImGuiStyle& style = ImGui::GetStyle(); + style.FrameBorderSize = 1.0f; + + const uint32_t W = this->GetWidth(); + const uint32_t H = this->GetHeight(); + + const uint32_t PROFILER_WINDOW_PADDIG_X = 10; + const uint32_t PROFILER_WINDOW_PADDIG_Y = 10; + const uint32_t PROFILER_WINDOW_SIZE_X = 330; + const uint32_t PROFILER_WINDOW_SIZE_Y = 450; + const uint32_t PROFILER_WINDOW_POS_X = W - PROFILER_WINDOW_PADDIG_X - PROFILER_WINDOW_SIZE_X; + const uint32_t PROFILER_WINDOW_POS_Y = PROFILER_WINDOW_PADDIG_Y; + + const uint32_t CONTROLS_WINDOW_POS_X = 10; + const uint32_t CONTROLS_WINDOW_POS_Y = 10; + const uint32_t CONTROLW_WINDOW_SIZE_X = 350; + const uint32_t CONTROLW_WINDOW_SIZE_Y = 780; // assuming > 720p + + // Render CONTROLS window + // + ImGui::SetNextWindowPos(ImVec2(CONTROLS_WINDOW_POS_X, CONTROLS_WINDOW_POS_Y), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(CONTROLW_WINDOW_SIZE_X, CONTROLW_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); + + if (m_UIState.bShowControlsWindow) + { + ImGui::Begin("CONTROLS (F1)", &m_UIState.bShowControlsWindow); + if (m_activeScene == 0) + { + if (ImGui::CollapsingHeader("Animation", ImGuiTreeNodeFlags_DefaultOpen)) + { + ImGui::Checkbox("Play", &m_bPlay); + } + + ImGui::Spacing(); + ImGui::Spacing(); + } + + if (ImGui::CollapsingHeader("Scene", ImGuiTreeNodeFlags_DefaultOpen)) + { + auto getterLambda = [](void* data, int idx, const char** out_str)->bool { *out_str = ((std::vector *)data)->at(idx).c_str(); return true; }; + bSceneChanged |= ImGui::Combo("Model", &m_activeScene, getterLambda, &m_sceneNames, (int)m_sceneNames.size()); + if (bSceneChanged) + { + m_UIState.TestPattern = m_activeScene; + switch (m_activeScene) + { + // Campfire + case 0: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 0.0f; + m_UIState.HdrMax = 8.0f; + m_UIState.LpmExposure = 3.0f; + m_UIState.Contrast = 0.3f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC709; + break; + } + // Lamp + case 1: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 0.0f; + m_UIState.HdrMax = 1024.0f; + m_UIState.LpmExposure = 10.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f; m_UIState.Crosstalk[2] = 1.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC709; + break; + } + // P3 1000 nits + case 2: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 1.0f / 16.0f; + m_UIState.HdrMax = 16.0f; + m_UIState.LpmExposure = 4.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_P3; + break; + } + // Rec2020 1000 nits + case 3: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 1.0f / 32.0f; + m_UIState.HdrMax = 16.0f; + m_UIState.LpmExposure = 4.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC2020; + break; + } + // Rec709 5000 nits + case 4: + { + m_UIState.bShoulder = 1; + m_UIState.SoftGap = 0.0f; + m_UIState.HdrMax = 64.0f; + m_UIState.LpmExposure = 6.0f; + m_UIState.Contrast = 0.0f; + m_UIState.ShoulderContrast = 1.0f; + m_UIState.Saturation[0] = 0.0f; m_UIState.Saturation[1] = 0.0f; m_UIState.Saturation[2] = 0.0f; + m_UIState.Crosstalk[0] = 1.0f; m_UIState.Crosstalk[1] = 1.0f / 2.0f; m_UIState.Crosstalk[2] = 1.0f / 32.0f; + + m_UIState.ColorSpace = ColorSpace::ColorSpace_REC709; + break; + } + } + + bSceneChanged = false; + + m_device.GPUFlush(); + OnUpdateDisplay(); + } + + if (m_activeScene == 0) + { + char* cameraControl[] = { "Orbit", "WASD" }; + ImGui::Combo("Camera", &m_activeCamera, cameraControl, _countof(cameraControl)); + + ImGui::SliderFloat("Emissive Intensity", &m_UIState.EmissiveFactor, 1.0f, 2.0f, NULL, 1.0f); + + for (int i = 0; i < m_pGltfLoader->m_lights.size(); i++) + { + ImGui::SliderFloat(format("Light %i Intensity", i).c_str(), &m_pGltfLoader->m_lights[i].m_intensity, 0.0f, 20.0f); + } + } + } + + ImGui::Spacing(); + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("PostProcessing", ImGuiTreeNodeFlags_DefaultOpen)) + { + const char* tonemappers[] = { "FidelityFX LPM", "AMD Tonemapper", "DX11DSK", "Reinhard", "Uncharted2Tonemap", "ACES", "No tonemapper" }; + ImGui::Combo("Tonemapper", &m_UIState.SelectedTonemapperIndex, tonemappers, _countof(tonemappers)); + + static float exposureStep = 0.0f; + ImGui::SliderFloat("Exposure", &exposureStep, -4.0f, +1.0f, NULL, 1.0f); + m_UIState.Exposure = (float)pow(2, exposureStep); + } + + ImGui::Spacing(); + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("FreeSync HDR", ImGuiTreeNodeFlags_DefaultOpen)) + { + const char* fullscreenModes[] = { "Windowed", "BorderlessFullscreen", "ExclusiveFulscreen" }; + if (ImGui::Combo("Fullscreen Mode", (int*)&m_fullscreenMode, fullscreenModes, _countof(fullscreenModes))) + { + if (m_previousFullscreenMode != m_fullscreenMode) + { + HandleFullScreen(); + m_previousFullscreenMode = m_fullscreenMode; + } + } + + static bool openWarning = false; + const char** displayModeNames = &m_displayModesNamesAvailable[0]; + if (ImGui::Combo("Display Mode", (int*)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) + { + if (m_fullscreenMode != PRESENTATIONMODE_WINDOWED) + { + UpdateDisplay(m_displayModesAvailable[m_currentDisplayModeNamesIndex]); + m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; + } + else if (CheckIfWindowModeHdrOn() && + (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_SDR || + m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_2084 || + m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DISPLAYMODE_HDR10_SCRGB)) + { + UpdateDisplay(m_displayModesAvailable[m_currentDisplayModeNamesIndex]); + m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex; + } + else + { + openWarning = true; + m_currentDisplayModeNamesIndex = m_previousDisplayModeNamesIndex; + } + } + + if (openWarning) + { + ImGui::OpenPopup("Display Modes Warning"); + ImGui::BeginPopupModal("Display Modes Warning", NULL, ImGuiWindowFlags_AlwaysAutoResize); + 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"); + if (ImGui::Button("Cancel", ImVec2(120, 0))) { openWarning = false; ImGui::CloseCurrentPopup(); } + ImGui::EndPopup(); + } + + if (m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_Gamma22 || + m_displayModesAvailable[m_currentDisplayModeNamesIndex] == DisplayMode::DISPLAYMODE_FSHDR_SCRGB) + { + if (ImGui::Checkbox("Enable Local Dimming", &m_enableLocalDimming)) + { + OnLocalDimmingChanged(); + } + } + } + + ImGui::Spacing(); + ImGui::Spacing(); + + #define LPM_CONFIG 0 + #if LPM_CONFIG + if (m_UIState.SelectedTonemapperIndex == 0) + { + ImGui::Spacing(); + ImGui::Spacing(); + static bool bLPMConfigChanged = false; + if (ImGui::CollapsingHeader("LPM Config", ImGuiTreeNodeFlags_DefaultOpen)) + { + bLPMConfigChanged |= ImGui::Checkbox("Shoulder", &m_UIState.bShoulder); + bLPMConfigChanged |= ImGui::SliderFloat("Soft Gap", &m_UIState.SoftGap, 0.0f, 0.5f); + bLPMConfigChanged |= ImGui::SliderFloat("HDR Max", &m_UIState.HdrMax, 8.0f, 2048.0f); + bLPMConfigChanged |= ImGui::SliderFloat("LPM Exposure", &m_UIState.LpmExposure, 3.0f, 11.0f); + bLPMConfigChanged |= ImGui::SliderFloat("Contrast", &m_UIState.Contrast, 0.0f, 1.0f); + bLPMConfigChanged |= ImGui::SliderFloat("Shoulder Contrast", &m_UIState.ShoulderContrast, 1.0f, 1.2f); + bLPMConfigChanged |= ImGui::SliderFloat3("Saturation", &m_UIState.Saturation[0], 0.0f, 1.0f); + bLPMConfigChanged |= ImGui::SliderFloat3("Crosstalk", &m_UIState.Crosstalk[0], 0.0f, 1.0f); + + if (bLPMConfigChanged) + { + bLPMConfigChanged = false; + + m_device.GPUFlush(); + OnUpdateDisplay(); + } + + if (ImGui::Button("Reset Scene defaults (R)")) + { + m_UIState.ResetLPMSceneDefaults(); + } + } + } + #endif + + ImGui::Spacing(); + ImGui::Spacing(); + + if (ImGui::CollapsingHeader("Magnifier", ImGuiTreeNodeFlags_DefaultOpen)) + { + // read in Magnifier pass parameters from the UI & app state + MagnifierPS::PassParameters& params = m_UIState.MagnifierParams; + params.uImageHeight = m_Height; + params.uImageWidth = m_Width; + params.iMousePos[0] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionX : static_cast(io.MousePos.x); + params.iMousePos[1] = m_UIState.bLockMagnifierPosition ? m_UIState.LockedMagnifiedScreenPositionY : static_cast(io.MousePos.y); + + if (ImGui::Checkbox("Show Magnifier (M)", &m_UIState.bUseMagnifier)) + { + // We need to update IMGUI's renderpass to draw to magnfier's renderpass when in hdr + // Hence, flush GPU and update it through OnUpdateDisplay + // Which needs to do the same thing when display mode is changed. + m_device.GPUFlush(); + OnUpdateDisplay(); + } + + DisableUIStateBegin(m_UIState.bUseMagnifier); + { + // use a local bool state here to track locked state through the UI widget, + // and then call ToggleMagnifierLockedState() to update the persistent state (m_UIState). + // the keyboard input for toggling lock directly operates on the persistent state. + const bool bIsMagnifierCurrentlyLocked = m_UIState.bLockMagnifierPosition; + ImGui::Checkbox("Lock Position (L)", &m_UIState.bLockMagnifierPosition); + const bool bWeJustLockedPosition = m_UIState.bLockMagnifierPosition && !bIsMagnifierCurrentlyLocked; + if (bWeJustLockedPosition) + { + m_UIState.ToggleMagnifierLock(); + } + ImGui::SliderFloat("Screen Size", ¶ms.fMagnifierScreenRadius, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); + ImGui::SliderFloat("Magnification", ¶ms.fMagnificationAmount, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); + ImGui::SliderInt("OffsetX", ¶ms.iMagnifierOffset[0], -m_Width, m_Width); + ImGui::SliderInt("OffsetY", ¶ms.iMagnifierOffset[1], -m_Height, m_Height); + } + DisableUIStateEnd(m_UIState.bUseMagnifier); + } + + ImGui::End(); // CONTROLS + } + + + // Render PROFILER window + // + if (m_UIState.bShowProfilerWindow) + { + constexpr size_t NUM_FRAMES = 128; + static float FRAME_TIME_ARRAY[NUM_FRAMES] = { 0 }; + + // track highest frame rate and determine the max value of the graph based on the measured highest value + static float RECENT_HIGHEST_FRAME_TIME = 0.0f; + constexpr int FRAME_TIME_GRAPH_MAX_FPS[] = { 800, 240, 120, 90, 60, 45, 30, 15, 10, 5, 4, 3, 2, 1 }; + static float FRAME_TIME_GRAPH_MAX_VALUES[_countof(FRAME_TIME_GRAPH_MAX_FPS)] = { 0 }; // us + 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]; } + + //scrolling data and average FPS computing + const std::vector& timeStamps = m_pRenderer->GetTimingValues(); + const bool bTimeStampsAvailable = timeStamps.size() > 0; + if (bTimeStampsAvailable) + { + RECENT_HIGHEST_FRAME_TIME = 0; + FRAME_TIME_ARRAY[NUM_FRAMES - 1] = timeStamps.back().m_microseconds; + for (uint32_t i = 0; i < NUM_FRAMES - 1; i++) + { + FRAME_TIME_ARRAY[i] = FRAME_TIME_ARRAY[i + 1]; + } + RECENT_HIGHEST_FRAME_TIME = max(RECENT_HIGHEST_FRAME_TIME, FRAME_TIME_ARRAY[NUM_FRAMES - 1]); + } + const float& frameTime_us = FRAME_TIME_ARRAY[NUM_FRAMES - 1]; + const float frameTime_ms = frameTime_us * 0.001f; + const int fps = bTimeStampsAvailable ? static_cast(1000000.0f / frameTime_us) : 0; + + // UI + ImGui::SetNextWindowPos(ImVec2((float)PROFILER_WINDOW_POS_X, (float)PROFILER_WINDOW_POS_Y), ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSize(ImVec2(PROFILER_WINDOW_SIZE_X, PROFILER_WINDOW_SIZE_Y), ImGuiCond_FirstUseEver); + ImGui::Begin("PROFILER (F2)", &m_UIState.bShowProfilerWindow); + + ImGui::Text("Resolution : %ix%i", m_Width, m_Height); + ImGui::Text("API : %s", m_systemInfo.mGfxAPI.c_str()); + ImGui::Text("GPU : %s", m_systemInfo.mGPUName.c_str()); + ImGui::Text("CPU : %s", m_systemInfo.mCPUName.c_str()); + ImGui::Text("FPS : %d (%.2f ms)", fps, frameTime_ms); + + if (ImGui::CollapsingHeader("GPU Timings", ImGuiTreeNodeFlags_DefaultOpen)) + { + std::string msOrUsButtonText = m_UIState.bShowMilliseconds ? "Switch to microseconds(us)" : "Switch to milliseconds(ms)"; + if (ImGui::Button(msOrUsButtonText.c_str())) { + m_UIState.bShowMilliseconds = !m_UIState.bShowMilliseconds; + } + ImGui::Spacing(); + + // find the index of the FrameTimeGraphMaxValue as the next higher-than-recent-highest-frame-time in the pre-determined value list + size_t iFrameTimeGraphMaxValue = 0; + for (int i = 0; i < _countof(FRAME_TIME_GRAPH_MAX_VALUES); ++i) + { + if (RECENT_HIGHEST_FRAME_TIME < FRAME_TIME_GRAPH_MAX_VALUES[i]) // FRAME_TIME_GRAPH_MAX_VALUES are in increasing order + { + iFrameTimeGraphMaxValue = min(_countof(FRAME_TIME_GRAPH_MAX_VALUES) - 1, i + 1); + break; + } + } + ImGui::PlotLines("", FRAME_TIME_ARRAY, NUM_FRAMES, 0, "GPU frame time (us)", 0.0f, FRAME_TIME_GRAPH_MAX_VALUES[iFrameTimeGraphMaxValue], ImVec2(0, 80)); + + for (uint32_t i = 0; i < timeStamps.size(); i++) + { + float value = m_UIState.bShowMilliseconds ? timeStamps[i].m_microseconds / 1000.0f : timeStamps[i].m_microseconds; + const char* pStrUnit = m_UIState.bShowMilliseconds ? "ms" : "us"; + ImGui::Text("%-18s: %7.2f %s", timeStamps[i].m_label.c_str(), value, pStrUnit); + } + } + ImGui::End(); // PROFILER + } +} + +void UIState::Initialize() +{ + // init magnifier params + for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; // start at 'free' state + + // init GUI state + this->SelectedTonemapperIndex = 0; + this->bUseMagnifier = false; + this->bLockMagnifierPosition = this->bLockMagnifierPositionHistory = false; + this->Exposure = 1.0f; + this->UnusedExposure = 1.0f; + this->EmissiveFactor = 1.0f; + this->bShowControlsWindow = true; + this->bShowProfilerWindow = false; + + this->TestPattern = 0; + this->ColorSpace = ColorSpace::ColorSpace_REC709; + this->bShoulder = 1; + this->SoftGap = 0.0f; + this->HdrMax = 8.0f; + this->LpmExposure = 3.0f; + this->Contrast = 0.3f; + this->ShoulderContrast = 1.0f; + this->Saturation[0] = 0.0f; this->Saturation[1] = 0.0f; this->Saturation[2] = 0.0f; + this->Crosstalk[0] = 1.0f; this->Crosstalk[1] = 1.0f / 2.0f; this->Crosstalk[2] = 1.0f / 32.0f; +} + + + +// +// Magnifier UI Controls +// +void UIState::ToggleMagnifierLock() +{ + if (this->bUseMagnifier) + { + this->bLockMagnifierPositionHistory = this->bLockMagnifierPosition; // record histroy + this->bLockMagnifierPosition = !this->bLockMagnifierPosition; // flip state + const bool bLockSwitchedOn = !this->bLockMagnifierPositionHistory && this->bLockMagnifierPosition; + const bool bLockSwitchedOff = this->bLockMagnifierPositionHistory && !this->bLockMagnifierPosition; + if (bLockSwitchedOn) + { + const ImGuiIO& io = ImGui::GetIO(); + this->LockedMagnifiedScreenPositionX = static_cast(io.MousePos.x); + this->LockedMagnifiedScreenPositionY = static_cast(io.MousePos.y); + for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__LOCKED[ch]; + } + else if (bLockSwitchedOff) + { + for (int ch = 0; ch < 3; ++ch) this->MagnifierParams.fBorderColorRGB[ch] = MAGNIFIER_BORDER_COLOR__FREE[ch]; + } + } +} +// These are currently not bound to any mouse input and are here for convenience/reference. +// Mouse scroll is currently wired up to camera for panning and moving in the local Z direction. +// Any application that would prefer otherwise can utilize these for easily controlling the magnifier parameters through the desired input. +void UIState::AdjustMagnifierSize (float increment /*= 0.05f*/){ MagnifierParams.fMagnifierScreenRadius = clamped(MagnifierParams.fMagnifierScreenRadius + increment, MAGNIFIER_RADIUS_MIN, MAGNIFIER_RADIUS_MAX); } +void UIState::AdjustMagnifierMagnification(float increment /*= 1.00f*/){ MagnifierParams.fMagnificationAmount = clamped(MagnifierParams.fMagnificationAmount + increment, MAGNIFICATION_AMOUNT_MIN, MAGNIFICATION_AMOUNT_MAX); } + +void UIState::ResetLPMSceneDefaults() +{ + if (SelectedTonemapperIndex == 0) + { + bSceneChanged = true; + } +} diff --git a/sample/src/VK/UI.h b/sample/src/VK/UI.h new file mode 100644 index 0000000..374541c --- /dev/null +++ b/sample/src/VK/UI.h @@ -0,0 +1,85 @@ +// AMD SampleVK sample code +// +// Copyright(c) 2020 Advanced Micro Devices, Inc.All rights reserved. +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files(the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and / or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions : +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +#pragma once + +#include "Misc/ColorConversion.h" +#include "PostProc/MagnifierPS.h" +#include + +struct UIState +{ + // + // WINDOW MANAGEMENT + // + bool bShowControlsWindow; + bool bShowProfilerWindow; + + // + // POST PROCESS CONTROLS + // + int SelectedTonemapperIndex; + float Exposure; + float UnusedExposure; + + bool bUseMagnifier; + bool bLockMagnifierPosition; + bool bLockMagnifierPositionHistory; + int LockedMagnifiedScreenPositionX; + int LockedMagnifiedScreenPositionY; + MagnifierPS::PassParameters MagnifierParams; + + // + // APP/SCENE CONTROLS + // + float EmissiveFactor; + + // + // PROFILER CONTROLS + // + bool bShowMilliseconds; + + // + // TEST PATTERN + // + int TestPattern; + ColorSpace ColorSpace; + + // + // LPM CONFIG + // + bool bShoulder; // Use optional extra shoulderContrast tuning (set to false if shoulderContrast is 1.0). + float SoftGap; // Range of 0 to a little over zero, controls how much feather region in out-of-gamut mapping, 0=clip. + float HdrMax; // Maximum input value. + float LpmExposure; // Number of stops between 'hdrMax' and 18% mid-level on input. + float Contrast; // Input range {0.0 (no extra contrast) to 1.0 (maximum contrast)}. + float ShoulderContrast; // Shoulder shaping, 1.0 = no change (fast path). + float Saturation[3]; // A per channel adjustment, use <0 decrease, 0=no change, >0 increase. + float Crosstalk[3]; // One channel must be 1.0, the rest can be <= 1.0 but not zero. + + // ----------------------------------------------- + + void Initialize(); + + void ToggleMagnifierLock(); + void AdjustMagnifierSize(float increment = 0.05f); + void AdjustMagnifierMagnification(float increment = 1.00f); + + void ResetLPMSceneDefaults(); +}; \ No newline at end of file diff --git a/sample/src/VK/dpiawarescaling.manifest b/sample/src/VK/dpiawarescaling.manifest new file mode 100644 index 0000000..8dd8cd9 --- /dev/null +++ b/sample/src/VK/dpiawarescaling.manifest @@ -0,0 +1,8 @@ + + + + + true/PM + + + \ No newline at end of file diff --git a/sample/src/VK/shaders/ExposureMultiplierCS.glsl b/sample/src/VK/shaders/ExposureMultiplierCS.glsl index a82def2..b956276 100644 --- a/sample/src/VK/shaders/ExposureMultiplierCS.glsl +++ b/sample/src/VK/shaders/ExposureMultiplierCS.glsl @@ -23,7 +23,7 @@ #extension GL_ARB_shading_language_420pack : enable #extension GL_ARB_compute_shader : enable -layout (std140, binding = 0) uniform perBatch +layout (std140, binding = 0) uniform perBatch { float u_exposure; } myPerScene; diff --git a/sample/src/VK/shaders/FlipBookAnimationPS.glsl b/sample/src/VK/shaders/FlipBookAnimationPS.glsl index 70315f7..119f8ca 100644 --- a/sample/src/VK/shaders/FlipBookAnimationPS.glsl +++ b/sample/src/VK/shaders/FlipBookAnimationPS.glsl @@ -27,9 +27,9 @@ layout (location = 0) out vec4 outColor; layout(set=0, binding=1) uniform sampler2D sSampler; -void main() +void main() { // Push the camp fire outside of rec709 gamut - outColor = texture(sSampler, inTexCoord.st); - outColor *= 2.0; + outColor = texture(sSampler, inTexCoord.st); + outColor *= 2.0; } \ No newline at end of file diff --git a/sample/src/VK/shaders/FlipBookAnimationVS.glsl b/sample/src/VK/shaders/FlipBookAnimationVS.glsl index 6e36b5b..4c8c907 100644 --- a/sample/src/VK/shaders/FlipBookAnimationVS.glsl +++ b/sample/src/VK/shaders/FlipBookAnimationVS.glsl @@ -66,7 +66,7 @@ void main() vec2 offset = vec2(size.x*indexX, size.y*indexY); // get single sprite UV - vec2 newUV = inTexCoord * size; + vec2 newUV = inTexCoord * size; // Slight offset in Y because of visual seam newUV.y += 0.001; diff --git a/sample/src/VK/shaders/LPMPS.glsl b/sample/src/VK/shaders/LPMPS.glsl index b7b1255..d759fef 100644 --- a/sample/src/VK/shaders/LPMPS.glsl +++ b/sample/src/VK/shaders/LPMPS.glsl @@ -26,7 +26,7 @@ layout (location = 0) in vec2 inTexCoord; layout (location = 0) out vec4 outColor; -layout (std140, binding = 0) uniform perBatch +layout (std140, binding = 0) uniform perBatch { bool u_shoulder; bool u_con; @@ -61,7 +61,7 @@ AU4 LpmFilterCtl(AU1 i) #include "transferfunction.h" -void main() +void main() { vec4 color = texture(sSampler, inTexCoord.st); @@ -77,7 +77,7 @@ void main() switch (myPerScene.u_displayMode) { - case 1: + case 1: // FS2_DisplayNative // Apply gamma color.xyz = ApplyGamma(color.rgb); diff --git a/sample/src/VK/shaders/TestImagesPS.glsl b/sample/src/VK/shaders/TestImagesPS.glsl index c5bd861..9459169 100644 --- a/sample/src/VK/shaders/TestImagesPS.glsl +++ b/sample/src/VK/shaders/TestImagesPS.glsl @@ -28,7 +28,7 @@ layout (location = 0) out vec4 outColor; layout (set=0, binding = 0, std140) uniform perFrame { - int u_testPattern; + int u_testPattern; } myPerFrame; layout(set=0, binding=1) uniform sampler2D sSampler; @@ -36,7 +36,7 @@ layout(set=0, binding=1) uniform sampler2D sSampler; void main() { vec4 texColor = vec4(1.0,1.0,1.0,1.0); - switch (myPerFrame.u_testPattern) + switch (myPerFrame.u_testPattern) { case 0: case 1: diff --git a/sample/src/VK/stdafx.h b/sample/src/VK/stdafx.h index a7c28a3..e67838f 100644 --- a/sample/src/VK/stdafx.h +++ b/sample/src/VK/stdafx.h @@ -31,63 +31,59 @@ // C RunTime Header Files #include #include +#include #include #include -#include -#define VK_USE_PLATFORM_WIN32_KHR 1 #include "vulkan/vulkan.h" - -// we are using DirectXMath -#include -using namespace DirectX; +// Pull in math library +#include "../../libs/vectormath/vectormath.hpp" // TODO: reference additional headers your program requires here -#include "base\Imgui.h" -#include "Base\ImguiHelper.h" -#include "base\Texture.h" -#include "base\Device.h" -#include "base\SwapChain.h" -#include "base\ExtFreeSyncHDR.h" -#include "Base\FreeSyncHDR.h" -#include "Base\Helper.h" -#include "base\UploadHeap.h" -#include "base\GPUTimeStamps.h" -#include "Base\ExtDebugMarkers.h" -#include "base\CommandListRing.h" -#include "base\StaticBufferPool.h" -#include "base\DynamicBufferRing.h" -#include "base\ResourceViewHeaps.h" -#include "Base\ShaderCompilerHelper.h" +#include "Base/Imgui.h" +#include "Base/ImguiHelper.h" +#include "Base/Device.h" +#include "Base/Helper.h" +#include "Base/Texture.h" +#include "Base/FrameworkWindows.h" +#include "Base/FreeSyncHDR.h" +#include "Base/SwapChain.h" +#include "Base/UploadHeap.h" +#include "Base/GPUTimeStamps.h" +#include "Base/CommandListRing.h" +#include "Base/StaticBufferPool.h" +#include "Base/DynamicBufferRing.h" +#include "Base/ResourceViewHeaps.h" +#include "Base/ShaderCompilerCache.h" +#include "Base/ShaderCompilerHelper.h" -#include "Misc\Error.h" -#include "misc\Misc.h" -#include "misc\Camera.h" +#include "GLTF/GltfPbrPass.h" +#include "GLTF/GltfBBoxPass.h" +#include "GLTF/GltfDepthPass.h" -#include "GLTF\GltfPbrPass.h" -#include "GLTF\GltfBBoxPass.h" -#include "GLTF\GltfDepthPass.h" +#include "Misc/Misc.h" +#include "Misc/Camera.h" -#include "PostProc\Bloom.h" -#include "PostProc\BlurPS.h" -#include "PostProc\SkyDome.h" -#include "PostProc\SkyDomeProc.h" -#include "PostProc\DownSamplePS.h" -#include "PostProc\ColorConversionPS.h" -#include "PostProc\ToneMapping.h" -#include "PostProc\ToneMappingCS.h" +#include "PostProc/TAA.h" +#include "PostProc/Bloom.h" +#include "PostProc/BlurPS.h" +#include "PostProc/SkyDome.h" +#include "PostProc/ToneMapping.h" +#include "PostProc/ToneMappingCS.h" +#include "PostProc/ColorConversionPS.h" +#include "PostProc/SkyDomeProc.h" +#include "PostProc/DownSamplePS.h" -#include "TestImages.h" -#include "FlipBookAnimation.h" -#include "LPMPS.h" -#include "ExposureMultiplierCS.h" -#include "Widgets\Axis.h" -#include "Widgets\CheckerBoardFloor.h" +#include "Widgets/Axis.h" +#include "Widgets/CheckerBoardFloor.h" +#include "Widgets/WireframeBox.h" +#include "Widgets/WireframeSphere.h" -#include "..\common\Misc\Camera.h" -#include "..\common\Misc\FrameworkWindows.h" -#include "..\common\Misc\ColorConversion.h" +#include "FlipBookAnimation.h" +#include "TestImages.h" +#include "ExposureMultiplierCS.h" +#include "LPMPS.h" using namespace CAULDRON_VK; \ No newline at end of file