diff --git a/.gitignore b/.gitignore index 28d4cd9..4f329d5 100644 --- a/.gitignore +++ b/.gitignore @@ -116,3 +116,7 @@ samples/hello-gltf/assets_tmp/ samples/rotatedCopy/assets_tmp/ samples/shaderResolveTonemap/assets_tmp/ samples/SubPass/assets_tmp/ +samples/BloomImageProcessing/assets_tmp/ +project/tools/ktx.dll +project/tools/ktxinfo.exe +project/tools/toktx.exe diff --git a/framework/code/graphicsApi/graphicsApiBase.hpp b/framework/code/graphicsApi/graphicsApiBase.hpp index ce01f3f..0a8832d 100644 --- a/framework/code/graphicsApi/graphicsApiBase.hpp +++ b/framework/code/graphicsApi/graphicsApiBase.hpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -58,7 +58,7 @@ auto* apiCast(T* rBase) { template auto apiCast(std::unique_ptr&& rBase) { using tDerived = typename T::template tApiDerived; - return std::unique_ptr(static_cast(rBase.get())); + return std::unique_ptr(static_cast(rBase.release())); } diff --git a/framework/code/main/frameworkApplicationBase.cpp b/framework/code/main/frameworkApplicationBase.cpp index 4af71f1..e248e8f 100644 --- a/framework/code/main/frameworkApplicationBase.cpp +++ b/framework/code/main/frameworkApplicationBase.cpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -13,7 +13,13 @@ #include "system/os_common.h" // Bring in the timestamp (and assign to a variable) +// Temporary fix for Android not building the timestamp, upstream cmake update will fix this in a future update +#if defined(_WIN32) #include "../../project/buildtimestamp.h" +#else +#define BUILD_TIMESTAMP "UNDEFINED" +#endif + const char* const FrameworkApplicationBase::sm_BuildTimestamp = BUILD_TIMESTAMP; diff --git a/framework/code/mesh/instanceGenerator.cpp b/framework/code/mesh/instanceGenerator.cpp index a2693e6..f91a8a6 100644 --- a/framework/code/mesh/instanceGenerator.cpp +++ b/framework/code/mesh/instanceGenerator.cpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -11,6 +11,11 @@ #include #define EIGEN_INITIALIZE_MATRICES_BY_ZERO #define EIGEN_MPL2_ONLY + +#if defined(_WIN32) +#define EIGEN_HAS_STD_RESULT_OF 0 +#endif + #include #include #include diff --git a/framework/code/texture/texture.hpp b/framework/code/texture/texture.hpp index 2e55347..ce0dc4e 100644 --- a/framework/code/texture/texture.hpp +++ b/framework/code/texture/texture.hpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -202,7 +202,7 @@ std::unique_ptr CreateTextureObject(GraphicsApiBase& gfxApi, const Crea /// Create texture from a memory buffer. template -TextureT CreateTextureFromBuffer( T_GFXAPI& gfxApi, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName = nullptr ) +TextureT CreateTextureFromBuffer( T_GFXAPI& gfxApi, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName = nullptr, uint32_t extraFlags = 0 ) { assert( 0 && "Expecting CreateTextureFromBuffer (per graphics api) to be used" ); return {}; @@ -210,10 +210,10 @@ TextureT CreateTextureFromBuffer( T_GFXAPI& gfxApi, const void* pData, /// Create texture (unique_ptr) (generally for render target usage). Uses CreateTexObjectInfo structure to define texture creation parameters. template -std::unique_ptr CreateTextureFromBuffer( GraphicsApiBase& gfxApi, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName = nullptr ) +std::unique_ptr CreateTextureFromBuffer( GraphicsApiBase& gfxApi, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName = nullptr, uint32_t extraFlags = 0 ) { auto pTexture = std::make_unique>(); - *pTexture = std::move( CreateTextureFromBuffer( static_cast( gfxApi ), pData, DataSize, Width, Height, Depth, Format, SamplerMode, Filter, pName ) ); + *pTexture = std::move( CreateTextureFromBuffer( static_cast( gfxApi ), pData, DataSize, Width, Height, Depth, Format, SamplerMode, Filter, pName, extraFlags) ); return pTexture; } diff --git a/framework/code/texture/textureManager.hpp b/framework/code/texture/textureManager.hpp index 86fb834..f06579c 100644 --- a/framework/code/texture/textureManager.hpp +++ b/framework/code/texture/textureManager.hpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -81,7 +81,7 @@ class TextureManager virtual std::unique_ptr CreateTextureObjectView( GraphicsApiBase& gfxApi, const Texture& original, TextureFormat viewFormat ) = 0; /// Create texture from a block of texture data in memory (with correct format, span etc). - virtual std::unique_ptr CreateTextureFromBuffer( GraphicsApiBase&, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName) = 0; + virtual std::unique_ptr CreateTextureFromBuffer( GraphicsApiBase&, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName, uint32_t extraFlags = 0) = 0; /// Get a 'default' sampler for the given address mode (all other sampler settings assumed to be 'normal' ie linearly sampled etc) virtual const Sampler* const GetSampler( SamplerAddressMode ) const = 0; diff --git a/framework/code/texture/vulkan/texture.cpp b/framework/code/texture/vulkan/texture.cpp index 2632752..11a4522 100644 --- a/framework/code/texture/vulkan/texture.cpp +++ b/framework/code/texture/vulkan/texture.cpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -730,7 +730,7 @@ TextureT CreateTextureObjectView( Vulkan& vulkan, const TextureT //----------------------------------------------------------------------------- template<> -TextureT CreateTextureFromBuffer( Vulkan& vulkan, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName ) +TextureT CreateTextureFromBuffer( Vulkan& vulkan, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName, uint32_t extraFlags ) //----------------------------------------------------------------------------- { if (pName == nullptr) @@ -742,6 +742,7 @@ TextureT CreateTextureFromBuffer( Vulkan& vulkan, const void* pD uint32_t MipLevels = 1; VkFormat vkFormat = TextureFormatToVk( Format ); VkImageUsageFlags FinalUsage = ( VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT ); + FinalUsage |= (VkImageUsageFlags)extraFlags; VkImageLayout FinalLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; // Image creation info. Will change below based on need diff --git a/framework/code/texture/vulkan/texture.hpp b/framework/code/texture/vulkan/texture.hpp index 9065df6..b969bd4 100644 --- a/framework/code/texture/vulkan/texture.hpp +++ b/framework/code/texture/vulkan/texture.hpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -110,7 +110,7 @@ TextureT CreateTextureObject( Vulkan&, const CreateTexObjectInfo /// Template specialization for Vulkan CreateTextureFromBuffer template<> -TextureT CreateTextureFromBuffer( Vulkan&, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName ); +TextureT CreateTextureFromBuffer( Vulkan&, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName, uint32_t extraFlags ); /// Create a texture that views (aliases) another texture but using a different texture format (must be 'related' formats, which formats are related is dependant on graphics api) TextureT CreateTextureObjectView( Vulkan&, const TextureT& original, TextureFormat viewFormat ); diff --git a/framework/code/texture/vulkan/textureManager.cpp b/framework/code/texture/vulkan/textureManager.cpp index 6fefc99..c585fb5 100644 --- a/framework/code/texture/vulkan/textureManager.cpp +++ b/framework/code/texture/vulkan/textureManager.cpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -200,11 +200,11 @@ std::unique_ptr TextureManagerT::CreateTextureObject(GraphicsAp } //----------------------------------------------------------------------------- -std::unique_ptr TextureManagerT::CreateTextureFromBuffer( GraphicsApiBase& gfxApi, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName ) +std::unique_ptr TextureManagerT::CreateTextureFromBuffer( GraphicsApiBase& gfxApi, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName, uint32_t extraFlags) //----------------------------------------------------------------------------- { auto pTexture = std::make_unique>(); - *pTexture = ::CreateTextureFromBuffer( static_cast( gfxApi ), pData, DataSize, Width, Height, Depth, Format, SamplerMode, Filter, pName ); + *pTexture = ::CreateTextureFromBuffer( static_cast( gfxApi ), pData, DataSize, Width, Height, Depth, Format, SamplerMode, Filter, pName, extraFlags); return pTexture; } diff --git a/framework/code/texture/vulkan/textureManager.hpp b/framework/code/texture/vulkan/textureManager.hpp index ea50ba6..20720a4 100644 --- a/framework/code/texture/vulkan/textureManager.hpp +++ b/framework/code/texture/vulkan/textureManager.hpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -49,7 +49,7 @@ class TextureManagerT final : public TextureManager /// Create texture from a block of texture data in memory (with correct format, span etc). /// Implements the base class virtual function. - std::unique_ptr CreateTextureFromBuffer( GraphicsApiBase&, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName ) override; + std::unique_ptr CreateTextureFromBuffer( GraphicsApiBase&, const void* pData, size_t DataSize, uint32_t Width, uint32_t Height, uint32_t Depth, TextureFormat Format, SamplerAddressMode SamplerMode, SamplerFilter Filter, const char* pName, uint32_t extraFlags = 0 ) override; /// Create a texture that views (aliases) another texture but using a different texture format (must be 'related' formats, which formats are related is dependant on graphics api) /// Implements the base class virtual function. diff --git a/project/android/settings.gradle b/project/android/settings.gradle index 4b6db06..dcaff86 100644 --- a/project/android/settings.gradle +++ b/project/android/settings.gradle @@ -1,4 +1,4 @@ -include ':empty', ':hello-gltf', ':hdrSwapchain', ':SubPass', ':shaderResolveTonemap', ':rotatedCopy', ':BloomImageProcessing', ':rayQueryShadows',':rayReflections' +include ':empty', ':hello-gltf', ':hdrSwapchain', ':SubPass', ':shaderResolveTonemap', ':rotatedCopy', ':BloomImageProcessing', ':rayQueryShadows',':rayReflections',':sgsr' project(':empty').projectDir = new File('../../samples/empty') project(':hello-gltf').projectDir = new File('../../samples/hello-gltf') @@ -8,4 +8,5 @@ project(':shaderResolveTonemap').projectDir = new File('../../samples/shaderReso project(':rotatedCopy').projectDir = new File('../../samples/rotatedCopy') project(':BloomImageProcessing').projectDir = new File('../../samples/BloomImageProcessing') project(':rayQueryShadows').projectDir = new File('../../samples/rayQueryShadows') -project(':rayReflections').projectDir = new File('../../samples/rayReflections') \ No newline at end of file +project(':rayReflections').projectDir = new File('../../samples/rayReflections') +project(':sgsr').projectDir = new File('../../samples/sgsr') \ No newline at end of file diff --git a/project/windows/CMakeLists.txt b/project/windows/CMakeLists.txt index dad970c..a14c29c 100644 --- a/project/windows/CMakeLists.txt +++ b/project/windows/CMakeLists.txt @@ -66,4 +66,5 @@ if(FRAMEWORK_ENABLE_VULKAN) add_subdirectory(../../samples/BloomImageProcessing/ samples/BloomImageProcessing) add_subdirectory(../../samples/rayQueryShadows/ samples/rayQueryShadows) add_subdirectory(../../samples/rayReflections/ samples/rayReflections) + add_subdirectory(../../samples/sgsr/ samples/sgsr) endif() diff --git a/samples/BloomImageProcessing/01_CompileShaders.bat b/samples/BloomImageProcessing/01_CompileShaders.bat deleted file mode 100644 index 2623ef1..0000000 --- a/samples/BloomImageProcessing/01_CompileShaders.bat +++ /dev/null @@ -1,53 +0,0 @@ -@echo off - -SETLOCAL -SET CurDir=%~dp0 -SET ShaderDir=%CurDir%\shaders -SET Glslang=%ShaderDir%\glslangValidator.exe -SET OutShaderDir=%CurDir%\Media\Shaders - -mkdir %CurDir%\Media -rmdir /s /q %OutShaderDir% -mkdir %OutShaderDir% - -IF NOT EXIST %Glslang% ( - ECHO "Local GLSL validator is missing - attempting global one" - SET Glslang=glslangValidator.exe -) - -MKDIR %OutShaderDir% - -CALL :compile_shader %ShaderDir%\VertexShader.vert vert 0 0 %OutShaderDir%\VertexShader.vert.spv || EXIT /B 1 - -CALL :compile_shader %ShaderDir%\Downsample.frag frag 0 0 %OutShaderDir%\Downsample.frag.spv || EXIT /B 1 -CALL :compile_shader %ShaderDir%\Downsample.frag frag 0 1 %OutShaderDir%\Downsample-Ext.frag.spv || EXIT /B 1 - -CALL :compile_shader %ShaderDir%\BlurBase.frag frag 0 0 %OutShaderDir%\BlurBase-Horizontal.frag.spv || EXIT /B 1 -CALL :compile_shader %ShaderDir%\BlurBase.frag frag 0 1 %OutShaderDir%\BlurBase-Horizontal-Ext.frag.spv || EXIT /B 1 - -CALL :compile_shader %ShaderDir%\BlurBase.frag frag 1 0 %OutShaderDir%\BlurBase-Vertical.frag.spv || EXIT /B 1 -CALL :compile_shader %ShaderDir%\BlurBase.frag frag 1 1 %OutShaderDir%\BlurBase-Vertical-Ext.frag.spv || EXIT /B 1 - -CALL :compile_shader %ShaderDir%\Display.frag frag 0 0 %OutShaderDir%\Display.frag.spv || EXIT /B 1 - -EXIT /B 0 - -:compile_shader -SET ShaderFile=%1 -SET Stage=%2 -SET VertPass=%3 -SET Ext=%4 -SET OutName=%5 - -SET ExtDef= -IF "%Ext%"=="1" ( - SET ExtDef="-DENABLE_QCOM_IMAGE_PROCESSING=1" -) -SET VertDef= -IF "%VertPass%"=="1" ( - SET VertDef="-DVERT_PASS=1" -) - -CALL %Glslang% -V -S %Stage% %ExtDef% %VertDef% -e main -o "%OutName%" "%ShaderFile%" || EXIT /B 1 - -EXIT /B 0 diff --git a/samples/BloomImageProcessing/02_Install_APK.bat b/samples/BloomImageProcessing/01_Install_APK.bat similarity index 79% rename from samples/BloomImageProcessing/02_Install_APK.bat rename to samples/BloomImageProcessing/01_Install_APK.bat index 274cb59..efe3031 100644 --- a/samples/BloomImageProcessing/02_Install_APK.bat +++ b/samples/BloomImageProcessing/01_Install_APK.bat @@ -8,7 +8,7 @@ adb uninstall com.quic.BloomImageProcessing @echo **************************************** @echo Install ..\..\build\android\BloomImageProcessing\outputs\apk\debug\BloomImageProcessing-debug.apk @echo **************************************** -adb install -r ..\..\build\android\BloomImageProcessing\outputs\apk\debug\BloomImageProcessing-debug.apk +adb install -r -g ..\..\build\android\BloomImageProcessing\outputs\apk\debug\BloomImageProcessing-debug.apk @echo. @echo **************************************** diff --git a/samples/BloomImageProcessing/03_InstallConfig.bat b/samples/BloomImageProcessing/02_InstallConfig.bat similarity index 100% rename from samples/BloomImageProcessing/03_InstallConfig.bat rename to samples/BloomImageProcessing/02_InstallConfig.bat diff --git a/samples/BloomImageProcessing/README.md b/samples/BloomImageProcessing/README.md index c325b16..073f3be 100644 --- a/samples/BloomImageProcessing/README.md +++ b/samples/BloomImageProcessing/README.md @@ -17,20 +17,6 @@ The following dependencies must be installed and the appropriate locations shoul * CMake * Android Studio -### Pre-Build - -Compile the underlying shaders to .spv by running the batch file below: - -``` -01_CompileShaders.bat -``` - -And convert the needed textures to the correct format using the batch file below: - -``` -02_PrepareMedia.bat -``` - ### Build Once the dependencies are installed and shaders compiled, building this sample .apk/.exe is as simple as running any of the batch files from the framework root directory, accordingly to your target system: @@ -45,13 +31,13 @@ Once the dependencies are installed and shaders compiled, building this sample . To deploy the media files and the .apk to a connected device, run the batch file below: ``` -03_Install_APK.bat +01_Install_APK.bat ``` Optionally you can change the default configurations for this sample by upating the file **app_config.txt** and running the batch file below: ``` -04_InstallConfig.bat +02_InstallConfig.bat ``` ## Android Studio diff --git a/samples/BloomImageProcessing/code/main/bloom-image-processing.cpp b/samples/BloomImageProcessing/code/main/bloom-image-processing.cpp index a6a34ea..798434d 100644 --- a/samples/BloomImageProcessing/code/main/bloom-image-processing.cpp +++ b/samples/BloomImageProcessing/code/main/bloom-image-processing.cpp @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -28,8 +28,8 @@ VAR(bool, gUseExtension, true, kVariableNonpersistent); VAR(unsigned, gBlurFilterSize, 7, kVariableNonpersistent); #if OS_ANDROID -#define SHADERFILE(f) "./Shaders/" f -#define TEXTUREFILE(f) "./Textures/" f +#define SHADERFILE(f) "./Media/Shaders/" f +#define TEXTUREFILE(f) "./Media/Textures/" f #else #define SHADERFILE(f) "./Media/Shaders/" f #define TEXTUREFILE(f) "./Media/Textures/" f @@ -69,7 +69,7 @@ void BloomImageprocessing::PreInitializeSetVulkanConfiguration(Vulkan::AppConfi { ApplicationHelperBase::PreInitializeSetVulkanConfiguration(config); config.RequiredExtension(VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME); - // config.RequiredExtension("VK_KHR_format_feature_flags2"); + config.RequiredExtension("VK_KHR_format_feature_flags2"); if (m_bUseExtension) { config.RequiredExtension(); @@ -177,7 +177,22 @@ bool BloomImageprocessing::Initialize(uintptr_t windowHandle, uintptr_t hInstanc if (ii == 1) // H { - m_weightTextures[ii] = apiCast(m_TextureManager->CreateTextureFromBuffer(*pVulkan, pHalfTexData, gBlurFilterSize * sizeof(float16), gBlurFilterSize, 1, 1, weightFormat, SamplerAddressMode::ClampEdge, SamplerFilter::Nearest/*, usageFlags, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/, nullptr)); +#if 0 + m_weightTextures[ii] = LoadTextureFromBuffer( + pVulkan, pHalfTexData, gBlurFilterSize * sizeof(float16), + gBlurFilterSize, 1, 1, weightFormat, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_FILTER_NEAREST, + usageFlags, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); +#endif + m_weightTextures[ii] = + apiCast(m_TextureManager->CreateTextureFromBuffer( + *pVulkan, pHalfTexData, gBlurFilterSize * sizeof(float16), + gBlurFilterSize, 1, 1, weightFormat, + SamplerAddressMode::ClampEdge, + SamplerFilter::Nearest, + nullptr, + (uint32_t)usageFlags)); + weightViewInfo.filterCenter.x = gBlurFilterSize / 2; weightViewInfo.filterCenter.y = 0; @@ -186,7 +201,22 @@ bool BloomImageprocessing::Initialize(uintptr_t windowHandle, uintptr_t hInstanc } else // V { - m_weightTextures[ii] = apiCast(m_TextureManager->CreateTextureFromBuffer(*pVulkan, pHalfTexData, gBlurFilterSize * sizeof(float16), 1, gBlurFilterSize, 1, weightFormat, SamplerAddressMode::ClampEdge, SamplerFilter::Nearest/*, usageFlags, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL*/, nullptr)); +#if 0 + m_weightTextures[ii] = LoadTextureFromBuffer( + pVulkan, pHalfTexData, gBlurFilterSize * sizeof(float16), 1, + gBlurFilterSize, 1, weightFormat, + VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE, VK_FILTER_NEAREST, + usageFlags, VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL); +#endif + + m_weightTextures[ii] = + apiCast(m_TextureManager->CreateTextureFromBuffer( + *pVulkan, pHalfTexData, gBlurFilterSize * sizeof(float16), + 1, gBlurFilterSize, 1, weightFormat, + SamplerAddressMode::ClampEdge, + SamplerFilter::Nearest, + nullptr, + (uint32_t)usageFlags)); weightViewInfo.filterCenter.x = 0; weightViewInfo.filterCenter.y = gBlurFilterSize / 2; @@ -203,8 +233,9 @@ bool BloomImageprocessing::Initialize(uintptr_t windowHandle, uintptr_t hInstanc } } } + - if (pVulkan->IsTextureFormatSupported(TextureFormat::ASTC_4x4_UNORM_BLOCK)) + if (/*pVulkan->IsTextureFormatSupported(TextureFormat::ASTC_4x4_UNORM_BLOCK)*/ false) { m_sourceTexture = apiCast(m_TextureManager->GetOrLoadTexture(*m_AssetManager, TEXTUREFILE("painting_astc.ktx"), SamplerAddressMode::ClampEdge)); } @@ -329,27 +360,26 @@ bool BloomImageprocessing::Initialize(uintptr_t windowHandle, uintptr_t hInstanc void BloomImageprocessing::Destroy() //----------------------------------------------------------------------------- { - Vulkan* pVulkan = GetVulkan(); - - vkDeviceWaitIdle(pVulkan->m_VulkanDevice); + vkDeviceWaitIdle(GetVulkan()->m_VulkanDevice); // Textures for (uint32_t ii = 0; ii < NumWeightImages; ++ii) { - m_weightTextures[ii] = nullptr; - vkDestroyImageView(pVulkan->m_VulkanDevice, m_weightTextureViews[ii], NULL); + m_sourceTexture = nullptr; + vkDestroyImageView(GetVulkan()->m_VulkanDevice, m_weightTextureViews[ii], NULL); } + m_sourceTexture = nullptr; // Shaders for (uint32_t ss = 0; ss < ShaderPair_Count; ++ss) { - ReleaseShader(pVulkan, &m_shaders[ss]); + ReleaseShader(GetVulkan(), &m_shaders[ss]); } // Uniform Buffers for (uint32_t ii = 0; ii < Pass_Count; ++ii) { - ReleaseUniformBuffer(pVulkan, &m_uniforms[ii]); + ReleaseUniformBuffer(GetVulkan(), &m_uniforms[ii]); } for (uint32_t pp = 0; pp < Pass_Count; ++pp) @@ -611,7 +641,8 @@ void BloomImageprocessing::FinalizePass(PassInfo* pPass) ds.depthTestEnable = VK_FALSE; ds.depthWriteEnable = VK_FALSE; - pVulkan->CreatePipeline(VK_NULL_HANDLE, + pVulkan->CreatePipeline( + VK_NULL_HANDLE, &visci, pPass->pLayout, pPass->renderpass, @@ -629,6 +660,7 @@ void BloomImageprocessing::FinalizePass(PassInfo* pPass) false, VK_NULL_HANDLE, & pPass->pipeline); + } void BloomImageprocessing::DrawPass(Wrap_VkCommandBuffer* cmd, const PassInfo* pPass, uint32_t idx) @@ -653,17 +685,13 @@ void BloomImageprocessing::DrawPass(Wrap_VkCommandBuffer* cmd, const PassInfo* p Scissor.extent.width = pPass->renderArea.width; Scissor.extent.height = pPass->renderArea.height; - cmd->BeginRenderPass( - Scissor, - 0.0f, - 1.0f, - { &clear_color,1 }, - 1, - pPass->pRt == NULL ? true : false, - pPass->renderpass, - pPass->pRt == NULL ? true : false, - pPass->pRt == NULL ? pVulkan->m_SwapchainBuffers[idx].framebuffer : pPass->fbo, - VK_SUBPASS_CONTENTS_INLINE); + cmd->BeginRenderPass(Scissor, 0.0f, 1.0f, {&clear_color, 1}, 1, + pPass->pRt == NULL ? true : false, pPass->renderpass, + pPass->pRt == NULL ? true : false, + pPass->pRt == NULL + ? pVulkan->m_SwapchainBuffers[idx].framebuffer + : pPass->fbo, + VK_SUBPASS_CONTENTS_INLINE); vkCmdSetViewport(cmd->m_VkCommandBuffer, 0, 1, &Viewport); vkCmdSetScissor(cmd->m_VkCommandBuffer, 0, 1, &Scissor); diff --git a/samples/BloomImageProcessing/shaders/BlurBase-Horizontal-Ext.frag b/samples/BloomImageProcessing/shaders/BlurBase-Horizontal-Ext.frag new file mode 100644 index 0000000..18409cf --- /dev/null +++ b/samples/BloomImageProcessing/shaders/BlurBase-Horizontal-Ext.frag @@ -0,0 +1,33 @@ +//============================================================================================================ +// +// +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 450 + +#extension GL_QCOM_image_processing : require + +precision mediump float; precision mediump int; + +layout(location = 0) noperspective in vec2 in_TEXCOORD0; + +layout(set = 0, binding = 0, std140) uniform WeightInfo +{ + vec4 weights[8]; +} _Globals; + + +layout(set = 0, binding = 1) uniform texture2D SourceTexture; +layout(set = 0, binding = 2) uniform sampler SourceSampler; +layout(set = 0, binding = 3) uniform texture2DArray BloomWeightTexture; +layout(set = 0, binding = 4) uniform sampler BloomWeightSampler; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = textureWeightedQCOM(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0, sampler2DArray(BloomWeightTexture, BloomWeightSampler)); +} diff --git a/samples/BloomImageProcessing/shaders/BlurBase-Horizontal.frag b/samples/BloomImageProcessing/shaders/BlurBase-Horizontal.frag new file mode 100644 index 0000000..f28c163 --- /dev/null +++ b/samples/BloomImageProcessing/shaders/BlurBase-Horizontal.frag @@ -0,0 +1,38 @@ +//============================================================================================================ +// +// +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 450 + +precision mediump float; precision mediump int; + +layout(location = 0) noperspective in vec2 in_TEXCOORD0; + +layout(set = 0, binding = 0, std140) uniform WeightInfo +{ + vec4 weights[8]; +} _Globals; + +layout(set = 0, binding = 1) uniform texture2D SourceTexture; +layout(set = 0, binding = 2) uniform sampler SourceSampler; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + const float StepX = 1.0 / 1920.0; + const float StepY = 0; + + int WeightSize = int(_Globals.weights[0][0]); + FragColor = vec4(0); + for (int ww = 0; ww < WeightSize; ++ww) + { + float coordIndex = float(ww - WeightSize / 2); + ivec2 weightIndex = ivec2((ww + 1) / 4, (ww + 1) % 4); + FragColor += texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0 + vec2(coordIndex * StepX, coordIndex * StepY)) * _Globals.weights[weightIndex.x][weightIndex.y]; + } +} diff --git a/samples/BloomImageProcessing/shaders/BlurBase-Vertical-Ext.frag b/samples/BloomImageProcessing/shaders/BlurBase-Vertical-Ext.frag new file mode 100644 index 0000000..18409cf --- /dev/null +++ b/samples/BloomImageProcessing/shaders/BlurBase-Vertical-Ext.frag @@ -0,0 +1,33 @@ +//============================================================================================================ +// +// +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 450 + +#extension GL_QCOM_image_processing : require + +precision mediump float; precision mediump int; + +layout(location = 0) noperspective in vec2 in_TEXCOORD0; + +layout(set = 0, binding = 0, std140) uniform WeightInfo +{ + vec4 weights[8]; +} _Globals; + + +layout(set = 0, binding = 1) uniform texture2D SourceTexture; +layout(set = 0, binding = 2) uniform sampler SourceSampler; +layout(set = 0, binding = 3) uniform texture2DArray BloomWeightTexture; +layout(set = 0, binding = 4) uniform sampler BloomWeightSampler; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + FragColor = textureWeightedQCOM(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0, sampler2DArray(BloomWeightTexture, BloomWeightSampler)); +} diff --git a/samples/BloomImageProcessing/shaders/BlurBase-Vertical.frag b/samples/BloomImageProcessing/shaders/BlurBase-Vertical.frag new file mode 100644 index 0000000..99afc1d --- /dev/null +++ b/samples/BloomImageProcessing/shaders/BlurBase-Vertical.frag @@ -0,0 +1,39 @@ +//============================================================================================================ +// +// +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 450 + +precision mediump float; precision mediump int; + +layout(location = 0) noperspective in vec2 in_TEXCOORD0; + +layout(set = 0, binding = 0, std140) uniform WeightInfo +{ + vec4 weights[8]; +} _Globals; + + +layout(set = 0, binding = 1) uniform texture2D SourceTexture; +layout(set = 0, binding = 2) uniform sampler SourceSampler; + +layout(location = 0) out vec4 FragColor; + +void main() +{ + const float StepX = 0; + const float StepY = 1.0 / 1080.0; + + int WeightSize = int(_Globals.weights[0][0]); + FragColor = vec4(0); + for (int ww = 0; ww < WeightSize; ++ww) + { + float coordIndex = float(ww - WeightSize / 2); + ivec2 weightIndex = ivec2((ww + 1) / 4, (ww + 1) % 4); + FragColor += texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0 + vec2(coordIndex * StepX, coordIndex * StepY)) * _Globals.weights[weightIndex.x][weightIndex.y]; + } +} diff --git a/samples/BloomImageProcessing/shaders/BlurBase.frag b/samples/BloomImageProcessing/shaders/BlurBase.frag index 8d433f3..879a6e9 100644 --- a/samples/BloomImageProcessing/shaders/BlurBase.frag +++ b/samples/BloomImageProcessing/shaders/BlurBase.frag @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ diff --git a/samples/BloomImageProcessing/shaders/Display.frag b/samples/BloomImageProcessing/shaders/Display.frag index 3c5db4f..2f5aaa8 100644 --- a/samples/BloomImageProcessing/shaders/Display.frag +++ b/samples/BloomImageProcessing/shaders/Display.frag @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ @@ -20,8 +20,13 @@ layout(set = 0, binding = 3) uniform sampler BlurSampler; layout(location = 0) out vec4 FragColor; +vec3 pow3(vec3 v, float p) { return vec3(pow(v.x, p), pow(v.y, p), pow(v.z, p)); } + void main() { - FragColor = texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0) + - texture(sampler2D(BlurTexture, BlurSampler), in_TEXCOORD0); + vec4 src = texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0); + src.rgb = pow3(src.rgb, 1.0/2.2); + vec4 bloom = texture(sampler2D(BlurTexture, BlurSampler), in_TEXCOORD0); + + FragColor = bloom + src; } diff --git a/samples/BloomImageProcessing/shaders/Downsample-Ext.frag b/samples/BloomImageProcessing/shaders/Downsample-Ext.frag new file mode 100644 index 0000000..315f914 --- /dev/null +++ b/samples/BloomImageProcessing/shaders/Downsample-Ext.frag @@ -0,0 +1,38 @@ +//============================================================================================================ +// +// +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 450 + +#extension GL_QCOM_image_processing : require + +precision mediump float; precision mediump int; + +layout(location = 0) noperspective in vec2 in_TEXCOORD0; + +layout(set = 0, binding = 0) uniform texture2D SourceTexture; +layout(set = 0, binding = 1) uniform sampler SourceSampler; + +layout(location = 0) out vec4 FragColor; + +vec3 pow3(vec3 v, float p) { return vec3(pow(v.x, p), pow(v.y, p), pow(v.z, p)); } + +void main() +{ + vec4 downsampleColor = vec4(0); + downsampleColor = textureBoxFilterQCOM(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0, vec2(2.0, 2.0)); + downsampleColor.rgb = pow3(downsampleColor.rgb, 1.0/2.2); + + float brightness = dot(downsampleColor.rgb, vec3(0.2126, 0.7152, 0.0722)); + if (brightness < 0.35) // Discard darker areas + { + downsampleColor = vec4(0, 0, 0, 1.0); + } + + FragColor = downsampleColor; + FragColor.a = 1.0; +} diff --git a/samples/BloomImageProcessing/shaders/Downsample.frag b/samples/BloomImageProcessing/shaders/Downsample.frag index a121d7e..3caa3e7 100644 --- a/samples/BloomImageProcessing/shaders/Downsample.frag +++ b/samples/BloomImageProcessing/shaders/Downsample.frag @@ -1,17 +1,13 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ #version 450 -#if ENABLE_QCOM_IMAGE_PROCESSING -#extension GL_QCOM_image_processing : require -#endif // ENABLE_QCOM_IMAGE_PROCESSING - precision mediump float; precision mediump int; layout(location = 0) noperspective in vec2 in_TEXCOORD0; @@ -21,21 +17,25 @@ layout(set = 0, binding = 1) uniform sampler SourceSampler; layout(location = 0) out vec4 FragColor; +vec3 pow3(vec3 v, float p) { return vec3(pow(v.x, p), pow(v.y, p), pow(v.z, p)); } + void main() { vec4 downsampleColor = vec4(0); -#if ENABLE_QCOM_IMAGE_PROCESSING - downsampleColor = textureBoxFilterQCOM(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0, vec2(2.0, 2.0)); -#else - const float StepX = 1.0 / 1920.0; - const float StepY = 1.0 / 1080.0; + + ivec2 srcSize = textureSize(sampler2D(SourceTexture, SourceSampler), 0); + + const float StepX = 1.0 / float(srcSize.x); + const float StepY = 1.0 / float(srcSize.y); downsampleColor = ( texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0 + vec2(0, 0)) + texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0 + vec2(StepX, 0)) + texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0 + vec2(0, StepY)) + texture(sampler2D(SourceTexture, SourceSampler), in_TEXCOORD0 + vec2(StepX, StepY)) ) / 4.0; -#endif // ENABLE_QCOM_IMAGE_PROCESSING + + downsampleColor.rgb = pow3(downsampleColor.rgb, 1.0/2.2); + float brightness = dot(downsampleColor.rgb, vec3(0.2126, 0.7152, 0.0722)); if (brightness < 0.35) // Discard darker areas { diff --git a/samples/BloomImageProcessing/shaders/VertexShader.vert b/samples/BloomImageProcessing/shaders/VertexShader.vert index b24eebf..7d7e4ea 100644 --- a/samples/BloomImageProcessing/shaders/VertexShader.vert +++ b/samples/BloomImageProcessing/shaders/VertexShader.vert @@ -1,7 +1,7 @@ //============================================================================================================ // // -// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// Copyright (c) 2024, Qualcomm Innovation Center, Inc. All rights reserved. // SPDX-License-Identifier: BSD-3-Clause // //============================================================================================================ diff --git a/samples/sgsr/01_CompileShaders.bat b/samples/sgsr/01_CompileShaders.bat new file mode 100644 index 0000000..fcb833a --- /dev/null +++ b/samples/sgsr/01_CompileShaders.bat @@ -0,0 +1,39 @@ +@echo off + +mkdir .\Media\Shaders + +@echo. +echo **************************************** +echo Compiling Shaders... +echo **************************************** +for %%i in (shaders\*.vert) do ( + call :COMPILE %%i || GOTO COMPILE_FAILED +) +for %%i in (shaders\*.frag) do ( + call :COMPILE %%i || GOTO COMPILE_FAILED +) +for %%i in (shaders\*.comp) do ( + call :COMPILE %%i || GOTO COMPILE_FAILED +) + +@echo. +echo **************************************** +echo Copying .json +echo **************************************** +xcopy /y shaders\*.json .\Media\Shaders\. + +@echo. +echo **************************************** +echo Done +echo **************************************** +IF %0 EQU "%~dpnx0" PAUSE +goto :EOF + +:COMPILE +glslangValidator.exe -V %1 -o .\Media\Shaders\%~nx1.spv +IF NOT ERRORLEVEL 1 echo. %1 -^> .\Media\Shaders\%~nx1.spv +goto :EOF + +:COMPILE_FAILED +echo COMPILE FAILED +IF %0 EQU "%~dpnx0" PAUSE diff --git a/samples/sgsr/02_Install_APK.bat b/samples/sgsr/02_Install_APK.bat new file mode 100644 index 0000000..f102c79 --- /dev/null +++ b/samples/sgsr/02_Install_APK.bat @@ -0,0 +1,18 @@ +@echo off +pushd . +cd /D "%~dp0" + +adb uninstall com.quic.sgsr + +@echo. +@echo **************************************** +@echo Install ..\..\build\android\sgsr\outputs\apk\debug\sgsr-debug.apk +@echo **************************************** +adb install -r ..\..\build\android\sgsr\outputs\apk\debug\sgsr-debug.apk + +@echo. +@echo **************************************** +@echo Done! +@echo **************************************** +popd +IF %0 EQU "%~dpnx0" PAUSE diff --git a/samples/sgsr/03_InstallConfig.bat b/samples/sgsr/03_InstallConfig.bat new file mode 100644 index 0000000..f666222 --- /dev/null +++ b/samples/sgsr/03_InstallConfig.bat @@ -0,0 +1,5 @@ +@echo off + +adb push %~dp0/app_config.txt /sdcard/Android/data/com.quic.sgsr/files/app_config.txt + +pause diff --git a/samples/sgsr/CMakeLists.txt b/samples/sgsr/CMakeLists.txt new file mode 100644 index 0000000..97964f6 --- /dev/null +++ b/samples/sgsr/CMakeLists.txt @@ -0,0 +1,39 @@ +cmake_minimum_required (VERSION 3.21) + +project (sgsr C CXX) +set(CMAKE_CXX_STANDARD 20) + +# +# Source files included in this application. +# + +set(CPP_SRC code/main/application.cpp + code/main/application.hpp +) + +# +# Setup the module path to include the 'project directory' (project/windows or project/android) +# +if(NOT DEFINED PROJECT_ROOT_DIR) + set(PROJECT_ROOT_DIR ${CMAKE_SOURCE_DIR}) # Windows can use CMAKE_SOURCE_DIR, Android needs build.gradle needs "-DPROJECT_ROOT_DIR=${project.rootDir}" in call to cmake set since there is not a 'top' cmakefile (gradle is top level) +endif() +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_ROOT_DIR}/cmake) + +# +# Add in the contents of 'shaders' directory +# +include(AddShadersDir) + +# +# Do all the build steps for a Framework application. +# needs Framework_dir and project_name variables. +# +include(FrameworkApplicationHelper) + +# +# Convert and copy textures to local folders +# +include(TexturePackager) + +# Textures +add_textures_from_path(${CMAKE_CURRENT_SOURCE_DIR}/../../assets/textures) \ No newline at end of file diff --git a/samples/sgsr/README.md b/samples/sgsr/README.md new file mode 100644 index 0000000..b192c7f --- /dev/null +++ b/samples/sgsr/README.md @@ -0,0 +1,65 @@ +# Snapdragon™ Game Super Resolution + +![Screenshot](img/screenshot.png) + +## Overview + +This sample demonstrates how to use the [Snapdragon™ Game Super Resolution](https://github.com/quic/snapdragon-gsr) and offers a comparison with the traditional *Bilinear Interpolation*. + +- Toggle **SGSR Active** to activate Snapdragon™ GSR +- Toggle **SGSR Edge Direction** to use an optional edge direction calculation on the SGSR shader that helps reducing banding + +## Building + +### Dependencies + +The following dependencies must be installed and the appropriate locations should be referenced in the `PATH` environment variable. + +* Android SDK +* Andorid NDK +* Gradle +* CMake +* Android Studio + +### Pre-Build + +Compile the underlying shaders to .spv by running the batch file below: + +``` +01_CompileShaders.bat +``` + +And convert the needed textures to the correct format using the batch file below: + +``` +02_PrepareMedia.bat +``` + +### Build + +Once the dependencies are installed and shaders compiled, building this sample .apk/.exe is as simple as running any of the batch files from the framework root directory, accordingly to your target system: + +``` +01_BuildAndroid.bat +02_BuildWindows.bat +``` + +### Deploy (android-only) + +To deploy the media files and the .apk to a connected device, run the batch file below: + +``` +03_Install_APK.bat +``` + +Optionally you can change the default configurations for this sample by upating the file **app_config.txt** and running the batch file below: + +``` +04_InstallConfig.bat +``` + +## Android Studio + +This sample can also be easily imported to Android Studio and be used within the Android Studio ecosystem including building, deploying, and native code debugging. + +To do this, open Android Studio and go to `File->New->Import Project...` and select the `project\android` folder as the source for the import. This will load up the gradle configuration and once finalized, the sample can be used within Android Studio. diff --git a/samples/sgsr/build.gradle b/samples/sgsr/build.gradle new file mode 100644 index 0000000..00d5915 --- /dev/null +++ b/samples/sgsr/build.gradle @@ -0,0 +1,93 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 30 + lintOptions { + abortOnError false + } + + String rootDir = "${project.rootDir}" + rootDir = rootDir.replace("\\", "/") + + defaultConfig { + applicationId "com.quic.sgsr" + minSdkVersion 26 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + ndkVersion "${project.ndkVersionDefault}" + ndk { + abiFilters 'arm64-v8a' + } + externalNativeBuild { + cmake { + arguments "-DPROJECT_ROOT_DIR=${rootDir}", "-DFRAMEWORK_DIR=${rootDir}/../../framework" + } + } + } + + signingConfigs{ + unsigned{ + storeFile file("${System.env.USERPROFILE}/.android/debug.keystore") + storePassword = "android" + keyAlias = "androiddebugkey" + keyPassword = "android" + v2SigningEnabled = false + } + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + signingConfig signingConfigs.unsigned + } + debug { + debuggable = true + jniDebuggable = true + } + } + + sourceSets { + main { + jni.srcDirs = [] + manifest.srcFile 'project/android/AndroidManifest.xml' + //java.srcDirs = ['src'] + res.srcDirs = ['project/android/res'] + + // Uncomment this to enable validation +// jniLibs { +// srcDir "${android.ndkDirectory}/sources/third_party/vulkan/src/build-android/jniLibs" +// } + } + main.assets { + srcDirs = ['assets'] + // Uncomment this to add Media folder to assets + srcDirs += ['assets_tmp'] + } + } + + dependencies { + } + + externalNativeBuild { + cmake { + version "3.19.0+" + path 'CMakeLists.txt' + } + } + + task copyTmpAssets(type: Copy) { + from "Media" + into "assets_tmp/Media" + } + task removeTmpAssets(type: Delete) { + delete "assets_tmp" + } + + afterEvaluate { + packageRelease.finalizedBy(removeTmpAssets) + } + + preBuild.dependsOn(copyTmpAssets) +} diff --git a/samples/sgsr/code/main/application.cpp b/samples/sgsr/code/main/application.cpp new file mode 100644 index 0000000..29d0892 --- /dev/null +++ b/samples/sgsr/code/main/application.cpp @@ -0,0 +1,871 @@ +//============================================================================================================ +// +// +// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +/// +/// Sample app demonstrating the loading of a .gltf file (hello world) +/// + +#include "application.hpp" +#include "main/applicationEntrypoint.hpp" +#include "camera/cameraController.hpp" +#include "camera/cameraControllerTouch.hpp" +#include "camera/cameraData.hpp" +#include "camera/cameraGltfLoader.hpp" +#include "gui/imguiVulkan.hpp" +#include "material/drawable.hpp" +#include "material/vulkan/shaderModule.hpp" +#include "material/shaderManagerT.hpp" +#include "material/materialManager.hpp" +#include "material/vulkan/specializationConstantsLayout.hpp" +#include "mesh/meshHelper.hpp" +#include "mesh/meshLoader.hpp" +#include "system/math_common.hpp" +#include "texture/textureManager.hpp" +#include "imgui.h" + +#include +#include +#include + +namespace +{ + static constexpr std::array sRenderPassNames = { "RP_SGSR", "RP_HUD", "RP_BLIT" }; + + glm::vec3 gCameraStartPos = glm::vec3(26.48f, 20.0f, -5.21f); + glm::vec3 gCameraStartRot = glm::vec3(0.0f, 110.0f, 0.0f); + + float gFOV = PI_DIV_4; + float gNearPlane = 1.0f; + float gFarPlane = 1800.0f; +} + +/// +/// @brief Implementation of the Application entrypoint (called by the framework) +/// @return Pointer to Application (derived from @FrameworkApplicationBase). +/// Creates the Application class. Ownership is passed to the calling (framework) function. +/// +FrameworkApplicationBase* Application_ConstructApplication() +{ + return new Application(); +} + +Application::Application() : ApplicationHelperBase() +{ + +} + +Application::~Application() +{ +} + +//----------------------------------------------------------------------------- +bool Application::Initialize(uintptr_t windowHandle, uintptr_t hInstance) +//----------------------------------------------------------------------------- +{ + if (!ApplicationHelperBase::Initialize( windowHandle, hInstance )) + { + return false; + } + + // Window width and height are the same as surface width and height on windows, but on + // Android these represent the device screen resolution + // If smaller resolutions are desired, modify these values as needed (or use their default + // values) + gSurfaceWidth = m_WindowWidth; + gSurfaceHeight = m_WindowHeight; + gRenderWidth = m_WindowWidth; + gRenderHeight = m_WindowHeight; + + if (!InitializeCamera()) + { + return false; + } + + if (!LoadShaders()) + { + return false; + } + + if (!InitUniforms()) + { + return false; + } + + if (!CreateRenderTargets()) + { + return false; + } + + if (!InitAllRenderPasses()) + { + return false; + } + + if (!InitGui(windowHandle)) + { + return false; + } + + if (!LoadMeshObjects()) + { + return false; + } + + if (!InitCommandBuffers()) + { + return false; + } + + if (!InitLocalSemaphores()) + { + return false; + } + + if (!BuildCmdBuffers()) + { + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +void Application::Destroy() +//----------------------------------------------------------------------------- +{ + Vulkan* const pVulkan = GetVulkan(); + + // Uniform Buffers + ReleaseUniformBuffer(pVulkan, &m_SGSRFragUniform); + + // Cmd buffers + for (int whichPass = 0; whichPass < NUM_RENDER_PASSES; whichPass++) + { + for (auto& cmdBuffer : m_RenderPassData[whichPass].PassCmdBuffer) + { + cmdBuffer.Release(); + } + + for (auto& cmdBuffer : m_RenderPassData[whichPass].ObjectsCmdBuffer) + { + cmdBuffer.Release(); + } + + m_RenderPassData[whichPass].RenderTarget.Release(); + } + + // Render passes / Semaphores + for (int whichPass = 0; whichPass < NUM_RENDER_PASSES; whichPass++) + { + vkDestroyRenderPass(pVulkan->m_VulkanDevice, m_RenderPassData[whichPass].RenderPass, nullptr); + vkDestroySemaphore(pVulkan->m_VulkanDevice, m_RenderPassData[whichPass].PassCompleteSemaphore, nullptr); + } + + // Drawables + m_SGSRQuadDrawable.reset(); + m_BlitQuadDrawable.reset(); + + // Internal + m_ShaderManager.reset(); + m_MaterialManager.reset(); + m_CameraController.reset(); + m_AssetManager.reset(); + + ApplicationHelperBase::Destroy(); +} + +//----------------------------------------------------------------------------- +int Application::PreInitializeSelectSurfaceFormat(std::span surfaceFormat) +//----------------------------------------------------------------------------- +{ + for (int i = 0; i < surfaceFormat.size(); i++) + { + if (surfaceFormat[i].format == TextureFormat::B8G8R8A8_SRGB || surfaceFormat[i].format == TextureFormat::R8G8B8A8_SRGB) + { + return i; + } + } + + return -1; +} + +//----------------------------------------------------------------------------- +void Application::PreInitializeSetVulkanConfiguration(Vulkan::AppConfiguration& configuration) +//----------------------------------------------------------------------------- +{ +} + +//----------------------------------------------------------------------------- +bool Application::InitializeCamera() +//----------------------------------------------------------------------------- +{ + LOGI("******************************"); + LOGI("Initializing Camera..."); + LOGI("******************************"); + + m_Camera.SetPosition(gCameraStartPos, glm::quat(gCameraStartRot * TO_RADIANS)); + m_Camera.SetAspect(float(gRenderWidth) / float(gRenderHeight)); + m_Camera.SetFov(gFOV); + m_Camera.SetClipPlanes(gNearPlane, gFarPlane); + + // Camera Controller // + +#if defined(OS_ANDROID) + typedef CameraControllerTouch tCameraController; +#else + typedef CameraController tCameraController; +#endif + + auto cameraController = std::make_unique(); + if (!cameraController->Initialize(gRenderWidth, gRenderHeight)) + { + return false; + } + + m_CameraController = std::move(cameraController); + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::LoadShaders() +//----------------------------------------------------------------------------- +{ + m_ShaderManager = std::make_unique>(*GetVulkan()); + m_ShaderManager->RegisterRenderPassNames(sRenderPassNames); + + m_MaterialManager = std::make_unique>(); + + LOGI("******************************"); + LOGI("Loading Shaders..."); + LOGI("******************************"); + + typedef std::pair tIdAndFilename; + for (const tIdAndFilename& i : + { tIdAndFilename { "Blit", "Media\\Shaders\\Blit.json" }, + tIdAndFilename { "SGSR", "Media\\Shaders\\sgsr_shader_mobile.json" } + }) + { + if (!m_ShaderManager->AddShader(*m_AssetManager, i.first, i.second)) + { + LOGE("Error Loading shader %s from %s", i.first.c_str(), i.second.c_str()); + LOGI("Please verify if you have all required assets on the sample media folder"); + LOGI("If you are running on Android, don't forget to run the `02_CopyMediaToDevice.bat` script to copy all media files into the device memory"); + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::CreateRenderTargets() +//----------------------------------------------------------------------------- +{ + Vulkan* const pVulkan = GetVulkan(); + + LOGI("**************************"); + LOGI("Creating Render Targets..."); + LOGI("**************************"); + + const TextureFormat MainColorType[] = { TextureFormat::B8G8R8A8_SRGB }; + const TextureFormat HudColorType[] = { TextureFormat::B8G8R8A8_SRGB }; + + if (!m_RenderPassData[RP_SGSR].RenderTarget.Initialize(pVulkan, gRenderWidth, gRenderHeight, MainColorType, TextureFormat::UNDEFINED, VK_SAMPLE_COUNT_1_BIT, "SGSR RT")) + { + LOGE("Unable to create scene render target"); + return false; + } + + // Notice no depth on the HUD RT + if (!m_RenderPassData[RP_HUD].RenderTarget.Initialize(pVulkan, gSurfaceWidth, gSurfaceHeight, HudColorType, TextureFormat::UNDEFINED, VK_SAMPLE_COUNT_1_BIT, "HUD RT")) + { + LOGE("Unable to create hud render target"); + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::InitUniforms() +//----------------------------------------------------------------------------- +{ + LOGI("******************************"); + LOGI("Initializing Uniforms..."); + LOGI("******************************"); + + Vulkan* const pVulkan = GetVulkan(); + + if (!CreateUniformBuffer(pVulkan, m_SGSRFragUniform)) + { + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::InitAllRenderPasses() +//----------------------------------------------------------------------------- +{ + Vulkan* const pVulkan = GetVulkan(); + + // ColorInputUsage | ClearDepthRenderPass | ColorOutputUsage | DepthOutputUsage | ClearColor + m_RenderPassData[RP_SGSR].PassSetup = { RenderPassInputUsage::Clear, true, RenderPassOutputUsage::StoreReadOnly, RenderPassOutputUsage::Discard, {}}; + m_RenderPassData[RP_HUD].PassSetup = { RenderPassInputUsage::Clear, true, RenderPassOutputUsage::StoreReadOnly, RenderPassOutputUsage::Discard, {}}; + m_RenderPassData[RP_BLIT].PassSetup = { RenderPassInputUsage::DontCare, true, RenderPassOutputUsage::Present, RenderPassOutputUsage::Discard, {}}; + + TextureFormat surfaceFormat = pVulkan->m_SurfaceFormat; + auto swapChainColorFormat = std::span({ &surfaceFormat, 1 }); + auto swapChainDepthFormat = pVulkan->m_SwapchainDepth.format; + + LOGI("******************************"); + LOGI("Initializing Render Passes... "); + LOGI("******************************"); + + for (uint32_t whichPass = 0; whichPass < NUM_RENDER_PASSES; whichPass++) + { + bool isSwapChainRenderPass = whichPass == RP_BLIT; + + std::span colorFormats = isSwapChainRenderPass ? swapChainColorFormat : m_RenderPassData[whichPass].RenderTarget[0].m_pLayerFormats; + TextureFormat depthFormat = isSwapChainRenderPass ? swapChainDepthFormat : m_RenderPassData[whichPass].RenderTarget[0].m_DepthFormat; + + const auto& passSetup = m_RenderPassData[whichPass].PassSetup; + + if (!pVulkan->CreateRenderPass( + { colorFormats }, + depthFormat, + VK_SAMPLE_COUNT_1_BIT, + passSetup.ColorInputUsage, + passSetup.ColorOutputUsage, + passSetup.ClearDepthRenderPass, + passSetup.DepthOutputUsage, + & m_RenderPassData[whichPass].RenderPass)) + { + return false; + } + + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::InitGui(uintptr_t windowHandle) +//----------------------------------------------------------------------------- +{ + const auto& hudRenderTarget = m_RenderPassData[RP_HUD].RenderTarget; + m_Gui = std::make_unique>(*GetVulkan(), m_RenderPassData[RP_HUD].RenderPass); + if (!m_Gui->Initialize(windowHandle, hudRenderTarget[0].m_Width, hudRenderTarget[0].m_Height)) + { + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::LoadMeshObjects() +//----------------------------------------------------------------------------- +{ + Vulkan* const pVulkan = GetVulkan(); + + LOGI("***********************"); + LOGI("Initializing Shaders... "); + LOGI("***********************"); + + const auto* pSGSRQuadShader = m_ShaderManager->GetShader("SGSR"); + const auto* pBlitQuadShader = m_ShaderManager->GetShader("Blit"); + if (!pSGSRQuadShader || !pBlitQuadShader) + { + return false; + } + + LOGI("*******************************"); + LOGI("Loading and preparing assets..."); + LOGI("*******************************"); + + m_TextureManager->SetDefaultFilenameManipulators(PathManipulator_PrefixDirectory{ "Media\\" }, PathManipulator_ChangeExtension{ ".ktx" }); + + m_sgsr_sampler = CreateSampler(*pVulkan, SamplerAddressMode::ClampEdge, SamplerFilter::Nearest, SamplerBorderColor::TransparentBlackFloat, 0.0f/*mipBias*/); + if (m_sgsr_sampler.IsEmpty()) + return false; + + auto* sceneTexture = apiCast(m_TextureManager->GetOrLoadTexture(*m_AssetManager, "Textures\\artifact.ktx", m_sgsr_sampler)); + + if (!sceneTexture) + { + LOGE("Failed to load supporting textures"); + return false; + } + + m_scene_texture_original_size.x = static_cast(sceneTexture->Width); + m_scene_texture_original_size.y = static_cast(sceneTexture->Height); + + LOGI("*********************"); + LOGI("Creating SGSR mesh..."); + LOGI("*********************"); + + MeshObject sgsrQuadMesh; + MeshHelper::CreateScreenSpaceMesh(pVulkan->GetMemoryManager(), 0, &sgsrQuadMesh); + + // SGSR Material + auto sgsrQuadShaderMaterial = m_MaterialManager->CreateMaterial(*pVulkan, *pSGSRQuadShader, pVulkan->m_SwapchainImageCount, + [this, &sceneTexture](const std::string& texName) -> const MaterialPass::tPerFrameTexInfo + { + if (texName == "SceneColor") + { + return { sceneTexture }; + } + return {}; + }, + [this](const std::string& bufferName) -> tPerFrameVkBuffer + { + if (bufferName == "SceneInfo") + { + return { m_SGSRFragUniform.buf.GetVkBuffer() }; + } + + return {}; + } + ); + + m_SGSRQuadDrawable = std::make_unique(*pVulkan, std::move(sgsrQuadShaderMaterial)); + if (!m_SGSRQuadDrawable->Init(m_RenderPassData[RP_SGSR].RenderPass, sRenderPassNames[RP_SGSR], std::move(sgsrQuadMesh))) + { + return false; + } + + LOGI("*********************"); + LOGI("Creating Blit mesh..."); + LOGI("*********************"); + + MeshObject blitQuadMesh; + MeshHelper::CreateScreenSpaceMesh(pVulkan->GetMemoryManager(), 0, &blitQuadMesh); + + // Blit Material + auto blitQuadShaderMaterial = m_MaterialManager->CreateMaterial(*pVulkan, *pBlitQuadShader, pVulkan->m_SwapchainImageCount, + [this](const std::string& texName) -> const MaterialPass::tPerFrameTexInfo + { + if (texName == "Diffuse") + { + return { &m_RenderPassData[RP_SGSR].RenderTarget[0].m_ColorAttachments[0] }; + } + else if (texName == "Overlay") + { + return { &m_RenderPassData[RP_HUD].RenderTarget[0].m_ColorAttachments[0] }; + } + return {}; + }, + [this](const std::string& bufferName) -> tPerFrameVkBuffer + { + return {}; + } + ); + + m_BlitQuadDrawable = std::make_unique(*pVulkan, std::move(blitQuadShaderMaterial)); + if (!m_BlitQuadDrawable->Init(m_RenderPassData[RP_BLIT].RenderPass, sRenderPassNames[RP_BLIT], std::move(blitQuadMesh))) + { + return false; + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::InitCommandBuffers() +//----------------------------------------------------------------------------- +{ + LOGI("*******************************"); + LOGI("Initializing Command Buffers..."); + LOGI("*******************************"); + + Vulkan* const pVulkan = GetVulkan(); + + auto GetPassName = [](uint32_t whichPass) + { + if (whichPass >= sRenderPassNames.size()) + { + LOGE("GetPassName() called with unknown pass (%d)!", whichPass); + return "RP_UNKNOWN"; + } + + return sRenderPassNames[whichPass]; + }; + + m_RenderPassData[RP_SGSR].PassCmdBuffer.resize(NUM_VULKAN_BUFFERS); + m_RenderPassData[RP_SGSR].ObjectsCmdBuffer.resize(NUM_VULKAN_BUFFERS); + m_RenderPassData[RP_HUD].PassCmdBuffer.resize(NUM_VULKAN_BUFFERS); + m_RenderPassData[RP_HUD].ObjectsCmdBuffer.resize(NUM_VULKAN_BUFFERS); + m_RenderPassData[RP_BLIT].PassCmdBuffer.resize(pVulkan->m_SwapchainImageCount); + m_RenderPassData[RP_BLIT].ObjectsCmdBuffer.resize(pVulkan->m_SwapchainImageCount); + + char szName[256]; + const VkCommandBufferLevel CmdBuffLevel = VK_COMMAND_BUFFER_LEVEL_SECONDARY; + for (uint32_t whichPass = 0; whichPass < NUM_RENDER_PASSES; whichPass++) + { + for (uint32_t whichBuffer = 0; whichBuffer < m_RenderPassData[whichPass].PassCmdBuffer.size(); whichBuffer++) + { + // The Pass Command Buffer => Primary + sprintf(szName, "Primary (%s; Buffer %d of %d)", GetPassName(whichPass), whichBuffer + 1, NUM_VULKAN_BUFFERS); + if (!m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].Initialize(pVulkan, szName, VK_COMMAND_BUFFER_LEVEL_PRIMARY)) + { + return false; + } + + // Model => Secondary + sprintf(szName, "Model (%s; Buffer %d of %d)", GetPassName(whichPass), whichBuffer + 1, NUM_VULKAN_BUFFERS); + if (!m_RenderPassData[whichPass].ObjectsCmdBuffer[whichBuffer].Initialize(pVulkan, szName, CmdBuffLevel)) + { + return false; + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::InitLocalSemaphores() +//----------------------------------------------------------------------------- +{ + LOGI("********************************"); + LOGI("Initializing Local Semaphores..."); + LOGI("********************************"); + + const VkSemaphoreCreateInfo SemaphoreInfo = { VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO }; + + for (uint32_t whichPass = 0; whichPass < NUM_RENDER_PASSES; whichPass++) + { + VkResult retVal = vkCreateSemaphore(GetVulkan()->m_VulkanDevice, &SemaphoreInfo, NULL, &m_RenderPassData[whichPass].PassCompleteSemaphore); + if (!CheckVkError("vkCreateSemaphore()", retVal)) + { + return false; + } + } + + return true; +} + +//----------------------------------------------------------------------------- +bool Application::BuildCmdBuffers() +//----------------------------------------------------------------------------- +{ + LOGI("***************************"); + LOGI("Building Command Buffers..."); + LOGI("****************************"); + + Vulkan* const pVulkan = GetVulkan(); + + // Begin recording + for (uint32_t whichPass = 0; whichPass < NUM_RENDER_PASSES; whichPass++) + { + auto& renderPassData = m_RenderPassData[whichPass]; + bool bisSwapChainRenderPass = whichPass == RP_BLIT; + + for (uint32_t whichBuffer = 0; whichBuffer < renderPassData.ObjectsCmdBuffer.size(); whichBuffer++) + { + auto& cmdBufer = renderPassData.ObjectsCmdBuffer[whichBuffer]; + + uint32_t targetWidth = bisSwapChainRenderPass ? pVulkan->m_SurfaceWidth : renderPassData.RenderTarget[0].m_Width; + uint32_t targetHeight = bisSwapChainRenderPass ? pVulkan->m_SurfaceHeight : renderPassData.RenderTarget[0].m_Height; + + VkViewport viewport = {}; + viewport.x = 0.0f; + viewport.y = 0.0f; + viewport.width = (float)targetWidth; + viewport.height = (float)targetHeight; + viewport.minDepth = 0.0f; + viewport.maxDepth = 1.0f; + + VkRect2D scissor = {}; + scissor.offset.x = 0; + scissor.offset.y = 0; + scissor.extent.width = targetWidth; + scissor.extent.height = targetHeight; + + // Set up some values that change based on render pass + VkRenderPass whichRenderPass = renderPassData.RenderPass; + VkFramebuffer whichFramebuffer = bisSwapChainRenderPass ? pVulkan->m_SwapchainBuffers[whichBuffer].framebuffer : renderPassData.RenderTarget[0].m_FrameBuffer; + + // Objects (can render into any pass except Blit) + if (!cmdBufer.Begin(whichFramebuffer, whichRenderPass, bisSwapChainRenderPass)) + { + return false; + } + vkCmdSetViewport(cmdBufer.m_VkCommandBuffer, 0, 1, &viewport); + vkCmdSetScissor(cmdBufer.m_VkCommandBuffer, 0, 1, &scissor); + } + } + + // Blit quad drawable + AddDrawableToCmdBuffers(*m_BlitQuadDrawable.get(), m_RenderPassData[RP_BLIT].ObjectsCmdBuffer.data(), 1, static_cast(m_RenderPassData[RP_BLIT].ObjectsCmdBuffer.size())); + + // SGSR quad drawable + AddDrawableToCmdBuffers(*m_SGSRQuadDrawable.get(), m_RenderPassData[RP_SGSR].ObjectsCmdBuffer.data(), 1, static_cast(m_RenderPassData[RP_SGSR].ObjectsCmdBuffer.size())); + + // End recording + for (uint32_t whichPass = 0; whichPass < NUM_RENDER_PASSES; whichPass++) + { + auto& renderPassData = m_RenderPassData[whichPass]; + + for (uint32_t whichBuffer = 0; whichBuffer < renderPassData.ObjectsCmdBuffer.size(); whichBuffer++) + { + auto& cmdBufer = renderPassData.ObjectsCmdBuffer[whichBuffer]; + if (!cmdBufer.End()) + { + return false; + } + } + } + + return true; +} + +//----------------------------------------------------------------------------- +void Application::UpdateGui() +//----------------------------------------------------------------------------- +{ + if (m_Gui) + { + m_Gui->Update(); + ImGuiIO& io = ImGui::GetIO(); + + if (ImGui::Begin("FPS", (bool*)nullptr, ImGuiWindowFlags_NoTitleBar)) + { + ImGui::Text("Texture Size [%f, %f]", m_SGSRFragUniformData.TechniqueInfo.z, m_SGSRFragUniformData.TechniqueInfo.w); + ImGui::Text("Render Target Size [%d, %d]", gRenderWidth, gRenderHeight); + ImGui::Separator(); + ImGui::Text("SGSR"); + ImGui::Checkbox("SGSR Active", &m_sgsr_active); + ImGui::Checkbox("SGSR Edge Direction (remove banding)", &m_sgsr_edge_dir_active); + + static int super_resolution_selection = 0; + std::array super_resolution_options = {"Native", "1.25x", "1.33x", "1.66x", "2x"}; + if (ImGui::BeginCombo("Upscaler", super_resolution_options[super_resolution_selection])) + { + for (int i = 0; i < super_resolution_options.size(); i++) + { + if (ImGui::Selectable(super_resolution_options[i], i == super_resolution_selection)) + { + super_resolution_selection = i; + } + } + + ImGui::EndCombo(); + } + + switch (super_resolution_selection) + { + case 0: m_sgsr_factor = 1.0f; break; + case 1: m_sgsr_factor = 0.8f; break; + case 2: m_sgsr_factor = 0.75f; break; + case 3: m_sgsr_factor = 0.6f; break; + case 4: m_sgsr_factor = 0.5f; break; + } + } + ImGui::End(); + + return; + } +} + +//----------------------------------------------------------------------------- +bool Application::UpdateUniforms(uint32_t whichBuffer) +//----------------------------------------------------------------------------- +{ + Vulkan* const pVulkan = GetVulkan(); + + // SGSR data + { + // Calculate the scale factor required to properly display the input image at render + // resolution + m_sgsr_scale_factor = static_cast(gRenderHeight) / m_scene_texture_original_size.y; + + m_SGSRFragUniformData.TechniqueInfo.x = m_sgsr_active ? 1.0f : 0.0f; + m_SGSRFragUniformData.TechniqueInfo.y = m_sgsr_edge_dir_active ? 1.0f : 0.0f; + m_SGSRFragUniformData.TechniqueInfo.z = m_scene_texture_original_size.x * m_sgsr_factor * m_sgsr_scale_factor; + m_SGSRFragUniformData.TechniqueInfo.w = m_scene_texture_original_size.y * m_sgsr_factor * m_sgsr_scale_factor; + + m_SGSRFragUniformData.ViewportInfo.z = m_scene_texture_original_size.x; + m_SGSRFragUniformData.ViewportInfo.w = m_scene_texture_original_size.y; + m_SGSRFragUniformData.ViewportInfo.x = (1.0f / m_SGSRFragUniformData.ViewportInfo.z); + m_SGSRFragUniformData.ViewportInfo.y = (1.0f / m_SGSRFragUniformData.ViewportInfo.w); + + UpdateUniformBuffer(pVulkan, m_SGSRFragUniform, m_SGSRFragUniformData); + } + + return true; +} + +//----------------------------------------------------------------------------- +void Application::Render(float fltDiffTime) +//----------------------------------------------------------------------------- +{ + Vulkan* const pVulkan = GetVulkan(); + + // Obtain the next swap chain image for the next frame. + auto currentVulkanBuffer = pVulkan->SetNextBackBuffer(); + uint32_t whichBuffer = currentVulkanBuffer.idx; + + // ******************************** + // Application Draw() - Begin + // ******************************** + + UpdateGui(); + + // Update camera + m_Camera.UpdateController(fltDiffTime * 10.0f, *m_CameraController); + m_Camera.UpdateMatrices(); + + // Update uniform buffers with latest data + UpdateUniforms(whichBuffer); + + // First time through, wait for the back buffer to be ready + std::span pWaitSemaphores = { ¤tVulkanBuffer.semaphore, 1 }; + + const VkPipelineStageFlags DefaultGfxWaitDstStageMasks[] = { VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT }; + + // RP_SGSR + { + BeginRenderPass(whichBuffer, RP_SGSR, currentVulkanBuffer.swapchainPresentIdx); + AddPassCommandBuffer(whichBuffer, RP_SGSR); + EndRenderPass(whichBuffer, RP_SGSR); + + // Submit the commands to the queue. + SubmitRenderPass(whichBuffer, RP_SGSR, pWaitSemaphores, DefaultGfxWaitDstStageMasks, { &m_RenderPassData[RP_SGSR].PassCompleteSemaphore,1 }); + pWaitSemaphores = { &m_RenderPassData[RP_SGSR].PassCompleteSemaphore, 1 }; + } + + // RP_HUD + VkCommandBuffer guiCommandBuffer = VK_NULL_HANDLE; + if (m_Gui) + { + // Render gui (has its own command buffer, optionally returns vk_null_handle if not rendering anything) + guiCommandBuffer = GetGui()->Render(whichBuffer, m_RenderPassData[RP_HUD].RenderTarget[0].m_FrameBuffer); + if (guiCommandBuffer != VK_NULL_HANDLE) + { + BeginRenderPass(whichBuffer, RP_HUD, currentVulkanBuffer.swapchainPresentIdx); + vkCmdExecuteCommands(m_RenderPassData[RP_HUD].PassCmdBuffer[whichBuffer].m_VkCommandBuffer, 1, &guiCommandBuffer); + EndRenderPass(whichBuffer, RP_HUD); + + // Submit the commands to the queue. + SubmitRenderPass(whichBuffer, RP_HUD, pWaitSemaphores, DefaultGfxWaitDstStageMasks, { &m_RenderPassData[RP_HUD].PassCompleteSemaphore,1 }); + pWaitSemaphores = { &m_RenderPassData[RP_HUD].PassCompleteSemaphore,1 }; + } + } + + // Blit Results to the screen + { + BeginRenderPass(whichBuffer, RP_BLIT, currentVulkanBuffer.swapchainPresentIdx); + AddPassCommandBuffer(whichBuffer, RP_BLIT); + EndRenderPass(whichBuffer, RP_BLIT); + + // Submit the commands to the queue. + SubmitRenderPass(whichBuffer, RP_BLIT, pWaitSemaphores, DefaultGfxWaitDstStageMasks, { &m_RenderPassData[RP_BLIT].PassCompleteSemaphore,1 }, currentVulkanBuffer.fence); + pWaitSemaphores = { &m_RenderPassData[RP_BLIT].PassCompleteSemaphore,1 }; + } + + // Queue is loaded up, tell the driver to start processing + pVulkan->PresentQueue(pWaitSemaphores, currentVulkanBuffer.swapchainPresentIdx); + + // ******************************** + // Application Draw() - End + // ******************************** +} + +//----------------------------------------------------------------------------- +void Application::BeginRenderPass(uint32_t whichBuffer, RENDER_PASS whichPass, uint32_t WhichSwapchainImage) +//----------------------------------------------------------------------------- +{ + Vulkan* const pVulkan = GetVulkan(); + auto& renderPassData = m_RenderPassData[whichPass]; + bool bisSwapChainRenderPass = whichPass == RP_BLIT; + + if (!m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].Reset()) + { + LOGE("Pass (%d) command buffer Reset() failed !", whichPass); + } + + if (!m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].Begin()) + { + LOGE("Pass (%d) command buffer Begin() failed !", whichPass); + } + + VkFramebuffer framebuffer = nullptr; + switch (whichPass) + { + case RP_SGSR: + framebuffer = m_RenderPassData[whichPass].RenderTarget[0].m_FrameBuffer; + break; + case RP_HUD: + framebuffer = m_RenderPassData[whichPass].RenderTarget[0].m_FrameBuffer; + break; + case RP_BLIT: + framebuffer = pVulkan->m_SwapchainBuffers[WhichSwapchainImage].framebuffer; + break; + default: + framebuffer = nullptr; + break; + } + + assert(framebuffer != nullptr); + + VkRect2D passArea = {}; + passArea.offset.x = 0; + passArea.offset.y = 0; + passArea.extent.width = bisSwapChainRenderPass ? pVulkan->m_SurfaceWidth : renderPassData.RenderTarget[0].m_Width; + passArea.extent.height = bisSwapChainRenderPass ? pVulkan->m_SurfaceHeight : renderPassData.RenderTarget[0].m_Height; + + TextureFormat swapChainColorFormat = pVulkan->m_SurfaceFormat; + auto swapChainColorFormats = std::span({ &swapChainColorFormat, 1 }); + TextureFormat swapChainDepthFormat = pVulkan->m_SwapchainDepth.format; + std::span colorFormats = bisSwapChainRenderPass ? swapChainColorFormats : m_RenderPassData[whichPass].RenderTarget[0].m_pLayerFormats; + TextureFormat depthFormat = bisSwapChainRenderPass ? swapChainDepthFormat : m_RenderPassData[whichPass].RenderTarget[0].m_DepthFormat; + + VkClearColorValue clearColor = { renderPassData.PassSetup.ClearColor[0], renderPassData.PassSetup.ClearColor[1], renderPassData.PassSetup.ClearColor[2], renderPassData.PassSetup.ClearColor[3] }; + + m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].BeginRenderPass( + passArea, + 0.0f, + 1.0f, + { &clearColor , 1 }, + (uint32_t)colorFormats.size(), + depthFormat != TextureFormat::UNDEFINED, + m_RenderPassData[whichPass].RenderPass, + bisSwapChainRenderPass, + framebuffer, + VK_SUBPASS_CONTENTS_SECONDARY_COMMAND_BUFFERS); +} + + +//----------------------------------------------------------------------------- +void Application::AddPassCommandBuffer(uint32_t whichBuffer, RENDER_PASS whichPass) +//----------------------------------------------------------------------------- +{ + if (m_RenderPassData[whichPass].ObjectsCmdBuffer[whichBuffer].m_NumDrawCalls) + { + vkCmdExecuteCommands(m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].m_VkCommandBuffer, 1, &m_RenderPassData[whichPass].ObjectsCmdBuffer[whichBuffer].m_VkCommandBuffer); + } +} + +//----------------------------------------------------------------------------- +void Application::EndRenderPass(uint32_t whichBuffer, RENDER_PASS whichPass) +//----------------------------------------------------------------------------- +{ + m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].EndRenderPass(); +} + +//----------------------------------------------------------------------------- +void Application::SubmitRenderPass(uint32_t whichBuffer, RENDER_PASS whichPass, const std::span WaitSemaphores, const std::span WaitDstStageMasks, std::span SignalSemaphores, VkFence CompletionFence) +//----------------------------------------------------------------------------- +{ + m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].End(); + m_RenderPassData[whichPass].PassCmdBuffer[whichBuffer].QueueSubmit(WaitSemaphores, WaitDstStageMasks, SignalSemaphores, CompletionFence); +} diff --git a/samples/sgsr/code/main/application.hpp b/samples/sgsr/code/main/application.hpp new file mode 100644 index 0000000..f95e012 --- /dev/null +++ b/samples/sgsr/code/main/application.hpp @@ -0,0 +1,139 @@ +//============================================================================================================ +// +// +// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +/// +/// Sample app demonstrating the loading of a .gltf file (hello world) +/// +#pragma once + +#include "main/applicationHelperBase.hpp" +#include "memory/vulkan/uniform.hpp" +#include "vulkan/commandBuffer.hpp" +#include + +#define NUM_SPOT_LIGHTS 4 + +class ShaderManager; +class MaterialManager; +class Drawable; + +enum RENDER_PASS +{ + RP_SGSR = 0, + RP_HUD, + RP_BLIT, + NUM_RENDER_PASSES +}; + +// ********************** +// Uniform Buffers +// ********************** +struct SGSRFragUB +{ + glm::vec4 ViewportInfo; + glm::vec4 TechniqueInfo; +}; + +// ********************** +// Render Pass +// ********************** +struct PassSetupInfo +{ + RenderPassInputUsage ColorInputUsage; + bool ClearDepthRenderPass; + RenderPassOutputUsage ColorOutputUsage; + RenderPassOutputUsage DepthOutputUsage; + glm::vec4 ClearColor; +}; + +struct PassData +{ + // Pass internal data + PassSetupInfo PassSetup; + VkRenderPass RenderPass = VK_NULL_HANDLE; + + // Recorded objects that are set to be drawn on this pass + std::vector< CommandListVulkan> ObjectsCmdBuffer; + + // Command buffer used to dispatch the render pass + std::vector< CommandListVulkan> PassCmdBuffer; + + // Indicates the completing of the underlying render pass + VkSemaphore PassCompleteSemaphore = VK_NULL_HANDLE; + + // Render targed used by the underlying render pass + // note: The blit pass uses the backbuffer directly instead this RT + CRenderTargetArray<1> RenderTarget; +}; + +// ********************** +// Application +// ********************** +class Application : public ApplicationHelperBase +{ +public: + Application(); + ~Application() override; + + // ApplicationHelperBase + virtual bool Initialize(uintptr_t windowHandle, uintptr_t hInstance) override; + virtual void Destroy() override; + virtual void Render(float fltDiffTime) override; + virtual int PreInitializeSelectSurfaceFormat(std::span surfaceFormat) override; + virtual void PreInitializeSetVulkanConfiguration(Vulkan::AppConfiguration& configuration) override; + +private: + + // Application - Initialization + bool InitializeCamera(); + bool LoadShaders(); + bool CreateRenderTargets(); + bool InitUniforms(); + bool InitAllRenderPasses(); + bool InitGui(uintptr_t windowHandle); + bool LoadMeshObjects(); + bool InitCommandBuffers(); + bool InitLocalSemaphores(); + bool BuildCmdBuffers(); + +private: + + // Application - Frame + void BeginRenderPass(uint32_t WhichBuffer, RENDER_PASS WhichPass, uint32_t WhichSwapchainImage); + void AddPassCommandBuffer(uint32_t WhichBuffer, RENDER_PASS WhichPass); + void EndRenderPass(uint32_t WhichBuffer, RENDER_PASS WhichPass); + void SubmitRenderPass(uint32_t WhichBuffer, RENDER_PASS WhichPass, const std::span WaitSemaphores, const std::span WaitDstStageMasks, std::span SignalSemaphores, VkFence CompletionFence = (VkFence)nullptr); + void UpdateGui(); + bool UpdateUniforms(uint32_t WhichBuffer); + +private: + + // Render passes + std::array< PassData, NUM_RENDER_PASSES> m_RenderPassData; + + // UBOs + UniformT m_SGSRFragUniform; + SGSRFragUB m_SGSRFragUniformData; + + glm::vec2 m_scene_texture_original_size; + float m_sgsr_factor = 1.0f; + float m_sgsr_scale_factor = 1.0f; + bool m_sgsr_active = false; + bool m_sgsr_edge_dir_active = false; + SamplerT m_sgsr_sampler; + + // Drawables + std::unique_ptr m_SGSRQuadDrawable; + std::unique_ptr m_BlitQuadDrawable; + + // Shaders + std::unique_ptr m_ShaderManager; + + // Materials + std::unique_ptr m_MaterialManager; +}; diff --git a/samples/sgsr/img/screenshot.png b/samples/sgsr/img/screenshot.png new file mode 100644 index 0000000..b77b563 Binary files /dev/null and b/samples/sgsr/img/screenshot.png differ diff --git a/samples/sgsr/project/android/AndroidManifest.xml b/samples/sgsr/project/android/AndroidManifest.xml new file mode 100644 index 0000000..0d06fc4 --- /dev/null +++ b/samples/sgsr/project/android/AndroidManifest.xml @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/samples/sgsr/project/android/res/mipmap-hdpi/ic_launcher.png b/samples/sgsr/project/android/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000..1b58b37 Binary files /dev/null and b/samples/sgsr/project/android/res/mipmap-hdpi/ic_launcher.png differ diff --git a/samples/sgsr/project/android/res/mipmap-mdpi/ic_launcher.png b/samples/sgsr/project/android/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000..11acf77 Binary files /dev/null and b/samples/sgsr/project/android/res/mipmap-mdpi/ic_launcher.png differ diff --git a/samples/sgsr/project/android/res/mipmap-xhdpi/ic_launcher.png b/samples/sgsr/project/android/res/mipmap-xhdpi/ic_launcher.png new file mode 100644 index 0000000..b8016f2 Binary files /dev/null and b/samples/sgsr/project/android/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/samples/sgsr/project/android/res/mipmap-xxhdpi/ic_launcher.png b/samples/sgsr/project/android/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000..c0b9e85 Binary files /dev/null and b/samples/sgsr/project/android/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/samples/sgsr/project/android/res/mipmap-xxxhdpi/ic_launcher.png b/samples/sgsr/project/android/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100644 index 0000000..7df4d52 Binary files /dev/null and b/samples/sgsr/project/android/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/samples/sgsr/project/android/res/values/strings.xml b/samples/sgsr/project/android/res/values/strings.xml new file mode 100644 index 0000000..465d045 --- /dev/null +++ b/samples/sgsr/project/android/res/values/strings.xml @@ -0,0 +1,4 @@ + + + Snapdragon GSR + diff --git a/samples/sgsr/shaders/Blit.frag b/samples/sgsr/shaders/Blit.frag new file mode 100644 index 0000000..839bc24 --- /dev/null +++ b/samples/sgsr/shaders/Blit.frag @@ -0,0 +1,65 @@ +//============================================================================================================ +// +// +// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 400 + +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +// Buffer binding locations +#define SHADER_DIFFUSE_TEXTURE_LOC 0 +#define SHADER_OVERLAY_TEXTURE_LOC 1 + +layout(set = 0, binding = SHADER_DIFFUSE_TEXTURE_LOC) uniform sampler2D u_DiffuseTex; +layout(set = 0, binding = SHADER_OVERLAY_TEXTURE_LOC) uniform sampler2D u_OverlayTex; + +// Varying's +layout (location = 0) in vec2 v_TexCoord; +layout (location = 1) in vec4 v_VertColor; + +// Finally, the output color +layout (location = 0) out vec4 FragColor; + + +//----------------------------------------------------------------------------- +void main() +//----------------------------------------------------------------------------- +{ + vec2 LocalTexCoord = vec2(v_TexCoord.xy); + + // ******************************** + // Texture Colors + // ******************************** + // Get base color from the color texture + vec4 DiffuseColor = texture( u_DiffuseTex, LocalTexCoord.xy ); + + // Multiply by vertex color. + DiffuseColor.xyzw *= v_VertColor.xyzw; + + // Apply darkening/lightening control + // float lerp01 = min(1,FragCB.Diffuse); + // float lerp12 = max(0,FragCB.Diffuse-1); + // DiffuseColor = DiffuseColor * lerp01 + lerp12 - lerp12 * DiffuseColor; + + // Get the Overlay value + vec4 OverlayColor = texture( u_OverlayTex, LocalTexCoord.xy ); + + // ******************************** + // Alpha Blending + // ******************************** + FragColor.rgb = DiffuseColor.rgb *(1.0-OverlayColor.a) + OverlayColor.rgb; + FragColor.a = 1.0; + + // DEBUG! DEBUG! DEBUG! DEBUG! DEBUG! DEBUG! DEBUG! DEBUG! DEBUG! DEBUG! DEBUG! + // FragColor.xyz = (1.0 - OverlayColor.a) * DiffuseColor.xyz + OverlayColor.a * OverlayColor.xyz; + // FragColor = vec4(DiffuseColor.xyz, DiffuseColor.a); + // FragColor = vec4(OverlayColor.xyz, OverlayColor.a); + // FragColor.a = 1.0; + // FragColor = vec4(0.8, 0.2, 0.8, 1.0); +} + diff --git a/samples/sgsr/shaders/Blit.json b/samples/sgsr/shaders/Blit.json new file mode 100644 index 0000000..d7d32c6 --- /dev/null +++ b/samples/sgsr/shaders/Blit.json @@ -0,0 +1,64 @@ +{ + "$schema": "../../../framework/schema/shaderSchema.json", + "Passes": [ + { + "Name": "RP_BLIT", + "Shaders": { + "Vertex": "Media/Shaders/Blit.vert.spv", + "Fragment": "Media/Shaders/Blit.frag.spv" + }, + "DescriptorSets": [ + { + "Buffers": [ + { + "Type": "ImageSampler", + "Stages": [ "Fragment" ], + "Count": 1, + "Names": [ "Diffuse" ] + }, + { + "Type": "ImageSampler", + "Stages": [ "Fragment" ], + "Count": 1, + "Names": [ "Overlay" ] + } + ] + } + ], + "VertexBindings": [ "VB0" ] + } + ], + "Vertex": [ + { + "Span": 60, + "Name": "VB0", + "Elements": [ + { + "Name": "Position", + "Offset": 0, + "Type": "Vec3" + }, + { + "Name": "Normal", + "Offset": 12, + "Type": "Vec3" + }, + { + "Name": "UV", + "Offset": 24, + "Type": "Vec2" + }, + { + "Name": "Color", + "Offset": 32, + "Type": "Vec4" + }, + { + "Name": "Tangent", + "Offset": 48, + "Type": "Vec3" + } + ] + } + ] +} diff --git a/samples/sgsr/shaders/Blit.vert b/samples/sgsr/shaders/Blit.vert new file mode 100644 index 0000000..d11750a --- /dev/null +++ b/samples/sgsr/shaders/Blit.vert @@ -0,0 +1,38 @@ +//============================================================================================================ +// +// +// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 400 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +#define SHADER_ATTRIB_LOC_POSITION 0 +#define SHADER_ATTRIB_LOC_NORMAL 1 +#define SHADER_ATTRIB_LOC_TEXCOORD0 2 +#define SHADER_ATTRIB_LOC_COLOR 3 +#define SHADER_ATTRIB_LOC_TANGENT 4 + +layout (location = SHADER_ATTRIB_LOC_POSITION ) in vec4 a_Position; +layout (location = SHADER_ATTRIB_LOC_NORMAL ) in vec3 a_Normal; +layout (location = SHADER_ATTRIB_LOC_TEXCOORD0) in vec2 a_TexCoord; +layout (location = SHADER_ATTRIB_LOC_COLOR ) in vec4 a_Color; +layout (location = SHADER_ATTRIB_LOC_TANGENT ) in vec4 a_Tangent; + +// Varying's +layout (location = 0) out vec2 v_TexCoord; +layout (location = 1) out vec4 v_VertColor; + +void main() +{ + // Position and text coord are simple (Except Y in inverted on screen compared to OpenGL) + vec4 TempPos = vec4(a_Position.xyz, 1.0); + gl_Position = vec4(TempPos.x, -TempPos.y, TempPos.z, TempPos.w); + v_TexCoord = vec2(a_TexCoord.xy); + + // Color is simple attribute color + v_VertColor.xyzw = vec4(a_Color.xyz, 1.0); +} diff --git a/samples/sgsr/shaders/sgsr_shader.vert b/samples/sgsr/shaders/sgsr_shader.vert new file mode 100644 index 0000000..f134e60 --- /dev/null +++ b/samples/sgsr/shaders/sgsr_shader.vert @@ -0,0 +1,34 @@ +//============================================================================================================ +// +// +// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +#version 400 +#extension GL_ARB_separate_shader_objects : enable +#extension GL_ARB_shading_language_420pack : enable + +#define SHADER_ATTRIB_LOC_POSITION 0 +#define SHADER_ATTRIB_LOC_NORMAL 1 +#define SHADER_ATTRIB_LOC_TEXCOORD0 2 +#define SHADER_ATTRIB_LOC_COLOR 3 +#define SHADER_ATTRIB_LOC_TANGENT 4 + +layout (location = SHADER_ATTRIB_LOC_POSITION ) in vec4 a_Position; +layout (location = SHADER_ATTRIB_LOC_NORMAL ) in vec3 a_Normal; +layout (location = SHADER_ATTRIB_LOC_TEXCOORD0) in vec2 a_TexCoord; +layout (location = SHADER_ATTRIB_LOC_COLOR ) in vec4 a_Color; +layout (location = SHADER_ATTRIB_LOC_TANGENT ) in vec4 a_Tangent; + +// Varying's +layout (location = 0) out vec4 v_TexCoord; + +void main() +{ + // Position and text coord are simple (Except Y in inverted on screen compared to OpenGL) + vec4 TempPos = vec4(a_Position.xyz, 1.0); + gl_Position = vec4(TempPos.x, -TempPos.y, TempPos.z, TempPos.w); + v_TexCoord = vec4(a_TexCoord.xy, 0.0, 0.0); +} diff --git a/samples/sgsr/shaders/sgsr_shader_mobile.frag b/samples/sgsr/shaders/sgsr_shader_mobile.frag new file mode 100644 index 0000000..176f61d --- /dev/null +++ b/samples/sgsr/shaders/sgsr_shader_mobile.frag @@ -0,0 +1,199 @@ +#version 320 es + +//============================================================================================================ +// +// +// Copyright (c) 2023, Qualcomm Innovation Center, Inc. All rights reserved. +// SPDX-License-Identifier: BSD-3-Clause +// +//============================================================================================================ + +// NOTE: This shader was modified for the sample, it contains more uniform variables and it's +// not optimal, see https://github.com/quic/snapdragon-gsr for the official shader files + +precision mediump float; +precision highp int; + +//////////////////////// +// USER CONFIGURATION // +//////////////////////// + +/* +* Operation modes: +* RGBA -> 1 +* RGBY -> 3 +* LERP -> 4 +*/ +#define OperationMode 1 + +#define EdgeThreshold 8.0/255.0 + +#define EdgeSharpness 2.0 + +#define UseUniformBlock + +//////////////////////// +//////////////////////// +//////////////////////// + +#if defined(UseUniformBlock) +layout (set=0, binding = 0) uniform UniformBlock +{ + highp vec4 ViewportInfo[1]; + highp vec4 TechniqueInfo[1]; +}; +layout(set = 0, binding = 1) uniform mediump sampler2D ps0; +#else +uniform highp vec4 ViewportInfo[1]; +uniform highp vec4 TechniqueInfo[1]; +uniform mediump sampler2D ps0; +#endif + +layout(location=0) in highp vec4 in_TEXCOORD0; +layout(location=0) out vec4 out_Target0; + +float fastLanczos2(float x) +{ + float wA = x-4.0; + float wB = x*wA-wA; + wA *= wA; + return wB*wA; +} + +vec2 weightY(float dx, float dy,float c, vec3 data) +{ + bool should_apply_edge_direction = TechniqueInfo[0].y > 0.5; // Simulates UseEdgeDirection on the original shader + + float x = 0.0; + + if(should_apply_edge_direction) + { + float std = data.x; + vec2 dir = data.yz; + + float edgeDis = ((dx*dir.y)+(dy*dir.x)); + x = (((dx*dx)+(dy*dy))+((edgeDis*edgeDis)*((clamp(((c*c)*std),0.0,1.0)*0.7)+-1.0))); + } + else + { + float std = data.x; + x = ((dx*dx)+(dy* dy))* 0.55 + clamp(abs(c)*std, 0.0, 1.0); + } + + float w = fastLanczos2(x); + return vec2(w, w * c); +} + +vec2 edgeDirection(vec4 left, vec4 right) +{ + vec2 dir; + float RxLz = (right.x + (-left.z)); + float RwLy = (right.w + (-left.y)); + vec2 delta; + delta.x = (RxLz + RwLy); + delta.y = (RxLz + (-RwLy)); + float lengthInv = inversesqrt((delta.x * delta.x+ 3.075740e-05) + (delta.y * delta.y)); + dir.x = (delta.x * lengthInv); + dir.y = (delta.y * lengthInv); + return dir; +} + +void main() +{ + const int mode = OperationMode; + const float edgeThreshold = EdgeThreshold; + const float edgeSharpness = EdgeSharpness; + bool should_apply_sgsr = TechniqueInfo[0].x > 0.5; + bool should_apply_edge_direction = TechniqueInfo[0].y > 0.5; // Simulates UseEdgeDirection on the original shader + + ////////////////////////////////////////////////////////////////////////////////// + // Modify the texture coordinates to support simulating different texture sizes // + ////////////////////////////////////////////////////////////////////////////////// + + highp vec4 MODIFIED_TEXCOORD0 = in_TEXCOORD0; + MODIFIED_TEXCOORD0.xy = floor(MODIFIED_TEXCOORD0.xy * TechniqueInfo[0].zw) / TechniqueInfo[0].zw; + + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////// + + vec4 color; + if(mode == 1) + color.xyz = textureLod(ps0,MODIFIED_TEXCOORD0.xy,0.0).xyz; + else + color.xyzw = textureLod(ps0,MODIFIED_TEXCOORD0.xy,0.0).xyzw; + + highp float xCenter; + xCenter = abs(MODIFIED_TEXCOORD0.x+-0.5); + highp float yCenter; + yCenter = abs(MODIFIED_TEXCOORD0.y+-0.5); + + if (should_apply_sgsr) + { + highp vec2 imgCoord = ((MODIFIED_TEXCOORD0.xy*ViewportInfo[0].zw)+vec2(-0.5,0.5)); + highp vec2 imgCoordPixel = floor(imgCoord); + highp vec2 coord = (imgCoordPixel*ViewportInfo[0].xy); + vec2 pl = (imgCoord+(-imgCoordPixel)); + vec4 left = textureGather(ps0,coord, mode); + + float edgeVote = abs(left.z - left.y) + abs(color[mode] - left.y) + abs(color[mode] - left.z) ; + if(edgeVote > edgeThreshold) + { + coord.x += ViewportInfo[0].x; + + vec4 right = textureGather(ps0,coord + vec2(ViewportInfo[0].x, 0.0), OperationMode); + vec4 upDown; + upDown.xy = textureGather(ps0,coord + vec2(0.0, -ViewportInfo[0].y),OperationMode).wz; + upDown.zw = textureGather(ps0,coord + vec2(0.0, ViewportInfo[0].y), OperationMode).yx; + + float mean = (left.y+left.z+right.x+right.w)*0.25; + left = left - vec4(mean); + right = right - vec4(mean); + upDown = upDown - vec4(mean); + color.w =color[OperationMode] - mean; + + float sum = (((((abs(left.x)+abs(left.y))+abs(left.z))+abs(left.w))+(((abs(right.x)+abs(right.y))+abs(right.z))+abs(right.w)))+(((abs(upDown.x)+abs(upDown.y))+abs(upDown.z))+abs(upDown.w))); + float sumMean = 1.014185e+01/sum; + + float std = 0.0; + if(should_apply_edge_direction) + { + std = (sumMean*sumMean); + } + else + { + std = 2.181818/sum; + } + + vec3 data = vec3(std, edgeDirection(left, right)); + + vec2 aWY = weightY(pl.x, pl.y+1.0, upDown.x,data); + aWY += weightY(pl.x-1.0, pl.y+1.0, upDown.y,data); + aWY += weightY(pl.x-1.0, pl.y-2.0, upDown.z,data); + aWY += weightY(pl.x, pl.y-2.0, upDown.w,data); + aWY += weightY(pl.x+1.0, pl.y-1.0, left.x,data); + aWY += weightY(pl.x, pl.y-1.0, left.y,data); + aWY += weightY(pl.x, pl.y, left.z,data); + aWY += weightY(pl.x+1.0, pl.y, left.w,data); + aWY += weightY(pl.x-1.0, pl.y-1.0, right.x,data); + aWY += weightY(pl.x-2.0, pl.y-1.0, right.y,data); + aWY += weightY(pl.x-2.0, pl.y, right.z,data); + aWY += weightY(pl.x-1.0, pl.y, right.w,data); + + float finalY = aWY.y/aWY.x; + float maxY = max(max(left.y,left.z),max(right.x,right.w)); + float minY = min(min(left.y,left.z),min(right.x,right.w)); + float deltaY = clamp(EdgeSharpness*finalY, minY, maxY) -color.w; + + //smooth high contrast input + deltaY = clamp(deltaY, -23.0 / 255.0, 23.0 / 255.0); + + color.x = clamp((color.x+deltaY),0.0,1.0); + color.y = clamp((color.y+deltaY),0.0,1.0); + color.z = clamp((color.z+deltaY),0.0,1.0); + } + } + + color.w = 1.0; //assume alpha channel is not used + out_Target0.xyzw = color; +} \ No newline at end of file diff --git a/samples/sgsr/shaders/sgsr_shader_mobile.json b/samples/sgsr/shaders/sgsr_shader_mobile.json new file mode 100644 index 0000000..5b001d9 --- /dev/null +++ b/samples/sgsr/shaders/sgsr_shader_mobile.json @@ -0,0 +1,63 @@ +{ + "$schema": "../../../framework/schema/shaderSchema.json", + "Passes": [ + { + "Name": "RP_SGSR", + "Shaders": { + "Vertex": "Media/Shaders/sgsr_shader.vert.spv", + "Fragment": "Media/Shaders/sgsr_shader_mobile.frag.spv" + }, + "DescriptorSets": [ + { + "Buffers": [ + { + "Type": "UniformBuffer", + "Stages": [ "Fragment" ], + "Names": [ "SceneInfo" ] + }, + { + "Type": "ImageSampler", + "Stages": [ "Fragment" ], + "Count": 1, + "Names": [ "SceneColor" ] + } + ] + } + ], + "VertexBindings": [ "VB0" ] + } + ], + "Vertex": [ + { + "Span": 60, + "Name": "VB0", + "Elements": [ + { + "Name": "Position", + "Offset": 0, + "Type": "Vec3" + }, + { + "Name": "Normal", + "Offset": 12, + "Type": "Vec3" + }, + { + "Name": "UV", + "Offset": 24, + "Type": "Vec2" + }, + { + "Name": "Color", + "Offset": 32, + "Type": "Vec4" + }, + { + "Name": "Tangent", + "Offset": 48, + "Type": "Vec3" + } + ] + } + ] +}