291 lines
12 KiB
C++

// This file is part of the FidelityFX SDK.
//
// Copyright (C) 2024 Advanced Micro Devices, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files(the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and /or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions :
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
#pragma once
#include <vector>
#include <mutex>
#include "render/rendermodule.h"
#include "core/framework.h"
#include "core/uimanager.h"
#include "core/contentmanager.h"
#include "render/renderdefines.h"
#include <FidelityFX/host/ffx_brixelizer.h>
#include <FidelityFX/host/ffx_brixelizergi.h>
#include "shaders/brixelizergiexampletypes.h"
namespace cauldron
{
class ParameterSet;
class RootSignature;
}; // namespace cauldron
/// @defgroup FfxBrixelizerSample FidelityFX Brixelizer sample
/// Sample documentation for FidelityFX Brixelizer
///
/// @ingroup SDKEffects
/// @defgroup BrixelizerRM Brixelizer RenderModule
/// BrixelizerRenderModule Reference Documentation
///
/// @ingroup FfxBrixelizerSample
/// @{
// Brixelizer supports a maximum of 24 raw cascades
// In the sample each cascade level we build is created by building a static cascade,
// a dynamic cascade, and then merging those into a merged cascade. Hence we require
// 3 raw cascades per cascade level.
#define NUM_BRIXELIZER_CASCADES (FFX_BRIXELIZER_MAX_CASCADES / 3)
// Brixelizer makes use of a scratch buffer for calculating cascade updates. Hence in
// this sample we allocate a buffer to be used as scratch space. Here we have chosen
// a somewhat arbitrary large size for use as scratch space, in a real application this
// value should be tuned to what is required by Brixelizer.
#define GPU_SCRATCH_BUFFER_SIZE (1 << 30)
class BrixelizerGIRenderModule : public cauldron::RenderModule, public cauldron::ContentListener
{
public:
/**
* @brief Constructor with default behavior.
*/
BrixelizerGIRenderModule() : RenderModule(L"BrixelizerGIRenderModule"), ContentListener() {}
virtual ~BrixelizerGIRenderModule();
/**
* @brief Tear down the FFX API Context and release resources.
*/
void Init(const json& initData) override;
/**
* @brief Initialize FFX API Context, Brixelizer context, create resources and setup UI section.
*/
void EnableModule(bool enabled) override;
/**
* @brief Submit dynamic instances, dispatch Brixelizer workloads and visualize sparse distance field using the example shader.
*/
void Execute(double deltaTime, cauldron::CommandList* pCmdList) override;
/**
* @brief Window resize callback with default behavior.
*/
void OnResize(const cauldron::ResolutionInfo& resInfo) override;
/**
* @brief Create Brixelizer instances for all loaded mesh geometry.
*/
void OnNewContentLoaded(cauldron::ContentBlock* pContentBlock) override;
/**
* @brief Delete Brixelizer instances for all unloaded mesh geometry.
*/
void OnContentUnloaded(cauldron::ContentBlock* pContentBlock) override;
private:
// Enum representing the Brixelizer cascade types.
enum class CascadeType
{
Static = 0,
Dynamic,
Merged
};
// Enum representing the Debug Visualization pass output types.
enum class DebugVisOutputType
{
Distance = 0,
UVW,
Iterations,
Gradient,
BrickID,
CascadeID
};
// Enum representing the output modes of the sample.
enum class OutputMode
{
None,
ExampleShader,
DebugVisualization,
DiffuseGI,
SpecularGI,
RadianceCache,
IrradianceCache
};
struct BrixelizerInstanceInfo
{
const cauldron::Entity* entity;
const cauldron::Surface* surface;
FfxBrixelizerInstanceID instanceID;
bool isDynamic;
};
struct BrixelizerBufferInfo
{
uint32_t index;
const cauldron::Buffer* buffer;
};
std::mutex m_CriticalSection;
std::mutex m_TextureLoadCallbackMutex;
uint32_t m_FrameIndex = 0;
// FidelityFX Brixelizer information
FfxBrixelizerContextDescription m_InitializationParameters = {};
FfxBrixelizerContext m_BrixelizerContext = {};
FfxBrixelizerBakedUpdateDescription m_BrixelizerBakedUpdateDesc = {};
const cauldron::Texture* m_pSdfAtlas = nullptr;
const cauldron::Buffer* m_pBrickAABBs = nullptr;
const cauldron::Buffer* m_pCascadeAABBTrees[FFX_BRIXELIZER_MAX_CASCADES] = {};
const cauldron::Buffer* m_pCascadeBrickMaps[FFX_BRIXELIZER_MAX_CASCADES] = {};
const cauldron::Buffer* m_pGpuScratchBuffer = nullptr;
std::vector<BrixelizerInstanceInfo> m_Instances = {};
std::vector<BrixelizerBufferInfo> m_Buffers = {};
// FidelityFX Brixelizer GI information
FfxBrixelizerGIContextDescription m_GIInitializationParameters = {};
FfxBrixelizerGIDispatchDescription m_GIDispatchDesc = {};
FfxBrixelizerGIContext m_BrixelizerGIContext = {};
const cauldron::Texture* m_pDiffuseGI = nullptr;
const cauldron::Texture* m_pSpecularGI = nullptr;
const cauldron::Texture* m_pDebugVisualization = nullptr;
const cauldron::Texture* m_pLitOutputCopy = nullptr;
// Config
float m_MeshUnitSize = 0.2f;
float m_CascadeSizeRatio = 2.0f;
OutputMode m_OutputMode = OutputMode::None;
CascadeType m_CascadeType = CascadeType::Merged;
DebugVisOutputType m_DebugVisOutputType = DebugVisOutputType::Gradient;
BrixelizerExampleOutputType m_ExampleOutputType = BRIXELIZER_EXAMPLE_OUTPUT_TYPE_GRADIENT;
uint32_t m_StartCascadeIdx = 0;
uint32_t m_EndCascadeIdx = NUM_BRIXELIZER_CASCADES - 1;
float m_TMin = 0.0f;
float m_TMax = 10000.0f;
float m_SdfSolveEps = 0.5f;
bool m_SdfCenterFollowCamera = true;
float m_SdfCenter[3] = {};
bool m_ShowStaticInstanceAABBs = false;
bool m_ShowDynamicInstanceAABBs = false;
bool m_ShowCascadeAABBs = false;
int32_t m_ShowAABBTreeIndex = -1;
bool m_ShowBrickOutlines = false;
float m_Alpha = 1.0f;
bool m_ResetStats = false;
float m_RayPushoff = 0.25f;
bool m_EnableGI = true;
bool m_MultiBounce = true;
float m_DiffuseGIFactor = 1.5f;
float m_SpecularGIFactor = 3.0f;
bool m_InitColorHistory = true;
// UI elements
std::vector<cauldron::UIElement*> m_StaticUIElements = {};
std::vector<cauldron::UIElement*> m_CommonUIElements = {};
std::vector<cauldron::UIElement*> m_DebugUIElements = {};
std::vector<cauldron::UIElement*> m_ExampleUIElements = {};
cauldron::UIElement* m_FreeBricksTextElement = nullptr;
cauldron::UIElement* m_StaticBricksTextElement = nullptr;
cauldron::UIElement* m_StaticTrianglesTextElement = nullptr;
cauldron::UIElement* m_StaticReferencesTextElement = nullptr;
cauldron::UIElement* m_DynamicBricksTextElement = nullptr;
cauldron::UIElement* m_DynamicTrianglesTextElement = nullptr;
cauldron::UIElement* m_DynamicReferencesTextElement = nullptr;
uint64_t m_MaxStaticTriangles = 0;
uint64_t m_MaxStaticReferences = 0;
uint64_t m_MaxStaticBricks = 0;
uint64_t m_MaxDynamicTriangles = 0;
uint64_t m_MaxDynamicReferences = 0;
uint64_t m_MaxDynamicBricks = 0;
// Input Resources
const cauldron::Texture* m_pColorTarget = nullptr;
const cauldron::Texture* m_pDiffuseTexture = nullptr;
const cauldron::Texture* m_pDepthBuffer = nullptr;
const cauldron::Texture* m_pNormalTarget = nullptr;
const cauldron::Texture* m_pVelocityBuffer = nullptr;
const cauldron::Texture* m_pRoughnessTarget = nullptr;
// Created Resources
const cauldron::Texture* m_pHistoryLitOutput = nullptr;
const cauldron::Texture* m_pHistoryDepth = nullptr;
const cauldron::Texture* m_pHistoryNormals = nullptr;
const cauldron::Texture* m_pEnivornmentMap = nullptr;
// Noise Textures
std::vector<const cauldron::Texture*> m_NoiseTextures;
// Matrices
Mat4 m_InvView;
Mat4 m_InvProj;
Mat4 m_PrevInvView;
Mat4 m_PrevInvProj;
Mat4 m_PrevProjection;
// Example pass resources
cauldron::RootSignature* m_pExampleRootSignature = nullptr;
cauldron::ParameterSet* m_pExampleParameterSet = nullptr;
cauldron::PipelineObject* m_pExamplePipeline = nullptr;
// Copy history pass resources
cauldron::RootSignature* m_pPassThroughRootSignature = nullptr;
cauldron::ParameterSet* m_pPassThroughParameterSet = {};
cauldron::PipelineObject* m_pPassThroughPipeline = nullptr;
// Deferred Lighting pass resources
cauldron::RootSignature* m_pDeferredLightingRootSignature = nullptr;
cauldron::ParameterSet* m_pDeferredLightingParameterSet = nullptr;
cauldron::PipelineObject* m_pDeferredLightingPipeline = nullptr;
void CreateBrixelizerContext();
void DeleteBrixelizerContext();
void RecreateBrixelizerContext();
void UpdateBrixelizerContext(cauldron::CommandList* pCmdList);
void SetupDebugVisualization(FfxBrixelizerUpdateDescription& updateDesc, FfxBrixelizerDebugVisualizationDescription& debugVisDesc);
void DispatchExampleShader(cauldron::CommandList* pCmdList);
void FlushInstances(bool flushStaticInstances);
void DeleteInstances();
void CreateBrixelizerGIContext();
void DeleteBrixelizerGIContext();
void RecreateBrixelizerGIContext();
void UpdateBrixelizerGIContext(cauldron::CommandList* pCmdList);
void CopyHistoryResource(cauldron::CommandList* pCmdList, const cauldron::Texture* pInput, const cauldron::Texture* pOutput, std::wstring name);
void CopyHistoryResources(cauldron::CommandList* pCmdList);
void DeferredLighting(cauldron::CommandList* pCmdList, bool enableGI);
void VisualizeGIDebug(cauldron::CommandList* pCmdList);
void TextureLoadComplete(const std::vector<const cauldron::Texture*>& textureList, void*);
void InitUI(cauldron::UISection* uiSection);
void UpdateUIElementVisibility();
void UpdateConfig();
uint32_t GetBufferIndex(const cauldron::Buffer *buffer);
};