From 41f6e27e5a03ecbe4f9ddff6a5221edca6640a81 Mon Sep 17 00:00:00 2001 From: Rys Sommefeldt Date: Thu, 27 Aug 2020 12:15:22 +0100 Subject: [PATCH] FidelityFX LPM sample release v1.1 --- .gitlab-ci.yml | 18 + readme.md | 15 +- sample/CMakeLists.txt | 4 + sample/build/GenerateSolutions.bat | 5 + sample/libs/cauldron | 2 +- sample/src/DX12/FlipBookAnimation.cpp | 4 +- sample/src/DX12/LPMPS.cpp | 36 +- sample/src/DX12/LPMPS.h | 13 +- sample/src/DX12/LPMSample.cpp | 39 +- sample/src/DX12/LPMSample.h | 6 + sample/src/DX12/SampleRenderer.cpp | 2 + sample/src/DX12/shaders/LPMPS.hlsl | 97 +- sample/src/DX12/stdafx.h | 2 +- sample/src/VK/CMakeLists.txt | 55 + sample/src/VK/ExposureMultiplierCS.cpp | 89 ++ sample/src/VK/ExposureMultiplierCS.h | 52 + sample/src/VK/FlipBookAnimation.cpp | 341 +++++ sample/src/VK/FlipBookAnimation.h | 84 ++ sample/src/VK/LPMPS.cpp | 343 +++++ sample/src/VK/LPMPS.h | 95 ++ sample/src/VK/LPMSample.cpp | 440 +++++++ sample/src/VK/LPMSample.h | 80 ++ sample/src/VK/SampleRenderer.cpp | 1148 +++++++++++++++++ sample/src/VK/SampleRenderer.h | 138 ++ sample/src/VK/TestImages.cpp | 98 ++ sample/src/VK/TestImages.h | 57 + .../src/VK/shaders/ExposureMultiplierCS.glsl | 43 + .../src/VK/shaders/FlipBookAnimationPS.glsl | 35 + .../src/VK/shaders/FlipBookAnimationVS.glsl | 75 ++ sample/src/VK/shaders/LPMPS.glsl | 94 ++ sample/src/VK/shaders/TestImagesPS.glsl | 101 ++ sample/src/VK/shaders/transferFunction.h | 44 + sample/src/VK/stdafx.cpp | 29 + sample/src/VK/stdafx.h | 93 ++ 34 files changed, 3643 insertions(+), 134 deletions(-) create mode 100644 sample/src/VK/CMakeLists.txt create mode 100644 sample/src/VK/ExposureMultiplierCS.cpp create mode 100644 sample/src/VK/ExposureMultiplierCS.h create mode 100644 sample/src/VK/FlipBookAnimation.cpp create mode 100644 sample/src/VK/FlipBookAnimation.h create mode 100644 sample/src/VK/LPMPS.cpp create mode 100644 sample/src/VK/LPMPS.h create mode 100644 sample/src/VK/LPMSample.cpp create mode 100644 sample/src/VK/LPMSample.h create mode 100644 sample/src/VK/SampleRenderer.cpp create mode 100644 sample/src/VK/SampleRenderer.h create mode 100644 sample/src/VK/TestImages.cpp create mode 100644 sample/src/VK/TestImages.h create mode 100644 sample/src/VK/shaders/ExposureMultiplierCS.glsl create mode 100644 sample/src/VK/shaders/FlipBookAnimationPS.glsl create mode 100644 sample/src/VK/shaders/FlipBookAnimationVS.glsl create mode 100644 sample/src/VK/shaders/LPMPS.glsl create mode 100644 sample/src/VK/shaders/TestImagesPS.glsl create mode 100644 sample/src/VK/shaders/transferFunction.h create mode 100644 sample/src/VK/stdafx.cpp create mode 100644 sample/src/VK/stdafx.h diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bb1a277..118c21f 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -20,6 +20,19 @@ build_dx12: - 'cmake -S . -B build/DX12 -DGFX_API=DX12 %CMakeConfig%' - 'cmake --build build/DX12 --config Release' +build_vk: + tags: + - windows + - amd64 + stage: build + artifacts: + paths: + - sample/bin/ + script: + - 'cd sample' + - 'cmake -S . -B build/Vk -DGFX_API=VK %CMakeConfig%' + - 'cmake --build build/Vk --config Release' + package_sample: tags: - windows @@ -27,11 +40,15 @@ package_sample: stage: deploy dependencies: - build_dx12 + - build_vk script: - mkdir "%SampleName%" - move sample/bin "%SampleName%" + - copy %VULKAN_SDK%\Bin\glslc.exe %SampleName%\bin - move NOTICES.txt %SampleName% - move sample/media %SampleName% + - echo cd .\%SampleName%\bin\ > %SampleName%_VK.bat + - echo start %SampleName%_VK.exe >> %SampleName%_VK.bat - echo cd .\%SampleName%\bin\ > %SampleName%_DX12.bat - echo start %SampleName%_DX12.exe >> %SampleName%_DX12.bat artifacts: @@ -40,4 +57,5 @@ package_sample: - "%SampleName%/bin/" - "%SampleName%/NOTICES.txt" - "%SampleName%/media" + - "%SampleName%_VK.bat" - "%SampleName%_DX12.bat" \ No newline at end of file diff --git a/readme.md b/readme.md index 3d834f5..314fc71 100644 --- a/readme.md +++ b/readme.md @@ -5,7 +5,7 @@ Luma Preserving Mapper is a tone mapping and gamut mapping solution for HDR and ### Sample Overview: -- This sample is meant to show LPM integration into DX12. +- This sample is meant to show LPM integration into DX12 and Vulkan API. - LPM is a single header tone and gamut mapping solutions tailored to work for HDR and wide gamut colour pipelines and displays. #### FidelityFX LPM Off @@ -23,6 +23,7 @@ Luma Preserving Mapper is a tone mapping and gamut mapping solution for HDR and - [CMake 3.4](https://cmake.org/download/) - [Visual Studio 2017](https://visualstudio.microsoft.com/downloads/) - [Windows 10 SDK 10.0.18362.0](https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk) + - [Vulkan SDK 1.2.131.1](https://www.lunarg.com/vulkan-sdk/) #### Running the LPM Sample: @@ -39,7 +40,7 @@ Luma Preserving Mapper is a tone mapping and gamut mapping solution for HDR and GenerateSolutions.bat ``` -- Open the solution in the DX12 directory, compile and run. +- Open the solutions in the VK or DX12 directories, compile and run. - The tonemapper selected in GUI will already be set to LPM. - If using HDR10 or FS2 displays, you can also change display mode option in UI. - Use test pattern option in UI to do accuracy testing of LPM on different colour swatches or test HDR photograph image. @@ -54,10 +55,10 @@ ffx_lpm.h: - A common header file for CPU side setup of the mapper and GPU side setup and tone and gamut map calculation functions. - LpmSetup() used to setup all the data required by mapper in a control block. - Information like: - - What is the content gamut. - - What is the display gamut. - - Max brightness value of content in RGB. - - Exposure steps above SDR/LDR 1.0 + - What is the content gamut. + - What is the display gamut. + - Max brightness value of content in RGB. + - Exposure steps above SDR/LDR 1.0 - LPMFilter() used to do the calculations for mapper by reading data from the control block. - For detailed intructions please read comments in ffx_lpm.h @@ -65,6 +66,6 @@ LPMPS.cpp: - CPU side setup code for LPM. - Select the right LPM_config_*_* and LPM_color_*_* configurations based on content gamut and display mode selected. -LPMPS.hlsl: +LPMPS.hlsl/glsl: - GPU side call to do the tone and gamut mapping. - Select right configurations of LPM_config_*_* based on content gamut and displaymode selected. diff --git a/sample/CMakeLists.txt b/sample/CMakeLists.txt index f7684c6..4bc5a79 100644 --- a/sample/CMakeLists.txt +++ b/sample/CMakeLists.txt @@ -17,6 +17,9 @@ set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY VS_STARTUP_PROJECT $ if(GFX_API STREQUAL DX12) add_subdirectory(src/DX12) +elseif(GFX_API STREQUAL VK) + find_package(Vulkan REQUIRED) + add_subdirectory(src/VK) else() message(STATUS "----------------------------------------------------------------------------------------") message(STATUS "") @@ -26,6 +29,7 @@ else() message(STATUS "") message(STATUS " Examples:") message(STATUS " cmake -DGFX_API=DX12") + message(STATUS " cmake -DGFX_API=VK") message(STATUS "") message(STATUS "----------------------------------------------------------------------------------------") message(FATAL_ERROR "") diff --git a/sample/build/GenerateSolutions.bat b/sample/build/GenerateSolutions.bat index 383eadb..5ee4fbc 100644 --- a/sample/build/GenerateSolutions.bat +++ b/sample/build/GenerateSolutions.bat @@ -1,4 +1,9 @@ mkdir DX12 cd DX12 cmake ..\.. -DGFX_API=DX12 +cd .. + +mkdir VK +cd VK +cmake ..\.. -DGFX_API=VK cd .. \ No newline at end of file diff --git a/sample/libs/cauldron b/sample/libs/cauldron index fd91cd7..050b274 160000 --- a/sample/libs/cauldron +++ b/sample/libs/cauldron @@ -1 +1 @@ -Subproject commit fd91cd744d014505daef1780dceee49fd62ce953 +Subproject commit 050b274df95777d688686d017a6926a515a58b30 diff --git a/sample/src/DX12/FlipBookAnimation.cpp b/sample/src/DX12/FlipBookAnimation.cpp index d6dc8e8..60dba67 100644 --- a/sample/src/DX12/FlipBookAnimation.cpp +++ b/sample/src/DX12/FlipBookAnimation.cpp @@ -76,8 +76,8 @@ namespace CAULDRON_DX12 D3D12_SHADER_BYTECODE shaderVert, shaderPixel; { DefineList defines; - CompileShaderFromFile("FlipBookAnimationVS.hlsl", &defines, "mainVS", "vs_5_0", 0, &shaderVert); - CompileShaderFromFile("FlipBookAnimationPS.hlsl", &defines, "mainPS", "ps_5_0", 0, &shaderPixel); + CompileShaderFromFile("FlipBookAnimationVS.hlsl", &defines, "mainVS", "-T vs_6_0", &shaderVert); + CompileShaderFromFile("FlipBookAnimationPS.hlsl", &defines, "mainPS", "-T ps_6_0", &shaderPixel); } // Create root signature diff --git a/sample/src/DX12/LPMPS.cpp b/sample/src/DX12/LPMPS.cpp index 7b6aff4..e523af3 100644 --- a/sample/src/DX12/LPMPS.cpp +++ b/sample/src/DX12/LPMPS.cpp @@ -21,7 +21,7 @@ #include "Base/DynamicBufferRing.h" #include "Base/ShaderCompiler.h" #include "Base/UploadHeap.h" -#include "Base/Freesync2.h" +#include "Base/FreesyncHDR.h" #include "Misc/ColorConversion.h" #include "LPMPS.h" @@ -60,7 +60,7 @@ namespace CAULDRON_DX12 SamplerDesc.RegisterSpace = 0; SamplerDesc.ShaderVisibility = D3D12_SHADER_VISIBILITY_PIXEL; - m_lpm.OnCreate(pDevice, "LPMPS.hlsl", pResourceViewHeaps, pStaticBufferPool, 1, 1, &SamplerDesc, outFormat, 1, NULL, NULL, 1, "vs_6_0", "ps_6_0"); + m_lpm.OnCreate(pDevice, "LPMPS.hlsl", pResourceViewHeaps, pStaticBufferPool, 1, 1, &SamplerDesc, outFormat, 1, NULL, NULL, 1); } void LPMPS::OnDestroy() @@ -107,11 +107,10 @@ namespace CAULDRON_DX12 m_lpm.UpdatePipeline(outFormat); m_displayMode = displayMode; - m_colorSpace = colorSpace; SetupGamutMapperMatrices( ColorSpace_REC709, - m_colorSpace, + colorSpace, &m_inputToOutputMatrix ); @@ -122,7 +121,7 @@ namespace CAULDRON_DX12 varAF2(displayMinMaxLuminance); if (displayMode != DISPLAYMODE_SDR) { - const AGSDisplayInfo *agsDisplayInfo = fs2GetDisplayInfo(); + const AGSDisplayInfo *agsDisplayInfo = fsHdrGetDisplayInfo(); // Only used in fs2 modes fs2R[0] = (float) agsDisplayInfo->chromaticityRedX; @@ -147,23 +146,23 @@ namespace CAULDRON_DX12 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; - switch (m_colorSpace) + switch (colorSpace) { case ColorSpace_REC709: { - switch (m_displayMode) + switch (displayMode) { case DISPLAYMODE_SDR: SetLPMConfig(LPM_CONFIG_709_709); SetLPMColors(LPM_COLORS_709_709); break; - case DISPLAYMODE_FS2_Gamma22: + case DISPLAYMODE_FSHDR_Gamma22: SetLPMConfig(LPM_CONFIG_FS2RAW_709); SetLPMColors(LPM_COLORS_FS2RAW_709); break; - case DISPLAYMODE_FS2_SCRGB: + case DISPLAYMODE_FSHDR_SCRGB: fs2S = LpmFs2ScrgbScalar(displayMinMaxLuminance[0], displayMinMaxLuminance[1]); SetLPMConfig(LPM_CONFIG_FS2SCRGB_709); SetLPMColors(LPM_COLORS_FS2SCRGB_709); @@ -196,12 +195,12 @@ namespace CAULDRON_DX12 SetLPMColors(LPM_COLORS_709_P3); break; - case DISPLAYMODE_FS2_Gamma22: + case DISPLAYMODE_FSHDR_Gamma22: SetLPMConfig(LPM_CONFIG_FS2RAW_P3); SetLPMColors(LPM_COLORS_FS2RAW_P3); break; - case DISPLAYMODE_FS2_SCRGB: + case DISPLAYMODE_FSHDR_SCRGB: fs2S = LpmFs2ScrgbScalar(displayMinMaxLuminance[0], displayMinMaxLuminance[1]); SetLPMConfig(LPM_CONFIG_FS2SCRGB_P3); SetLPMColors(LPM_COLORS_FS2SCRGB_P3); @@ -234,12 +233,12 @@ namespace CAULDRON_DX12 SetLPMColors(LPM_COLORS_709_2020); break; - case DISPLAYMODE_FS2_Gamma22: + case DISPLAYMODE_FSHDR_Gamma22: SetLPMConfig(LPM_CONFIG_FS2RAW_2020); SetLPMColors(LPM_COLORS_FS2RAW_2020); break; - case DISPLAYMODE_FS2_SCRGB: + case DISPLAYMODE_FSHDR_SCRGB: fs2S = LpmFs2ScrgbScalar(displayMinMaxLuminance[0], displayMinMaxLuminance[1]); SetLPMConfig(LPM_CONFIG_FS2SCRGB_2020); SetLPMColors(LPM_COLORS_FS2SCRGB_2020); @@ -283,10 +282,15 @@ namespace CAULDRON_DX12 D3D12_GPU_VIRTUAL_ADDRESS cbLPMHandle; LPMConsts *pLPM; m_pDynamicBufferRing->AllocConstantBuffer(sizeof(LPMConsts), (void **)&pLPM, &cbLPMHandle); - pLPM->inputToOutputMatrix = m_inputToOutputMatrix; - pLPM->displayMode = m_displayMode; - pLPM->colorSpaces = m_colorSpace; pLPM->shoulder = m_shoulder; + pLPM->con = m_con; + pLPM->soft = m_soft; + pLPM->con2 = m_con2; + pLPM->clip = m_clip; + pLPM->scaleOnly = m_scaleOnly; + pLPM->displayMode = m_displayMode; + pLPM->pad = 0; + pLPM->inputToOutputMatrix = m_inputToOutputMatrix; for (int i = 0; i < 4 * 24; ++i) { pLPM->ctl[i] = ctl[i]; diff --git a/sample/src/DX12/LPMPS.h b/sample/src/DX12/LPMPS.h index 6e0d6ac..af36220 100644 --- a/sample/src/DX12/LPMPS.h +++ b/sample/src/DX12/LPMPS.h @@ -62,14 +62,17 @@ namespace CAULDRON_DX12 DynamicBufferRing *m_pDynamicBufferRing = NULL; DisplayModes m_displayMode; - ColorSpace m_colorSpace; XMMATRIX m_inputToOutputMatrix; struct LPMConsts { - int colorSpaces; - int displayMode; - bool shoulder; - float pad; + UINT shoulder; + UINT con; + UINT soft; + UINT con2; + UINT clip; + UINT scaleOnly; + UINT displayMode; + UINT pad; XMMATRIX inputToOutputMatrix; uint32_t ctl[24 * 4]; }; diff --git a/sample/src/DX12/LPMSample.cpp b/sample/src/DX12/LPMSample.cpp index dab33fd..233196b 100644 --- a/sample/src/DX12/LPMSample.cpp +++ b/sample/src/DX12/LPMSample.cpp @@ -21,8 +21,6 @@ #include "LPMSample.h" -static const bool VALIDATION_ENABLED = false; - LPMSample::LPMSample(LPCSTR name) : FrameworkWindows(name) { m_lastFrameTime = MillisecondsNow(); @@ -30,10 +28,23 @@ LPMSample::LPMSample(LPCSTR name) : FrameworkWindows(name) m_bPlay = true; m_pGltfLoader = NULL; - m_previousDisplayMode = m_currentDisplayMode = DISPLAYMODE_SDR; + m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; m_disableLocalDimming = false; } +//-------------------------------------------------------------------------------------- +// +// OnParseCommandLine +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight, bool* pbFullScreen) +{ + // set some default values + *pWidth = 1920; + *pHeight = 1080; + *pbFullScreen = false; +} + //-------------------------------------------------------------------------------------- // // OnCreate @@ -43,10 +54,11 @@ void LPMSample::OnCreate(HWND hWnd) { // Create Device // - m_device.OnCreate("myapp", "myEngine", VALIDATION_ENABLED, hWnd); + m_device.OnCreate("myapp", "myEngine", m_isCpuValidationLayerEnabled, m_isGpuValidationLayerEnabled, hWnd); m_device.CreatePipelineCache(); //init the shader compiler + InitDirectXCompiler(); CreateShaderCache(); // Create Swapchain @@ -88,7 +100,7 @@ void LPMSample::OnDestroy() m_device.GPUFlush(); // Set display mode to SDR before quitting. - m_previousDisplayMode = m_currentDisplayMode = DISPLAYMODE_SDR; + m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; // Fullscreen state should always be false before exiting the app. m_swapChain.SetFullScreen(false); @@ -139,7 +151,7 @@ void LPMSample::SetFullScreen(bool fullscreen) // when going to windowed make sure we are always using SDR if ((fullscreen == false) && (m_currentDisplayMode != DISPLAYMODE_SDR)) - m_previousDisplayMode = m_currentDisplayMode = DISPLAYMODE_SDR; + m_previousDisplayMode = m_currentDisplayMode = m_previousDisplayModeNamesIndex = m_currentDisplayModeNamesIndex = DISPLAYMODE_SDR; m_swapChain.SetFullScreen(fullscreen); } @@ -196,6 +208,7 @@ void LPMSample::OnActivate(bool windowActive) return; 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); } @@ -264,23 +277,25 @@ void LPMSample::OnRender() 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", }; + 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_currentDisplayMode, displayModeNames, (int)m_displayModesNamesAvailable.size())) + if (ImGui::Combo("Display Mode", (int *)&m_currentDisplayModeNamesIndex, displayModeNames, (int)m_displayModesNamesAvailable.size())) { if (m_swapChain.IsFullScreen()) { - m_previousDisplayMode = m_currentDisplayMode = m_displayModesAvailable[m_currentDisplayMode]; + 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; } } @@ -293,7 +308,7 @@ void LPMSample::OnRender() ImGui::EndPopup(); } - if (m_currentDisplayMode == DisplayModes::DISPLAYMODE_FS2_Gamma22 || m_currentDisplayMode == DisplayModes::DISPLAYMODE_FS2_SCRGB) + if (m_currentDisplayMode == DisplayModes::DISPLAYMODE_FSHDR_Gamma22 || m_currentDisplayMode == DisplayModes::DISPLAYMODE_FSHDR_SCRGB) { if (ImGui::Checkbox("Disable Local Dimming", &m_disableLocalDimming)) { @@ -402,10 +417,8 @@ int WINAPI WinMain(HINSTANCE hInstance, int nCmdShow) { LPCSTR Name = "LPMSample DX12 v1.0"; - uint32_t Width = 1280; - uint32_t Height = 720; // create new DX sample - return RunFramework(hInstance, lpCmdLine, nCmdShow, Width, Height, new LPMSample(Name)); + return RunFramework(hInstance, lpCmdLine, nCmdShow, new LPMSample(Name)); } diff --git a/sample/src/DX12/LPMSample.h b/sample/src/DX12/LPMSample.h index 812a7f9..b0de4a5 100644 --- a/sample/src/DX12/LPMSample.h +++ b/sample/src/DX12/LPMSample.h @@ -40,6 +40,7 @@ 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(); @@ -55,6 +56,8 @@ class LPMSample : public FrameworkWindows DisplayModes m_previousDisplayMode; DisplayModes m_currentDisplayMode; + DisplayModes m_previousDisplayModeNamesIndex; + DisplayModes m_currentDisplayModeNamesIndex; std::vector m_displayModesAvailable; std::vector m_displayModesNamesAvailable; bool m_disableLocalDimming; @@ -68,5 +71,8 @@ class LPMSample : public FrameworkWindows double m_deltaTime; // The elapsed time since the previous frame. double m_lastFrameTime; + bool m_isCpuValidationLayerEnabled = false; + bool m_isGpuValidationLayerEnabled = false; + bool m_bPlay; }; diff --git a/sample/src/DX12/SampleRenderer.cpp b/sample/src/DX12/SampleRenderer.cpp index b13c566..85d66f5 100644 --- a/sample/src/DX12/SampleRenderer.cpp +++ b/sample/src/DX12/SampleRenderer.cpp @@ -262,10 +262,12 @@ int SampleRenderer::LoadScene(GLTFCommon *pGLTFCommon, int stage) &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) diff --git a/sample/src/DX12/shaders/LPMPS.hlsl b/sample/src/DX12/shaders/LPMPS.hlsl index 4602fa3..7a3a964 100644 --- a/sample/src/DX12/shaders/LPMPS.hlsl +++ b/sample/src/DX12/shaders/LPMPS.hlsl @@ -22,10 +22,14 @@ //-------------------------------------------------------------------------------------- cbuffer cbPerFrame : register(b0) { - int u_colourSpace; - int u_displayMode; bool u_shoulder; - float u_pad; + bool u_con; + bool u_soft; + bool u_con2; + bool u_clip; + bool u_scaleOnly; + uint u_displayMode; + uint pad; matrix u_inputToOutputMatrix; uint4 u_ctl[24]; } @@ -70,92 +74,7 @@ float4 mainPS(VERTEX Input) : SV_Target color.b = max(0, color.b); // - switch (u_colourSpace) - { - // REC 709 - case 0: - { - switch (u_displayMode) - { - case 0: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_709_709); - break; - - case 1: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_FS2RAW_709); - break; - - case 2: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_FS2SCRGB_709); - break; - - case 3: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_HDR10RAW_709); - break; - - case 4: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_HDR10SCRGB_709); - break; - } - break; - } - - // P3 - case 1: - { - switch (u_displayMode) - { - case 0: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_709_P3); - break; - - case 1: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_FS2RAW_P3); - break; - - case 2: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_FS2SCRGB_P3); - break; - - case 3: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_HDR10RAW_P3); - break; - - case 4: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_HDR10SCRGB_P3); - break; - } - break; - } - - // REC2020 - case 2: - { - switch (u_displayMode) - { - case 0: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_709_2020); - break; - - case 1: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_FS2RAW_2020); - break; - - case 2: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_FS2SCRGB_2020); - break; - - case 3: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_HDR10RAW_2020); - break; - - case 4: - LpmFilter(color.r, color.g, color.b, u_shoulder, LPM_CONFIG_HDR10SCRGB_2020); - break; - } - break; - } - } + LpmFilter(color.r, color.g, color.b, u_shoulder, u_con, u_soft, u_con2, u_clip, u_scaleOnly); switch (u_displayMode) { diff --git a/sample/src/DX12/stdafx.h b/sample/src/DX12/stdafx.h index 0bf41a3..5afdaeb 100644 --- a/sample/src/DX12/stdafx.h +++ b/sample/src/DX12/stdafx.h @@ -47,7 +47,7 @@ using namespace DirectX; #include "base\Fence.h" #include "Base\Helper.h" #include "Base\Device.h" -#include "base\Freesync2.h" +#include "base\FreesyncHDR.h" #include "base\Texture.h" #include "base\SwapChain.h" #include "base\UploadHeap.h" diff --git a/sample/src/VK/CMakeLists.txt b/sample/src/VK/CMakeLists.txt new file mode 100644 index 0000000..511915d --- /dev/null +++ b/sample/src/VK/CMakeLists.txt @@ -0,0 +1,55 @@ +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) + +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) +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() +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 new file mode 100644 index 0000000..df2b2fa --- /dev/null +++ b/sample/src/VK/ExposureMultiplierCS.cpp @@ -0,0 +1,89 @@ +// AMD AMDUtils code +// +// Copyright(c) 2018 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 "Base/DynamicBufferRing.h" +#include "Base/StaticBufferPool.h" +#include "Base/ExtDebugMarkers.h" +#include "Base/UploadHeap.h" +#include "Base/Helper.h" +#include "ExposureMultiplierCS.h" + +namespace CAULDRON_VK +{ + void ExposureMultiplierCS::OnCreate(Device* pDevice, ResourceViewHeaps *pResourceViewHeaps, DynamicBufferRing *pDynamicBufferRing) + { + m_pDevice = pDevice; + m_pDynamicBufferRing = pDynamicBufferRing; + m_pResourceViewHeaps = pResourceViewHeaps; + + std::vector layoutBindings(2); + layoutBindings[0].binding = 0; + layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + layoutBindings[0].descriptorCount = 1; + layoutBindings[0].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + layoutBindings[0].pImmutableSamplers = NULL; + + layoutBindings[1].binding = 1; + layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_STORAGE_IMAGE; + layoutBindings[1].descriptorCount = 1; + layoutBindings[1].stageFlags = VK_SHADER_STAGE_COMPUTE_BIT; + layoutBindings[1].pImmutableSamplers = NULL; + + m_pResourceViewHeaps->CreateDescriptorSetLayout(&layoutBindings, &m_descriptorSetLayout); + + m_ExposureMultiplier.OnCreate(pDevice, "ExposureMultiplierCS.glsl", "main", "", m_descriptorSetLayout, 8, 8, 1, NULL); + + m_descriptorIndex = 0; + for (int i = 0; i < s_descriptorBuffers; i++) + m_pResourceViewHeaps->AllocDescriptor(m_descriptorSetLayout, &m_descriptorSet[i]); + } + + void ExposureMultiplierCS::OnDestroy() + { + m_ExposureMultiplier.OnDestroy(); + + for (int i = 0; i < s_descriptorBuffers; i++) + m_pResourceViewHeaps->FreeDescriptor(m_descriptorSet[i]); + + vkDestroyDescriptorSetLayout(m_pDevice->GetDevice(), m_descriptorSetLayout, NULL); + } + + void ExposureMultiplierCS::Draw(VkCommandBuffer cmd_buf, VkImageView HDRSRV, float exposure, int width, int height) + { + SetPerfMarkerBegin(cmd_buf, "ExposureMultiplierCS"); + + VkDescriptorBufferInfo cbExposureMultiplierHandle; + ExposureMultiplierConsts *pExposureMultiplierConsts; + m_pDynamicBufferRing->AllocConstantBuffer(sizeof(ExposureMultiplierConsts), (void **)&pExposureMultiplierConsts, &cbExposureMultiplierHandle); + pExposureMultiplierConsts->m_exposure = exposure; + + // We'll be modifying the descriptor set(DS), to prevent writing on a DS that is in use we + // need to do some basic buffering. Just to keep it safe and simple we'll have 10 buffers. + VkDescriptorSet descriptorSet = m_descriptorSet[m_descriptorIndex]; + m_descriptorIndex = (m_descriptorIndex + 1) % s_descriptorBuffers; + + 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); + + SetPerfMarkerEnd(cmd_buf); + } +} \ No newline at end of file diff --git a/sample/src/VK/ExposureMultiplierCS.h b/sample/src/VK/ExposureMultiplierCS.h new file mode 100644 index 0000000..f518d1d --- /dev/null +++ b/sample/src/VK/ExposureMultiplierCS.h @@ -0,0 +1,52 @@ +// AMD AMDUtils code +// +// Copyright(c) 2018 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 "PostProc/PostProcCS.h" +#include "Base/ResourceViewHeaps.h" + +namespace CAULDRON_VK +{ + class ExposureMultiplierCS + { + public: + void OnCreate(Device* pDevice, ResourceViewHeaps *pResourceViewHeaps, DynamicBufferRing *pDynamicBufferRing); + void OnDestroy(); + + void Draw(VkCommandBuffer cmd_buf, VkImageView HDRSRV, float exposure, int width, int height); + + private: + Device* m_pDevice; + ResourceViewHeaps *m_pResourceViewHeaps; + + PostProcCS m_ExposureMultiplier; + DynamicBufferRing *m_pDynamicBufferRing = NULL; + + uint32_t m_descriptorIndex; + static const uint32_t s_descriptorBuffers = 10; + + VkDescriptorSet m_descriptorSet[s_descriptorBuffers]; + VkDescriptorSetLayout m_descriptorSetLayout; + + struct ExposureMultiplierConsts + { + float m_exposure; + }; + }; +} diff --git a/sample/src/VK/FlipBookAnimation.cpp b/sample/src/VK/FlipBookAnimation.cpp new file mode 100644 index 0000000..5ebdaeb --- /dev/null +++ b/sample/src/VK/FlipBookAnimation.cpp @@ -0,0 +1,341 @@ +// AMD AMDUtils 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 "base\ShaderCompilerHelper.h" +#include "FlipBookAnimation.h" + +namespace CAULDRON_VK +{ + void FlipBookAnimation::OnCreate( + Device* pDevice, + VkRenderPass renderPass, + UploadHeap* pUploadHeap, + ResourceViewHeaps *pResourceViewHeaps, + DynamicBufferRing *pDynamicBufferRing, + StaticBufferPool *pStaticBufferPool, + VkSampleCountFlagBits sampleDescCount, + UINT numRows, UINT numColms, std::string flipBookAnimationTexture, XMMATRIX worldMatrix) + { + m_pDevice = pDevice; + m_pResourceViewHeaps = pResourceViewHeaps; + m_pDynamicBufferRing = pDynamicBufferRing; + m_pStaticBufferPool = pStaticBufferPool; + m_sampleDescCount = sampleDescCount; + m_numRows = numRows; + m_numColms = numColms; + m_worldMatrix = worldMatrix; + m_NumIndices = 6; + + short indices[] = + { + 0, 1, 2, + 2, 3, 0 + }; + m_indexType = VK_INDEX_TYPE_UINT16; + m_pStaticBufferPool->AllocBuffer(m_NumIndices, sizeof(short), indices, &m_IBV); + + 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 + }; + m_pStaticBufferPool->AllocBuffer(24, 6 * sizeof(float), vertices, &m_VBV); + + VkResult res; + + ///////////////////////////////////////////// + // vertex input state + + VkVertexInputBindingDescription vi_binding = {}; + vi_binding.binding = 0; + vi_binding.stride = sizeof(float) * 6; + vi_binding.inputRate = VK_VERTEX_INPUT_RATE_VERTEX; + + VkVertexInputAttributeDescription vi_attrs[] = + { + { 0, 0, VK_FORMAT_R32G32B32A32_SFLOAT, 0 }, + { 1, 0, VK_FORMAT_R32G32_SFLOAT, sizeof(float) * 4 }, + }; + + VkPipelineVertexInputStateCreateInfo vi = {}; + vi.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO; + vi.pNext = NULL; + vi.flags = 0; + vi.vertexBindingDescriptionCount = 1; + vi.pVertexBindingDescriptions = &vi_binding; + vi.vertexAttributeDescriptionCount = _countof(vi_attrs); + vi.pVertexAttributeDescriptions = vi_attrs; + + m_FlipBookTexture.InitFromFile(pDevice, pUploadHeap, flipBookAnimationTexture.c_str(), true); + pUploadHeap->FlushAndFinish(); + m_FlipBookTexture.CreateSRV(&m_FlipBookTextureSRV); + + VkSamplerCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.magFilter = VK_FILTER_NEAREST; + info.minFilter = VK_FILTER_NEAREST; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_NEAREST; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_BORDER; + info.minLod = -1000; + info.maxLod = 1000; + info.maxAnisotropy = 1.0f; + res = vkCreateSampler(pDevice->GetDevice(), &info, NULL, &m_sampler); + assert(res == VK_SUCCESS); + + char vertexShaderFiles[1024] = "FlipBookAnimationVS.glsl"; + char pixelShaderFiles[1024] = "FlipBookAnimationPS.glsl"; + + // Compile shaders + // + DefineList attributeDefines; + + VkPipelineShaderStageCreateInfo m_vertexShader; + res = VKCompileFromFile(m_pDevice->GetDevice(), VK_SHADER_STAGE_VERTEX_BIT, vertexShaderFiles, "main", "", &attributeDefines, &m_vertexShader); + assert(res == VK_SUCCESS); + + VkPipelineShaderStageCreateInfo m_fragmentShader; + res = VKCompileFromFile(m_pDevice->GetDevice(), VK_SHADER_STAGE_FRAGMENT_BIT, pixelShaderFiles, "main", "", &attributeDefines, &m_fragmentShader); + assert(res == VK_SUCCESS); + + std::vector shaderStages = { m_vertexShader, m_fragmentShader }; + + ///////////////////////////////////////////// + // Create descriptor set layout + + ///////////////////////////////////////////// + // Create descriptor set + + std::vector layoutBindings(2); + layoutBindings[0].binding = 0; + layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + layoutBindings[0].descriptorCount = 1; + layoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT; + layoutBindings[0].pImmutableSamplers = NULL; + + layoutBindings[1].binding = 1; + layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layoutBindings[1].descriptorCount = 1; + layoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layoutBindings[1].pImmutableSamplers = NULL; + + m_pResourceViewHeaps->CreateDescriptorSetLayoutAndAllocDescriptorSet(&layoutBindings, &m_descriptorSetLayout, &m_descriptorSet); + m_pDynamicBufferRing->SetDescriptorSet(0, sizeof(FlipBookAnimationCBuffer), m_descriptorSet); + + ///////////////////////////////////////////// + // Create the pipeline layout using the descriptoset + + VkPipelineLayoutCreateInfo pPipelineLayoutCreateInfo = {}; + pPipelineLayoutCreateInfo.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO; + pPipelineLayoutCreateInfo.pNext = NULL; + pPipelineLayoutCreateInfo.pushConstantRangeCount = 0; + pPipelineLayoutCreateInfo.pPushConstantRanges = NULL; + pPipelineLayoutCreateInfo.setLayoutCount = (uint32_t)1; + pPipelineLayoutCreateInfo.pSetLayouts = &m_descriptorSetLayout; + + res = vkCreatePipelineLayout(pDevice->GetDevice(), &pPipelineLayoutCreateInfo, NULL, &m_pipelineLayout); + assert(res == VK_SUCCESS); + + ///////////////////////////////////////////// + // Create pipeline + + // input assembly state + + VkPipelineInputAssemblyStateCreateInfo ia; + ia.sType = VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO; + ia.pNext = NULL; + ia.flags = 0; + ia.primitiveRestartEnable = VK_FALSE; + ia.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST; + + // rasterizer state + + VkPipelineRasterizationStateCreateInfo rs; + rs.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO; + rs.pNext = NULL; + rs.flags = 0; + rs.polygonMode = VK_POLYGON_MODE_FILL; + rs.cullMode = VK_CULL_MODE_NONE; + rs.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE; + rs.depthClampEnable = VK_FALSE; + rs.rasterizerDiscardEnable = VK_FALSE; + rs.depthBiasEnable = VK_FALSE; + rs.depthBiasConstantFactor = 0; + rs.depthBiasClamp = 0; + rs.depthBiasSlopeFactor = 0; + rs.lineWidth = 1.0f; + + VkPipelineColorBlendAttachmentState att_state[1]; + att_state[0].colorWriteMask = 0xf; + att_state[0].blendEnable = VK_TRUE; + att_state[0].alphaBlendOp = VK_BLEND_OP_ADD; + att_state[0].colorBlendOp = VK_BLEND_OP_ADD; + att_state[0].srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA; + att_state[0].dstColorBlendFactor = VK_BLEND_FACTOR_ONE; + att_state[0].srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + att_state[0].dstAlphaBlendFactor = VK_BLEND_FACTOR_ONE; + + // Color blend state + + VkPipelineColorBlendStateCreateInfo cb; + cb.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO; + cb.flags = 0; + cb.pNext = NULL; + cb.attachmentCount = 1; + cb.pAttachments = att_state; + cb.logicOpEnable = VK_FALSE; + cb.logicOp = VK_LOGIC_OP_NO_OP; + cb.blendConstants[0] = 1.0f; + cb.blendConstants[1] = 1.0f; + cb.blendConstants[2] = 1.0f; + cb.blendConstants[3] = 1.0f; + + std::vector dynamicStateEnables = { + VK_DYNAMIC_STATE_VIEWPORT, + VK_DYNAMIC_STATE_SCISSOR, + VK_DYNAMIC_STATE_BLEND_CONSTANTS + }; + VkPipelineDynamicStateCreateInfo dynamicState = {}; + dynamicState.sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO; + dynamicState.pNext = NULL; + dynamicState.pDynamicStates = dynamicStateEnables.data(); + dynamicState.dynamicStateCount = (uint32_t)dynamicStateEnables.size(); + + // view port state + + VkPipelineViewportStateCreateInfo vp = {}; + vp.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO; + vp.pNext = NULL; + vp.flags = 0; + vp.viewportCount = 1; + vp.scissorCount = 1; + vp.pScissors = NULL; + vp.pViewports = NULL; + + // depth stencil state + + VkPipelineDepthStencilStateCreateInfo ds; + ds.sType = VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO; + ds.pNext = NULL; + ds.flags = 0; + ds.depthTestEnable = VK_TRUE; + ds.depthWriteEnable = VK_TRUE; + ds.depthCompareOp = VK_COMPARE_OP_LESS; + ds.depthBoundsTestEnable = VK_FALSE; + ds.stencilTestEnable = VK_FALSE; + ds.back.failOp = VK_STENCIL_OP_KEEP; + ds.back.passOp = VK_STENCIL_OP_KEEP; + ds.back.compareOp = VK_COMPARE_OP_LESS; + ds.back.compareMask = 0; + ds.back.reference = 0; + ds.back.depthFailOp = VK_STENCIL_OP_KEEP; + ds.back.writeMask = 0; + ds.minDepthBounds = 0; + ds.maxDepthBounds = 0; + ds.stencilTestEnable = VK_FALSE; + ds.front = ds.back; + + // multi sample state + + VkPipelineMultisampleStateCreateInfo ms; + ms.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO; + ms.pNext = NULL; + ms.flags = 0; + ms.pSampleMask = NULL; + ms.rasterizationSamples = sampleDescCount; + ms.sampleShadingEnable = VK_FALSE; + ms.alphaToCoverageEnable = VK_FALSE; + ms.alphaToOneEnable = VK_FALSE; + ms.minSampleShading = 0.0; + + // create pipeline + + VkGraphicsPipelineCreateInfo pipeline = {}; + pipeline.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO; + pipeline.pNext = NULL; + pipeline.layout = m_pipelineLayout; + pipeline.basePipelineHandle = VK_NULL_HANDLE; + pipeline.basePipelineIndex = 0; + pipeline.flags = VK_PIPELINE_CREATE_DISABLE_OPTIMIZATION_BIT; + pipeline.pVertexInputState = &vi; + pipeline.pInputAssemblyState = &ia; + pipeline.pRasterizationState = &rs; + pipeline.pColorBlendState = &cb; + pipeline.pTessellationState = NULL; + pipeline.pMultisampleState = &ms; + pipeline.pDynamicState = &dynamicState; + pipeline.pViewportState = &vp; + pipeline.pDepthStencilState = &ds; + pipeline.pStages = shaderStages.data(); + pipeline.stageCount = (uint32_t)shaderStages.size(); + pipeline.renderPass = renderPass; + pipeline.subpass = 0; + + res = vkCreateGraphicsPipelines(pDevice->GetDevice(), pDevice->GetPipelineCache(), 1, &pipeline, NULL, &m_pipeline); + assert(res == VK_SUCCESS); + + SetDescriptorSet(m_pDevice->GetDevice(), 1, m_FlipBookTextureSRV, &m_sampler, m_descriptorSet); + } + + void FlipBookAnimation::OnDestroy() + { + vkDestroyImageView(m_pDevice->GetDevice(), m_FlipBookTextureSRV, NULL); + m_FlipBookTexture.OnDestroy(); + m_pResourceViewHeaps->FreeDescriptor(m_descriptorSet); + vkDestroyPipeline(m_pDevice->GetDevice(), m_pipeline, nullptr); + vkDestroyPipelineLayout(m_pDevice->GetDevice(), m_pipelineLayout, nullptr); + vkDestroyDescriptorSetLayout(m_pDevice->GetDevice(), m_descriptorSetLayout, NULL); + vkDestroySampler(m_pDevice->GetDevice(), m_sampler, nullptr); + } + + void FlipBookAnimation::Draw(VkCommandBuffer cmd_buf, float time, XMVECTOR camPos, XMMATRIX viewProjMat) + { + VkDescriptorBufferInfo cbFlipBookAnimation; + FlipBookAnimationCBuffer *pFlipBookAnimation; + m_pDynamicBufferRing->AllocConstantBuffer(sizeof(FlipBookAnimationCBuffer), (void **)&pFlipBookAnimation, &cbFlipBookAnimation); + pFlipBookAnimation->row = m_numRows; + pFlipBookAnimation->cols = m_numColms; + pFlipBookAnimation->time = time; + + XMFLOAT4 dist; + XMStoreFloat4(&dist, camPos - m_worldMatrix.r[3]); + float angle = atan2(dist.x, dist.z); + + pFlipBookAnimation->angle = -angle; + pFlipBookAnimation->camPos = camPos; + pFlipBookAnimation->worldMat = m_worldMatrix; + pFlipBookAnimation->viewProjMat = viewProjMat; + + VkDescriptorSet descritorSets[1] = { m_descriptorSet }; + + uint32_t uniformOffsets[1] = { (uint32_t)cbFlipBookAnimation.offset }; + vkCmdBindDescriptorSets(cmd_buf, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipelineLayout, 0, 1, descritorSets, 1, uniformOffsets); + + vkCmdBindIndexBuffer(cmd_buf, m_IBV.buffer, m_IBV.offset, m_indexType); + vkCmdBindVertexBuffers(cmd_buf, 0, 1, &m_VBV.buffer, &m_VBV.offset); + 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 new file mode 100644 index 0000000..f7b2d90 --- /dev/null +++ b/sample/src/VK/FlipBookAnimation.h @@ -0,0 +1,84 @@ +// AMD AMDUtils 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 "base\UploadHeap.h" +#include "base\ResourceViewHeaps.h" +#include "base\StaticBufferPool.h" +#include "base\DynamicBufferRing.h" +#include "base\Texture.h" + +namespace CAULDRON_VK +{ + class FlipBookAnimation + { + public: + void OnCreate( + Device* pDevice, + VkRenderPass renderPass, + UploadHeap* pUploadHeap, + ResourceViewHeaps *pResourceViewHeaps, + DynamicBufferRing *pDynamicBufferRing, + StaticBufferPool *pStaticBufferPool, + VkSampleCountFlagBits sampleDescCount, + UINT numRows, UINT numColms, std::string flipBookAnimationTexture, XMMATRIX worldMatrix); + void OnDestroy(); + void Draw(VkCommandBuffer cmd_buf, float time, XMVECTOR camPos, XMMATRIX viewProjMat); + + private: + Device * m_pDevice; + VkRenderPass m_renderPass; + + VkIndexType m_indexType; + UINT m_NumIndices; + VkDescriptorBufferInfo m_IBV; + VkDescriptorBufferInfo m_VBV; + + VkPipeline m_pipeline; + VkPipelineLayout m_pipelineLayout; + + VkDescriptorSet m_descriptorSet; + VkDescriptorSetLayout m_descriptorSetLayout; + + VkSampler m_sampler; + VkSampleCountFlagBits m_sampleDescCount; + Texture m_FlipBookTexture; + VkImageView m_FlipBookTextureSRV; + + StaticBufferPool *m_pStaticBufferPool; + DynamicBufferRing *m_pDynamicBufferRing; + ResourceViewHeaps *m_pResourceViewHeaps; + + UINT m_numRows; + UINT m_numColms; + + XMMATRIX m_worldMatrix; + + struct FlipBookAnimationCBuffer { + UINT row; + UINT cols; + float time; + float angle; + XMVECTOR camPos; + XMMATRIX worldMat; + XMMATRIX viewProjMat; + }; + }; +} \ No newline at end of file diff --git a/sample/src/VK/LPMPS.cpp b/sample/src/VK/LPMPS.cpp new file mode 100644 index 0000000..a89fa15 --- /dev/null +++ b/sample/src/VK/LPMPS.cpp @@ -0,0 +1,343 @@ +// AMD AMDUtils code +// +// Copyright(c) 2018 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 "Base/DynamicBufferRing.h" +#include "Base/ShaderCompiler.h" +#include "Base/ExtDebugMarkers.h" +#include "Base/UploadHeap.h" +#include "Base/FreeSyncHDR.h" +#include "Base/Helper.h" +#include "LPMPS.h" + +// LPM +#include +#define A_CPU 1 +#include "../../../ffx-lpm/ffx_a.h" +A_STATIC AF1 fs2S; +A_STATIC AF1 hdr10S; +A_STATIC AU1 ctl[24 * 4]; + +A_STATIC void LpmSetupOut(AU1 i, inAU4 v) +{ + for (int j = 0; j < 4; ++j) { ctl[i * 4 + j] = v[j]; } +} +#include "../../../ffx-lpm/ffx_lpm.h" + +namespace CAULDRON_VK +{ + void LPMPS::OnCreate(Device* pDevice, VkRenderPass renderPass, ResourceViewHeaps *pResourceViewHeaps, StaticBufferPool *pStaticBufferPool, DynamicBufferRing *pDynamicBufferRing) + { + m_pDevice = pDevice; + m_pDynamicBufferRing = pDynamicBufferRing; + m_pResourceViewHeaps = pResourceViewHeaps; + + { + VkSamplerCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT; + info.minLod = -1000; + info.maxLod = 1000; + info.maxAnisotropy = 1.0f; + VkResult res = vkCreateSampler(m_pDevice->GetDevice(), &info, NULL, &m_sampler); + assert(res == VK_SUCCESS); + } + + std::vector layoutBindings(2); + layoutBindings[0].binding = 0; + layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + layoutBindings[0].descriptorCount = 1; + layoutBindings[0].stageFlags = VK_SHADER_STAGE_VERTEX_BIT | VK_SHADER_STAGE_FRAGMENT_BIT; + layoutBindings[0].pImmutableSamplers = NULL; + + layoutBindings[1].binding = 1; + layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layoutBindings[1].descriptorCount = 1; + layoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layoutBindings[1].pImmutableSamplers = NULL; + + m_pResourceViewHeaps->CreateDescriptorSetLayout(&layoutBindings, &m_descriptorSetLayout); + + m_lpm.OnCreate(m_pDevice, renderPass, "LPMPS.glsl", "main", "", pStaticBufferPool, pDynamicBufferRing, m_descriptorSetLayout, NULL, VK_SAMPLE_COUNT_1_BIT); + + m_descriptorIndex = 0; + for (int i = 0; i < s_descriptorBuffers; i++) + m_pResourceViewHeaps->AllocDescriptor(m_descriptorSetLayout, &m_descriptorSet[i]); + } + + void LPMPS::OnDestroy() + { + m_lpm.OnDestroy(); + + for (int i = 0; i < s_descriptorBuffers; i++) + m_pResourceViewHeaps->FreeDescriptor(m_descriptorSet[i]); + + vkDestroySampler(m_pDevice->GetDevice(), m_sampler, nullptr); + + vkDestroyDescriptorSetLayout(m_pDevice->GetDevice(), m_descriptorSetLayout, NULL); + } + + void LPMPS::SetLPMConfig(bool con, bool soft, bool con2, bool clip, bool scaleOnly) + { + m_con = con; + m_soft = soft; + m_con2 = con2; + m_clip = clip; + m_scaleOnly = scaleOnly; + } + + void LPMPS::SetLPMColors( + float xyRedW[2], float xyGreenW[2], float xyBlueW[2], float xyWhiteW[2], + float xyRedO[2], float xyGreenO[2], float xyBlueO[2], float xyWhiteO[2], + float xyRedC[2], float xyGreenC[2], float xyBlueC[2], float xyWhiteC[2], + float scaleC + ) + { + m_xyRedW[0] = xyRedW[0]; m_xyRedW[1] = xyRedW[1]; + m_xyGreenW[0] = xyGreenW[0]; m_xyGreenW[1] = xyGreenW[1]; + m_xyBlueW[0] = xyBlueW[0]; m_xyBlueW[1] = xyBlueW[1]; + m_xyWhiteW[0] = xyWhiteW[0]; m_xyWhiteW[1] = xyWhiteW[1]; + + m_xyRedO[0] = xyRedO[0]; m_xyRedO[1] = xyRedO[1]; + m_xyGreenO[0] = xyGreenO[0]; m_xyGreenO[1] = xyGreenO[1]; + m_xyBlueO[0] = xyBlueO[0]; m_xyBlueO[1] = xyBlueO[1]; + m_xyWhiteO[0] = xyWhiteO[0]; m_xyWhiteO[1] = xyWhiteO[1]; + + m_xyRedC[0] = xyRedC[0]; m_xyRedC[1] = xyRedC[1]; + m_xyGreenC[0] = xyGreenC[0]; m_xyGreenC[1] = xyGreenC[1]; + m_xyBlueC[0] = xyBlueC[0]; m_xyBlueC[1] = xyBlueC[1]; + m_xyWhiteC[0] = xyWhiteC[0]; m_xyWhiteC[1] = xyWhiteC[1]; + + m_scaleC = scaleC; + } + void LPMPS::UpdatePipelines(VkRenderPass renderPass, DisplayModes displayMode, ColorSpace colorSpace) + { + m_lpm.UpdatePipeline(renderPass, NULL, VK_SAMPLE_COUNT_1_BIT); + + m_displayMode = displayMode; + + SetupGamutMapperMatrices( + ColorSpace_REC709, + colorSpace, + &m_inputToOutputMatrix + ); + + // LPM Only setup + varAF2(fs2R); + varAF2(fs2G); + varAF2(fs2B); + varAF2(fs2W); + varAF2(displayMinMaxLuminance); + if (m_displayMode != DISPLAYMODE_SDR) + { + const VkHdrMetadataEXT *pHDRMetatData = fsHdrGetDisplayInfo(); + + // Only used in fs2 modes + fs2R[0] = pHDRMetatData->displayPrimaryRed.x; + fs2R[1] = pHDRMetatData->displayPrimaryRed.y; + fs2G[0] = pHDRMetatData->displayPrimaryGreen.x; + fs2G[1] = pHDRMetatData->displayPrimaryGreen.y; + fs2B[0] = pHDRMetatData->displayPrimaryBlue.x; + fs2B[1] = pHDRMetatData->displayPrimaryBlue.y; + fs2W[0] = pHDRMetatData->whitePoint.x; + fs2W[1] = pHDRMetatData->whitePoint.y; + // Only used in fs2 modes + + 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; + + switch (colorSpace) + { + case ColorSpace_REC709: + { + switch (m_displayMode) + { + case DISPLAYMODE_SDR: + SetLPMConfig(LPM_CONFIG_709_709); + SetLPMColors(LPM_COLORS_709_709); + break; + + case DISPLAYMODE_FSHDR_Gamma22: + SetLPMConfig(LPM_CONFIG_FS2RAW_709); + SetLPMColors(LPM_COLORS_FS2RAW_709); + break; + + case DISPLAYMODE_FSHDR_SCRGB: + fs2S = LpmFs2ScrgbScalar(displayMinMaxLuminance[0], displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_FS2SCRGB_709); + SetLPMColors(LPM_COLORS_FS2SCRGB_709); + break; + + case DISPLAYMODE_HDR10_2084: + hdr10S = LpmHdr10RawScalar(displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_HDR10RAW_709); + SetLPMColors(LPM_COLORS_HDR10RAW_709); + break; + + case DISPLAYMODE_HDR10_SCRGB: + hdr10S = LpmHdr10ScrgbScalar(displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_HDR10SCRGB_709); + SetLPMColors(LPM_COLORS_HDR10SCRGB_709); + break; + + default: + break; + } + break; + } + + case ColorSpace_P3: + { + switch (displayMode) + { + case DISPLAYMODE_SDR: + SetLPMConfig(LPM_CONFIG_709_P3); + SetLPMColors(LPM_COLORS_709_P3); + break; + + case DISPLAYMODE_FSHDR_Gamma22: + SetLPMConfig(LPM_CONFIG_FS2RAW_P3); + SetLPMColors(LPM_COLORS_FS2RAW_P3); + break; + + case DISPLAYMODE_FSHDR_SCRGB: + fs2S = LpmFs2ScrgbScalar(displayMinMaxLuminance[0], displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_FS2SCRGB_P3); + SetLPMColors(LPM_COLORS_FS2SCRGB_P3); + break; + + case DISPLAYMODE_HDR10_2084: + hdr10S = LpmHdr10RawScalar(displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_HDR10RAW_P3); + SetLPMColors(LPM_COLORS_HDR10RAW_P3); + break; + + case DISPLAYMODE_HDR10_SCRGB: + hdr10S = LpmHdr10ScrgbScalar(displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_HDR10SCRGB_P3); + SetLPMColors(LPM_COLORS_HDR10SCRGB_P3); + break; + + default: + break; + } + break; + } + + case ColorSpace_REC2020: + { + switch (displayMode) + { + case DISPLAYMODE_SDR: + SetLPMConfig(LPM_CONFIG_709_2020); + SetLPMColors(LPM_COLORS_709_2020); + break; + + case DISPLAYMODE_FSHDR_Gamma22: + SetLPMConfig(LPM_CONFIG_FS2RAW_2020); + SetLPMColors(LPM_COLORS_FS2RAW_2020); + break; + + case DISPLAYMODE_FSHDR_SCRGB: + fs2S = LpmFs2ScrgbScalar(displayMinMaxLuminance[0], displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_FS2SCRGB_2020); + SetLPMColors(LPM_COLORS_FS2SCRGB_2020); + break; + + case DISPLAYMODE_HDR10_2084: + hdr10S = LpmHdr10RawScalar(displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_HDR10RAW_2020); + SetLPMColors(LPM_COLORS_HDR10RAW_2020); + break; + + case DISPLAYMODE_HDR10_SCRGB: + hdr10S = LpmHdr10ScrgbScalar(displayMinMaxLuminance[1]); + SetLPMConfig(LPM_CONFIG_HDR10SCRGB_2020); + SetLPMColors(LPM_COLORS_HDR10SCRGB_2020); + break; + + default: + break; + } + break; + } + + default: + break; + } + + LpmSetup(m_shoulder, m_con, m_soft, m_con2, m_clip, m_scaleOnly, + m_xyRedW, m_xyGreenW, m_xyBlueW, m_xyWhiteW, + m_xyRedO, m_xyGreenO, m_xyBlueO, m_xyWhiteO, + m_xyRedC, m_xyGreenC, m_xyBlueC, m_xyWhiteC, + m_scaleC, + m_softGap, m_hdrMax, m_exposure, m_contrast, m_shoulderContrast, + m_saturation, m_crosstalk); + } + + void LPMPS::Draw(VkCommandBuffer cmd_buf, VkImageView HDRSRV) + { + SetPerfMarkerBegin(cmd_buf, "LPM Tonemapper"); + + VkDescriptorBufferInfo cbLPMHandle; + LPMConsts *pLPM; + m_pDynamicBufferRing->AllocConstantBuffer(sizeof(LPMConsts), (void **)&pLPM, &cbLPMHandle); + pLPM->shoulder = m_shoulder; + pLPM->con = m_con; + pLPM->soft = m_soft; + pLPM->con2 = m_con2; + pLPM->clip = m_clip; + pLPM->scaleOnly = m_scaleOnly; + pLPM->displayMode = m_displayMode; + pLPM->pad = 0; + pLPM->inputToOutputMatrix = m_inputToOutputMatrix; + for (int i = 0; i < 4 * 24; ++i) + { + pLPM->ctl[i] = ctl[i]; + } + + // We'll be modifying the descriptor set(DS), to prevent writing on a DS that is in use we + // need to do some basic buffering. Just to keep it safe and simple we'll have 10 buffers. + VkDescriptorSet descriptorSet = m_descriptorSet[m_descriptorIndex]; + m_descriptorIndex = (m_descriptorIndex + 1) % s_descriptorBuffers; + + // modify Descriptor set + SetDescriptorSet(m_pDevice->GetDevice(), 1, HDRSRV, &m_sampler, descriptorSet); + m_pDynamicBufferRing->SetDescriptorSet(0, sizeof(LPMConsts), descriptorSet); + + // Draw! + m_lpm.Draw(cmd_buf, cbLPMHandle, descriptorSet); + + SetPerfMarkerEnd(cmd_buf); + } +} \ No newline at end of file diff --git a/sample/src/VK/LPMPS.h b/sample/src/VK/LPMPS.h new file mode 100644 index 0000000..5cabfd4 --- /dev/null +++ b/sample/src/VK/LPMPS.h @@ -0,0 +1,95 @@ +// AMD AMDUtils code +// +// Copyright(c) 2018 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 "PostProc/PostProcPS.h" +#include "Base/ResourceViewHeaps.h" +#include "Misc/ColorConversion.h" + +namespace CAULDRON_VK +{ + class LPMPS + { + public: + void OnCreate(Device* pDevice, VkRenderPass renderPass, ResourceViewHeaps *pResourceViewHeaps, StaticBufferPool *pStaticBufferPool, DynamicBufferRing *pDynamicBufferRing); + void OnDestroy(); + + void UpdatePipelines(VkRenderPass renderPass, DisplayModes displayMode, ColorSpace colorSpace); + + void Draw(VkCommandBuffer cmd_buf, VkImageView HDRSRV); + + private: + // LPM Only + void SetLPMConfig(bool con, bool soft, bool con2, bool clip, bool scaleOnly); + void SetLPMColors( + float xyRedW[2], float xyGreenW[2], float xyBlueW[2], float xyWhiteW[2], + float xyRedO[2], float xyGreenO[2], float xyBlueO[2], float xyWhiteO[2], + float xyRedC[2], float xyGreenC[2], float xyBlueC[2], float xyWhiteC[2], + float scaleC + ); + + bool m_shoulder; // Use optional extra shoulderContrast tuning (set to false if shoulderContrast is 1.0). + bool m_con; // Use first RGB conversion matrix, if 'soft' then 'con' must be true also. + bool m_soft; // Use soft gamut mapping. + bool m_con2; // Use last RGB conversion matrix. + bool m_clip; // Use clipping in last conversion matrix. + bool m_scaleOnly; // Scale only for last conversion matrix (used for 709 HDR to scRGB). + float m_xyRedW[2]; float m_xyGreenW[2]; float m_xyBlueW[2]; float m_xyWhiteW[2]; // Chroma coordinates for working color space. + float m_xyRedO[2]; float m_xyGreenO[2]; float m_xyBlueO[2]; float m_xyWhiteO[2]; // For the output color space. + float m_xyRedC[2]; float m_xyGreenC[2]; float m_xyBlueC[2]; float m_xyWhiteC[2]; float m_scaleC; // For the output container color space (if con2). + float m_softGap; // Range of 0 to a little over zero, controls how much feather region in out-of-gamut mapping, 0=clip. + float m_hdrMax; // Maximum input value. + float m_exposure; // Number of stops between 'hdrMax' and 18% mid-level on input. + float m_contrast; // Input range {0.0 (no extra contrast) to 1.0 (maximum contrast)}. + float m_shoulderContrast; // Shoulder shaping, 1.0 = no change (fast path). + float m_saturation[3]; // A per channel adjustment, use <0 decrease, 0=no change, >0 increase. + float m_crosstalk[3]; // One channel must be 1.0, the rest can be <= 1.0 but not zero. + // LPM Only + + Device* m_pDevice; + ResourceViewHeaps *m_pResourceViewHeaps; + + PostProcPS m_lpm; + DynamicBufferRing *m_pDynamicBufferRing = NULL; + + VkSampler m_sampler; + + uint32_t m_descriptorIndex; + static const uint32_t s_descriptorBuffers = 10; + + VkDescriptorSet m_descriptorSet[s_descriptorBuffers]; + VkDescriptorSetLayout m_descriptorSetLayout; + + DisplayModes m_displayMode; + XMMATRIX m_inputToOutputMatrix; + + struct LPMConsts { + UINT shoulder; + UINT con; + UINT soft; + UINT con2; + UINT clip; + UINT scaleOnly; + UINT displayMode; + UINT pad; + XMMATRIX inputToOutputMatrix; + uint32_t ctl[24 * 4]; + }; + }; +} diff --git a/sample/src/VK/LPMSample.cpp b/sample/src/VK/LPMSample.cpp new file mode 100644 index 0000000..b696fc0 --- /dev/null +++ b/sample/src/VK/LPMSample.cpp @@ -0,0 +1,440 @@ +// 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 "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; +} + +//-------------------------------------------------------------------------------------- +// +// OnParseCommandLine +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnParseCommandLine(LPSTR lpCmdLine, uint32_t* pWidth, uint32_t* pHeight, bool* pbFullScreen) +{ + // set some default values + *pWidth = 1920; + *pHeight = 1080; + *pbFullScreen = false; +} + +//-------------------------------------------------------------------------------------- +// +// OnCreate +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnCreate(HWND hWnd) +{ + // Create Device + // + m_device.OnCreate("myapp", "myEngine", m_isCpuValidationLayerEnabled, m_isGpuValidationLayerEnabled, hWnd); + m_device.CreatePipelineCache(); + + //init the shader compiler + 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); + + // 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); +} + +//-------------------------------------------------------------------------------------- +// +// OnDestroy +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnDestroy() +{ + ImGUI_Shutdown(); + + 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(); + + delete m_Node; + + m_swapChain.OnDestroyWindowSizeDependentResources(); + m_swapChain.OnDestroy(); + + //shut down the shader compiler + DestroyShaderCache(&m_device); + + if (m_pGltfLoader) + { + delete m_pGltfLoader; + m_pGltfLoader = NULL; + } + + m_device.DestroyPipelineCache(); + m_device.OnDestroy(); +} + +//-------------------------------------------------------------------------------------- +// +// OnEvent +// +//-------------------------------------------------------------------------------------- +bool LPMSample::OnEvent(MSG msg) +{ + if (ImGUI_WndProcHandler(msg.hwnd, msg.message, msg.wParam, msg.lParam)) + return true; + + return true; +} + +//-------------------------------------------------------------------------------------- +// +// SetFullScreen +// +//-------------------------------------------------------------------------------------- +void LPMSample::SetFullScreen(bool fullscreen) +{ + m_device.GPUFlush(); + + // 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_swapChain.SetFullScreen(fullscreen); +} + +//-------------------------------------------------------------------------------------- +// +// OnResize +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnResize(uint32_t width, uint32_t height) +{ + // Flush GPU + // + m_device.GPUFlush(); + + // If resizing but no minimizing + // + if (m_Width > 0 && m_Height > 0) + { + if (m_Node != NULL) + { + m_Node->OnDestroyWindowSizeDependentResources(); + } + m_swapChain.OnDestroyWindowSizeDependentResources(); + } + + m_swapChain.EnumerateDisplayModes(&m_displayModesAvailable, &m_displayModesNamesAvailable); + + m_Width = width; + m_Height = height; + + // 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); + if (m_Node != NULL) + { + m_Node->OnCreateWindowSizeDependentResources(&m_swapChain, m_Width, m_Height, &m_state); + } + } + + m_state.camera.SetFov(XM_PI / 4, m_Width, m_Height, 0.1f, 1000.0f); + +} + +//-------------------------------------------------------------------------------------- +// +// OnActivate +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnActivate(bool windowActive) +{ + if (m_previousDisplayMode == DisplayModes::DISPLAYMODE_SDR && m_currentDisplayMode == DisplayModes::DISPLAYMODE_SDR) + return; + + 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); +} + +//-------------------------------------------------------------------------------------- +// +// OnLocalDimmingChanged +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnLocalDimmingChanged() +{ + // Flush GPU + // + m_device.GPUFlush(); + + fsHdrSetLocalDimmingMode(m_swapChain.GetSwapChain(), m_enableLocalDimming); + + m_Node->OnUpdateLocalDimmingChangedResources(&m_swapChain, &m_state); +} + +//-------------------------------------------------------------------------------------- +// +// OnRender +// +//-------------------------------------------------------------------------------------- +void LPMSample::OnRender() +{ + // Get timings + // + double timeNow = MillisecondsNow(); + m_deltaTime = timeNow - m_lastFrameTime; + m_lastFrameTime = timeNow; + + // Build UI and set the scene state. Note that the rendering of the UI happens later. + // + ImGUI_UpdateIO(); + ImGui::NewFrame(); + + static int cameraControlSelected = 1; + static int loadingStage = 0; + if (loadingStage >= 0) + { + // 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); + } + else + { + ImGuiStyle& style = ImGui::GetStyle(); + style.FrameBorderSize = 1.0f; + + bool opened = true; + ImGui::Begin("Stats", &opened); + + 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); + } + } + + 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)); + } + + ImGui::End(); + } + + // If the mouse was not used by the GUI then it's for the camera + // + ImGuiIO& io = ImGui::GetIO(); + if (io.WantCaptureMouse == false) + { + float yaw = m_state.camera.GetYaw(); + float pitch = m_state.camera.GetPitch(); + float distance = m_state.camera.GetDistance(); + + if ((io.KeyCtrl == false) && (io.MouseDown[0] == true)) + { + yaw -= io.MouseDelta.x / 100.f; + pitch += io.MouseDelta.y / 100.f; + } + + // Choose camera movement depending on setting + // + + 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); + + bool panning = (io.KeyCtrl == true) && (io.MouseDown[0] == true); + + m_state.camera.UpdateCameraPolar(yaw, pitch, panning ? -io.MouseDelta.x / 100.0f : 0.0f, panning ? io.MouseDelta.y / 100.0f : 0.0f, distance); + } + } + + // Set animation time + // + if (m_bPlay) + { + m_time += (float)m_deltaTime / 1000.0f; + } + + // transform scene + // + if (m_pGltfLoader) + { + m_pGltfLoader->SetAnimationTime(0, m_time); + m_pGltfLoader->TransformScene(0, XMMatrixIdentity()); + } + + m_state.time = m_time; + + // Do Render frame using AFR + // + m_Node->OnRender(&m_state, &m_swapChain); + + m_swapChain.Present(); +} + + +//-------------------------------------------------------------------------------------- +// +// WinMain +// +//-------------------------------------------------------------------------------------- +int WINAPI WinMain(HINSTANCE hInstance, + HINSTANCE hPrevInstance, + LPSTR lpCmdLine, + int nCmdShow) +{ + LPCSTR Name = "LPMSample VK v1.0"; + + // 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 new file mode 100644 index 0000000..54613a8 --- /dev/null +++ b/sample/src/VK/LPMSample.h @@ -0,0 +1,80 @@ +// 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 "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 +// + +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); + +private: + + Device m_device; + SwapChain m_swapChain; + + DisplayModes m_previousDisplayMode; + DisplayModes m_currentDisplayMode; + DisplayModes m_previousDisplayModeNamesIndex; + DisplayModes m_currentDisplayModeNamesIndex; + std::vector m_displayModesAvailable; + std::vector m_displayModesNamesAvailable; + bool m_enableLocalDimming; + + GLTFCommon *m_pGltfLoader; + + SampleRenderer *m_Node; + SampleRenderer::State m_state; + + float m_time; + double m_deltaTime; // The elapsed time in milliseconds since the previous frame. + double m_lastFrameTime; + + bool m_isCpuValidationLayerEnabled = false; + bool m_isGpuValidationLayerEnabled = false; + + bool m_bPlay; +}; \ No newline at end of file diff --git a/sample/src/VK/SampleRenderer.cpp b/sample/src/VK/SampleRenderer.cpp new file mode 100644 index 0000000..4d59d2b --- /dev/null +++ b/sample/src/VK/SampleRenderer.cpp @@ -0,0 +1,1148 @@ +// 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 new file mode 100644 index 0000000..8b43d63 --- /dev/null +++ b/sample/src/VK/SampleRenderer.h @@ -0,0 +1,138 @@ +// 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 new file mode 100644 index 0000000..49d6e30 --- /dev/null +++ b/sample/src/VK/TestImages.cpp @@ -0,0 +1,98 @@ +// AMD AMDUtils 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 "TestImages.h" + +namespace CAULDRON_VK +{ + void TestImages::OnCreate(Device* pDevice, VkRenderPass renderPass, UploadHeap* pUploadHeap, ResourceViewHeaps *pResourceViewHeaps, StaticBufferPool *pStaticBufferPool, DynamicBufferRing *pDynamicBufferRing) + { + m_pDevice = pDevice; + m_pResourceViewHeaps = pResourceViewHeaps; + m_pDynamicBufferRing = pDynamicBufferRing; + + { + VkSamplerCreateInfo info = {}; + info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO; + info.magFilter = VK_FILTER_LINEAR; + info.minFilter = VK_FILTER_LINEAR; + info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR; + info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; + info.minLod = -1000; + info.maxLod = 1000; + info.maxAnisotropy = 1.0f; + VkResult res = vkCreateSampler(m_pDevice->GetDevice(), &info, NULL, &m_sampler); + assert(res == VK_SUCCESS); + } + + std::vector layoutBindings(2); + layoutBindings[0].binding = 0; + layoutBindings[0].descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER_DYNAMIC; + layoutBindings[0].descriptorCount = 1; + layoutBindings[0].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layoutBindings[0].pImmutableSamplers = NULL; + + layoutBindings[1].binding = 1; + layoutBindings[1].descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER; + layoutBindings[1].descriptorCount = 1; + layoutBindings[1].stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT; + layoutBindings[1].pImmutableSamplers = NULL; + + for (int i = 0; i < NUM_TEXTURES; ++i) + { + m_testImageTexture[i].InitFromFile(pDevice, pUploadHeap, m_TextureNameList[i].c_str(), 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_testImagePS.OnCreate(m_pDevice, renderPass, "TestImagesPS.glsl", "main", "", pStaticBufferPool, pDynamicBufferRing, m_descriptorSetLayout[0], NULL, VK_SAMPLE_COUNT_1_BIT); + } + + void TestImages::OnDestroy() + { + for (int i = 0; i < NUM_TEXTURES; ++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); + } + + m_testImagePS.OnDestroy(); + + vkDestroySampler(m_pDevice->GetDevice(), m_sampler, nullptr); + } + + void TestImages::Draw(VkCommandBuffer cmd_buf, int testPattern) + { + VkDescriptorBufferInfo cbTestImagesHandle; + TestImagesConsts *pTestImagesConsts; + m_pDynamicBufferRing->AllocConstantBuffer(sizeof(TestImagesConsts), (void **)&pTestImagesConsts, &cbTestImagesHandle); + + pTestImagesConsts->testPattern = testPattern - 1; + + m_testImagePS.Draw(cmd_buf, cbTestImagesHandle, m_descriptorSet[pTestImagesConsts->testPattern % NUM_TEXTURES]); + } +} \ No newline at end of file diff --git a/sample/src/VK/TestImages.h b/sample/src/VK/TestImages.h new file mode 100644 index 0000000..d877e4b --- /dev/null +++ b/sample/src/VK/TestImages.h @@ -0,0 +1,57 @@ +// AMD AMDUtils 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 "PostProc\PostProcPS.h" + +#define NUM_TEXTURES 3 + +namespace CAULDRON_VK +{ + class TestImages + { + public: + void OnCreate(Device* pDevice, VkRenderPass renderPass, UploadHeap* pUploadHeap, ResourceViewHeaps *pResourceViewHeaps, StaticBufferPool *pStaticBufferPool, DynamicBufferRing *pDynamicBufferRing); + void OnDestroy(); + void Draw(VkCommandBuffer cmd_buf, int testPattern); + + private: + 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]; + 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/shaders/ExposureMultiplierCS.glsl b/sample/src/VK/shaders/ExposureMultiplierCS.glsl new file mode 100644 index 0000000..a82def2 --- /dev/null +++ b/sample/src/VK/shaders/ExposureMultiplierCS.glsl @@ -0,0 +1,43 @@ +#version 420 + +// AMD Cauldron code +// +// Copyright(c) 2018 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. + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable +#extension GL_ARB_compute_shader : enable + +layout (std140, binding = 0) uniform perBatch +{ + float u_exposure; +} myPerScene; + +layout (local_size_x = 8, local_size_y = 8) in; +layout (binding = 1, rgba16f) uniform image2D HDR; + +void main() +{ + ivec2 coords = ivec2(gl_GlobalInvocationID.xy); + + vec4 texColor = imageLoad(HDR, coords).rgba; + + texColor.rgb *= myPerScene.u_exposure; + + imageStore(HDR, coords, texColor); +} diff --git a/sample/src/VK/shaders/FlipBookAnimationPS.glsl b/sample/src/VK/shaders/FlipBookAnimationPS.glsl new file mode 100644 index 0000000..70315f7 --- /dev/null +++ b/sample/src/VK/shaders/FlipBookAnimationPS.glsl @@ -0,0 +1,35 @@ +// AMD AMDUtils 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. + +#version 400 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec2 inTexCoord; + +layout (location = 0) out vec4 outColor; + +layout(set=0, binding=1) uniform sampler2D sSampler; + +void main() +{ + // Push the camp fire outside of rec709 gamut + 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 new file mode 100644 index 0000000..6e36b5b --- /dev/null +++ b/sample/src/VK/shaders/FlipBookAnimationVS.glsl @@ -0,0 +1,75 @@ +// AMD AMDUtils 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. + +#version 400 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +layout (location = 0) in vec4 pos; +layout (location = 1) in vec2 inTexCoord; + +layout (location = 0) out vec2 outTexCoord; + +layout (std140, binding = 0) uniform perFrame +{ + uint row; + uint cols; + float time; + float angle; + vec4 camPos; + mat4 worldMat; + mat4 viewProjMat; +} myPerFrame; + +void main() +{ + float cos_angle = cos(myPerFrame.angle); + float sin_angle = sin(myPerFrame.angle); + + mat4 rotMatrix = mat4(cos_angle, 0, sin_angle, 0, + 0, 1, 0, 0, + -sin_angle, 0, cos_angle, 0, + 0, 0, 0, 1); + + vec4 newPos = rotMatrix * pos; + + gl_Position = myPerFrame.viewProjMat * myPerFrame.worldMat * newPos; + + vec2 size = vec2(1.0f / myPerFrame.cols, 1.0f / myPerFrame.row); + uint totalFrames = myPerFrame.row * myPerFrame.cols; + + // use timer to increment index + uint index = uint(myPerFrame.time * 60) % totalFrames; + + // wrap x and y indexes + uint indexX = uint(index % myPerFrame.cols); + uint indexY = uint(index / myPerFrame.cols); + + // get offsets to our sprite index + vec2 offset = vec2(size.x*indexX, size.y*indexY); + + // get single sprite UV + vec2 newUV = inTexCoord * size; + + // Slight offset in Y because of visual seam + newUV.y += 0.001; + + outTexCoord = newUV + offset; +} \ No newline at end of file diff --git a/sample/src/VK/shaders/LPMPS.glsl b/sample/src/VK/shaders/LPMPS.glsl new file mode 100644 index 0000000..b7b1255 --- /dev/null +++ b/sample/src/VK/shaders/LPMPS.glsl @@ -0,0 +1,94 @@ +// AMD Cauldron code +// +// Copyright(c) 2018 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. + +#version 460 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable +#extension GL_ARB_gpu_shader_fp64 : enable + +layout (location = 0) in vec2 inTexCoord; + +layout (location = 0) out vec4 outColor; + +layout (std140, binding = 0) uniform perBatch +{ + bool u_shoulder; + bool u_con; + bool u_soft; + bool u_con2; + bool u_clip; + bool u_scaleOnly; + uint u_displayMode; + uint pad; + mat4 u_inputToOutputMatrix; + ivec4 u_ctl[24 * 4]; +} myPerScene; + +layout(set=0, binding=1) uniform sampler2D sSampler; + +//-------------------------------------------------------------------------------------- +// Timothy Lottes LPM +//-------------------------------------------------------------------------------------- + +#define A_GPU 1 +#define A_GLSL 1 + +#include "ffx_a.h" + +AU4 LpmFilterCtl(AU1 i) +{ + return myPerScene.u_ctl[i]; +} + +#define LPM_NO_SETUP 1 +#include "ffx_lpm.h" + +#include "transferfunction.h" + +void main() +{ + vec4 color = texture(sSampler, inTexCoord.st); + + color = myPerScene.u_inputToOutputMatrix * color; + + // This code is there to make sure no negative values make it down to LPM. Make sure to never hit this case and convert content to correct colourspace + color.r = max(0, color.r); + color.g = max(0, color.g); + color.b = max(0, color.b); + // + + LpmFilter(color.r, color.g, color.b, myPerScene.u_shoulder, myPerScene.u_con, myPerScene.u_soft, myPerScene.u_con2, myPerScene.u_clip, myPerScene.u_scaleOnly); + + switch (myPerScene.u_displayMode) + { + case 1: + // FS2_DisplayNative + // Apply gamma + color.xyz = ApplyGamma(color.rgb); + break; + + case 3: + // HDR10_ST2084 + // Apply ST2084 curve + color.xyz = ApplyPQ(color.xyz); + break; + } + + outColor = color; +} diff --git a/sample/src/VK/shaders/TestImagesPS.glsl b/sample/src/VK/shaders/TestImagesPS.glsl new file mode 100644 index 0000000..c5bd861 --- /dev/null +++ b/sample/src/VK/shaders/TestImagesPS.glsl @@ -0,0 +1,101 @@ +// AMD AMDUtils 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. + +#version 450 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable +#extension GL_GOOGLE_include_directive : enable + +layout (location = 0) in vec2 inTexCoord; + +layout (location = 0) out vec4 outColor; + +layout (set=0, binding = 0, std140) uniform perFrame +{ + int u_testPattern; +} myPerFrame; + +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) + { + case 0: + case 1: + case 2: + { + texColor = texture(sSampler, inTexCoord.st); + break; + } + case 3: + { + // Get rgb for hue value from x coord of uv + float H = inTexCoord.x * 360.0f; + float S = 1.0f; + float V = 1.0f; + + float C = V * S; + float X = C * (1.0f - abs(mod((H / 60.0f) , 2.0f) - 1.0f)); + float m = V - C; + + vec3 absColor; + if (H >= 0.0f && H < 60.0f) + { + absColor = vec3(C, X, 0.0f); + } + else if (H >= 60.0f && H < 120.0f) + { + absColor = vec3(X, C, 0.0f); + } + else if (H >= 120.0f && H < 180.0f) + { + absColor = vec3(0.0f, C, X); + } + else if (H >= 180.0f && H < 240.0f) + { + absColor = vec3(0.0f, X, C); + } + else if (H >= 240.0f && H < 300.0f) + { + absColor = vec3(X, 0.0f, C); + } + else if (H >= 300.0f && H < 360.0f) + { + absColor = vec3(C, 0.0f, X); + } + + texColor.xyz = vec3(absColor.r + m, absColor.g + m, absColor.b + m); + + if (inTexCoord.y < 0.5) + { + texColor.xyz *= (inTexCoord.y * 2.0); + } + else + { + float exp = mix(0, 6, (inTexCoord.y - 0.5) * 2); + texColor.xyz *= pow(2, exp); + } + break; + } + } + + outColor = texColor; +} diff --git a/sample/src/VK/shaders/transferFunction.h b/sample/src/VK/shaders/transferFunction.h new file mode 100644 index 0000000..dbcdd80 --- /dev/null +++ b/sample/src/VK/shaders/transferFunction.h @@ -0,0 +1,44 @@ +// AMD Cauldron code +// +// Copyright(c) 2018 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. + +vec3 ApplyGamma(vec3 color) +{ + float invGamma = 1.0 / 2.2; + color.xyz = pow(color.rgb, vec3(invGamma, invGamma, invGamma)); + return color; +} + +vec3 ApplyPQ(vec3 color) +{ + // Apply ST2084 curve + float m1 = 2610.0 / 4096.0 / 4; + float m2 = 2523.0 / 4096.0 * 128; + float c1 = 3424.0 / 4096.0; + float c2 = 2413.0 / 4096.0 * 32; + float c3 = 2392.0 / 4096.0 * 32; + vec3 cp = pow(abs(color.xyz), vec3(m1)); + color.xyz = pow((c1 + c2 * cp) / (1 + c3 * cp), vec3(m2)); + return color; +} + +vec3 ApplyscRGBScale(vec3 color, float minLuminancePerNits, float maxLuminancePerNits) +{ + color.xyz = (color.xyz * (maxLuminancePerNits - minLuminancePerNits)) + vec3(minLuminancePerNits, minLuminancePerNits, minLuminancePerNits); + return color; +} \ No newline at end of file diff --git a/sample/src/VK/stdafx.cpp b/sample/src/VK/stdafx.cpp new file mode 100644 index 0000000..96fcbef --- /dev/null +++ b/sample/src/VK/stdafx.cpp @@ -0,0 +1,29 @@ +// AMD AMDUtils 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. + +// stdafx.cpp : source file that includes just the standard includes +// ObjRendererD3D12.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file + + diff --git a/sample/src/VK/stdafx.h b/sample/src/VK/stdafx.h new file mode 100644 index 0000000..a7c28a3 --- /dev/null +++ b/sample/src/VK/stdafx.h @@ -0,0 +1,93 @@ +// AMD AMDUtils 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. + +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// +#pragma once + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#include + +// C RunTime Header Files +#include +#include +#include +#include +#include + +#define VK_USE_PLATFORM_WIN32_KHR 1 +#include "vulkan/vulkan.h" + + +// we are using DirectXMath +#include +using namespace DirectX; + +// 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 "Misc\Error.h" +#include "misc\Misc.h" +#include "misc\Camera.h" + +#include "GLTF\GltfPbrPass.h" +#include "GLTF\GltfBBoxPass.h" +#include "GLTF\GltfDepthPass.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 "TestImages.h" +#include "FlipBookAnimation.h" +#include "LPMPS.h" +#include "ExposureMultiplierCS.h" + +#include "Widgets\Axis.h" +#include "Widgets\CheckerBoardFloor.h" + +#include "..\common\Misc\Camera.h" +#include "..\common\Misc\FrameworkWindows.h" +#include "..\common\Misc\ColorConversion.h" + +using namespace CAULDRON_VK; \ No newline at end of file