mirror of
https://github.com/MaSzyna-EU07/maszyna.git
synced 2026-07-21 13:39:18 +02:00
merge manul
This commit is contained in:
142
manul/renderer/source/IntelTAA.h
Normal file
142
manul/renderer/source/IntelTAA.h
Normal file
@@ -0,0 +1,142 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2016-2021, Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Author(s): Lukasz, Migas (Lukasz.Migas@intel.com)
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// See https://github.com/GameTechDev/TAA
|
||||
|
||||
#ifndef __INTEL_TAA_H__
|
||||
#define __INTEL_TAA_H__
|
||||
|
||||
#define INTEL_TAA_NUM_THREADS_X 8
|
||||
#define INTEL_TAA_NUM_THREADS_Y 8
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace IntelTAA
|
||||
{
|
||||
// cpp<->hlsl mapping
|
||||
typedef glm::mat4 Matrix4x4;
|
||||
typedef glm::vec4 Vector4;
|
||||
typedef glm::vec3 Vector3;
|
||||
typedef glm::vec2 Vector2;
|
||||
typedef glm::ivec2 Vector2i;
|
||||
typedef glm::ivec4 Vector4i;
|
||||
typedef glm::uvec4 Vector4ui;
|
||||
typedef unsigned int uint32;
|
||||
|
||||
#else // #ifdef __cplusplus
|
||||
|
||||
// cpp<->hlsl mapping
|
||||
#define Matrix4x4 float4x4
|
||||
#define Vector4 float4
|
||||
#define Vector3 float3
|
||||
#define Vector2 float2
|
||||
#define Vector2i int2
|
||||
#define Vector4i int4
|
||||
#define Vector4ui uint4
|
||||
#define uint32 uint
|
||||
|
||||
#endif
|
||||
|
||||
// Constant buffer
|
||||
struct FTAAResolve
|
||||
{
|
||||
Vector4 Resolution; //width, height, 1/width, 1/height
|
||||
Vector2 Jitter;
|
||||
uint32 FrameNumber;
|
||||
uint32 DebugFlags; // AllowLongestVelocityVector | AllowNeighbourhoodSampling | AllowYCoCg | AllowVarianceClipping | AllowBicubicFilter | AllowDepthThreshold | MarkNoHistoryPixels
|
||||
float LerpMul;
|
||||
float LerpPow;
|
||||
float VarClipGammaMin; // (MIN_VARIANCE_GAMMA)
|
||||
float VarClipGammaMax; // (MAX_VARIANCE_GAMMA)
|
||||
float PreExposureNewOverOld;
|
||||
float Padding0;
|
||||
float Padding1;
|
||||
float Padding2;
|
||||
};
|
||||
|
||||
#ifndef __cplusplus
|
||||
|
||||
typedef float fp32_t;
|
||||
typedef float2 fp32_t2;
|
||||
typedef float3 fp32_t3;
|
||||
typedef float4 fp32_t4;
|
||||
|
||||
#if 0 == USE_FP16
|
||||
typedef float fp16_t;
|
||||
typedef float2 fp16_t2;
|
||||
typedef float3 fp16_t3;
|
||||
typedef float4 fp16_t4;
|
||||
|
||||
typedef int i16_t;
|
||||
typedef int2 i16_t2;
|
||||
typedef int3 i16_t3;
|
||||
typedef int4 i16_t4;
|
||||
|
||||
typedef uint ui16_t;
|
||||
typedef uint2 ui16_t2;
|
||||
typedef uint3 ui16_t3;
|
||||
typedef uint4 ui16_t4;
|
||||
#else
|
||||
typedef float16_t fp16_t;
|
||||
typedef float16_t2 fp16_t2;
|
||||
typedef float16_t3 fp16_t3;
|
||||
typedef float16_t4 fp16_t4;
|
||||
|
||||
typedef int16_t i16_t;
|
||||
typedef int16_t2 i16_t2;
|
||||
typedef int16_t3 i16_t3;
|
||||
typedef int16_t4 i16_t4;
|
||||
|
||||
typedef uint16_t ui16_t;
|
||||
typedef uint16_t2 ui16_t2;
|
||||
typedef uint16_t3 ui16_t3;
|
||||
typedef uint16_t4 ui16_t4;
|
||||
#endif
|
||||
|
||||
// this is all that the effect requires
|
||||
struct TAAParams
|
||||
{
|
||||
FTAAResolve CBData;
|
||||
|
||||
// in current MiniEngine's format
|
||||
Texture2D<fp16_t3> VelocityBuffer;
|
||||
|
||||
// Current colour buffer - rgb used
|
||||
Texture2D<fp16_t3> ColourTexture;
|
||||
|
||||
// Stored temporal antialiased pixel - .a should be sufficient enough to handle weight stored as float [0.5f, 1.f)
|
||||
Texture2D<fp32_t4> HistoryTexture;
|
||||
|
||||
// Current linear depth buffer - used only when USE_DEPTH_THRESHOLD is set
|
||||
Texture2D<fp16_t> DepthBuffer;
|
||||
|
||||
// Previous linear frame depth buffer - used only when USE_DEPTH_THRESHOLD is set
|
||||
Texture2D<fp16_t> PrvDepthBuffer;
|
||||
|
||||
// Antialiased colour buffer (used in a next frame as the HistoryTexture)
|
||||
RWTexture2D<fp16_t4> OutTexture;
|
||||
|
||||
// Samplers
|
||||
SamplerState MinMagLinearMipPointClamp;
|
||||
SamplerState MinMagMipPointClamp;
|
||||
};
|
||||
|
||||
#endif // #ifndef __cplusplus
|
||||
|
||||
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // namespace
|
||||
#endif // #ifdef __cplusplus
|
||||
|
||||
#endif // #ifndef __INTEL_TAA_H__
|
||||
263
manul/renderer/source/XeGTAO.h
Normal file
263
manul/renderer/source/XeGTAO.h
Normal file
@@ -0,0 +1,263 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2016-2021, Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// XeGTAO is based on GTAO/GTSO "Jimenez et al. / Practical Real-Time Strategies for Accurate Indirect Occlusion",
|
||||
// https://www.activision.com/cdn/research/Practical_Real_Time_Strategies_for_Accurate_Indirect_Occlusion_NEW%20VERSION_COLOR.pdf
|
||||
//
|
||||
// Implementation: Filip Strugar (filip.strugar@intel.com), Steve Mccalla <stephen.mccalla@intel.com> (\_/)
|
||||
// Version: 1.02 (='.'=)
|
||||
// Details: https://github.com/GameTechDev/XeGTAO (")_(")
|
||||
//
|
||||
// Version history:
|
||||
// 1.00 (2021-08-09): Initial release
|
||||
// 1.01 (2021-09-02): Fix for depth going to inf for 'far' depth buffer values that are out of fp16 range
|
||||
// 1.02 (2021-09-03): More fast_acos use and made final horizon cos clamping optional (off by default): 3-4% perf boost
|
||||
// 1.10 (2021-09-03): Added a couple of heuristics to combat over-darkening errors in certain scenarios
|
||||
// 1.20 (2021-09-06): Optional normal from depth generation is now a standalone pass: no longer integrated into
|
||||
// main XeGTAO pass to reduce complexity and allow reuse; also quality of generated normals improved
|
||||
// 1.21 (2021-09-28): Replaced 'groupshared'-based denoiser with a slightly slower multi-pass one where a 2-pass new
|
||||
// equals 1-pass old. However, 1-pass new is faster than the 1-pass old and enough when TAA enabled.
|
||||
// 1.22 (2021-09-28): Added 'XeGTAO_' prefix to all local functions to avoid name clashes with various user codebases.
|
||||
// 1.30 (2021-10-10): Added support for directional component (bent normals).
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __XE_GTAO_TYPES_H__
|
||||
#define __XE_GTAO_TYPES_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
#include <cmath>
|
||||
|
||||
namespace XeGTAO
|
||||
{
|
||||
|
||||
// cpp<->hlsl mapping
|
||||
struct Matrix4x4 { float m[16]; };
|
||||
struct Vector3 { float x,y,z; };
|
||||
struct Vector2 { float x,y; };
|
||||
struct Vector2i { int x,y; };
|
||||
typedef unsigned int uint;
|
||||
|
||||
#else // #ifdef __cplusplus
|
||||
|
||||
// cpp<->hlsl mapping
|
||||
#define Matrix4x4 float4x4
|
||||
#define Vector3 float3
|
||||
#define Vector2 float2
|
||||
#define Vector2i int2
|
||||
|
||||
#endif
|
||||
|
||||
// Global consts that need to be visible from both shader and cpp side
|
||||
#define XE_GTAO_DEPTH_MIP_LEVELS 5 // this one is hard-coded to 5 for now
|
||||
#define XE_GTAO_NUMTHREADS_X 8 // these can be changed
|
||||
#define XE_GTAO_NUMTHREADS_Y 8 // these can be changed
|
||||
|
||||
struct GTAOConstants
|
||||
{
|
||||
Vector2i ViewportSize;
|
||||
Vector2 ViewportPixelSize; // .zw == 1.0 / ViewportSize.xy
|
||||
|
||||
Vector2 DepthUnpackConsts;
|
||||
Vector2 CameraTanHalfFOV;
|
||||
|
||||
Vector2 NDCToViewMul;
|
||||
Vector2 NDCToViewAdd;
|
||||
|
||||
Vector2 NDCToViewMul_x_PixelSize;
|
||||
float EffectRadius; // world (viewspace) maximum size of the shadow
|
||||
float EffectFalloffRange;
|
||||
|
||||
float RadiusMultiplier;
|
||||
float Padding0;
|
||||
float FinalValuePower;
|
||||
float DenoiseBlurBeta;
|
||||
|
||||
float SampleDistributionPower;
|
||||
float ThinOccluderCompensation;
|
||||
float DepthMIPSamplingOffset;
|
||||
int NoiseIndex; // frameIndex % 64 if using TAA or 0 otherwise
|
||||
};
|
||||
|
||||
// This is used only for the development (ray traced ground truth).
|
||||
struct ReferenceRTAOConstants
|
||||
{
|
||||
float TotalRaysLength ; // similar to Radius from GTAO
|
||||
float Albedo ; // the assumption on the average material albedo
|
||||
int MaxBounces ; // how many rays to recurse before stopping
|
||||
int AccumulatedFrames ; // how many frames have we accumulated so far (after resetting/clearing). If 0 - this is the first.
|
||||
int AccumulateFrameMax ; // how many frames are we aiming to accumulate; stop when we hit!
|
||||
int Padding0;
|
||||
int Padding1;
|
||||
int Padding2;
|
||||
#ifdef __cplusplus
|
||||
ReferenceRTAOConstants( ) { TotalRaysLength = 1.0f; Albedo = 0.0f; MaxBounces = 1; AccumulatedFrames = 0; AccumulateFrameMax = 0; }
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef XE_GTAO_USE_DEFAULT_CONSTANTS
|
||||
#define XE_GTAO_USE_DEFAULT_CONSTANTS 1
|
||||
#endif
|
||||
|
||||
// some constants reduce performance if provided as dynamic values; if these constants are not required to be dynamic and they match default values,
|
||||
// set XE_GTAO_USE_DEFAULT_CONSTANTS and the code will compile into a more efficient shader
|
||||
#define XE_GTAO_DEFAULT_RADIUS_MULTIPLIER (1.457f ) // allows us to use different value as compared to ground truth radius to counter inherent screen space biases
|
||||
#define XE_GTAO_DEFAULT_FALLOFF_RANGE (0.615f ) // distant samples contribute less
|
||||
#define XE_GTAO_DEFAULT_SAMPLE_DISTRIBUTION_POWER (2.0f ) // small crevices more important than big surfaces
|
||||
#define XE_GTAO_DEFAULT_THIN_OCCLUDER_COMPENSATION (0.0f ) // the new 'thickness heuristic' approach
|
||||
#define XE_GTAO_DEFAULT_FINAL_VALUE_POWER (2.2f ) // modifies the final ambient occlusion value using power function - this allows some of the above heuristics to do different things
|
||||
#define XE_GTAO_DEFAULT_DEPTH_MIP_SAMPLING_OFFSET (3.30f ) // main trade-off between performance (memory bandwidth) and quality (temporal stability is the first affected, thin objects next)
|
||||
|
||||
#define XE_GTAO_OCCLUSION_TERM_SCALE (1.5f) // for packing in UNORM (because raw, pre-denoised occlusion term can overshoot 1 but will later average out to 1)
|
||||
|
||||
// From https://www.shadertoy.com/view/3tB3z3 - except we're using R2 here
|
||||
#define XE_HILBERT_LEVEL 6U
|
||||
#define XE_HILBERT_WIDTH ( (1U << XE_HILBERT_LEVEL) )
|
||||
#define XE_HILBERT_AREA ( XE_HILBERT_WIDTH * XE_HILBERT_WIDTH )
|
||||
inline uint HilbertIndex( uint posX, uint posY )
|
||||
{
|
||||
uint index = 0U;
|
||||
for( uint curLevel = XE_HILBERT_WIDTH/2U; curLevel > 0U; curLevel /= 2U )
|
||||
{
|
||||
uint regionX = ( posX & curLevel ) > 0U;
|
||||
uint regionY = ( posY & curLevel ) > 0U;
|
||||
index += curLevel * curLevel * ( (3U * regionX) ^ regionY);
|
||||
if( regionY == 0U )
|
||||
{
|
||||
if( regionX == 1U )
|
||||
{
|
||||
posX = uint( (XE_HILBERT_WIDTH - 1U) ) - posX;
|
||||
posY = uint( (XE_HILBERT_WIDTH - 1U) ) - posY;
|
||||
}
|
||||
|
||||
uint temp = posX;
|
||||
posX = posY;
|
||||
posY = temp;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
||||
struct GTAOSettings
|
||||
{
|
||||
int QualityLevel = 2; // 0: low; 1: medium; 2: high; 3: ultra
|
||||
int DenoisePasses = 1; // 0: disabled; 1: sharp; 2: medium; 3: soft
|
||||
float Radius = 0.5f; // [0.0, ~ ] World (view) space size of the occlusion sphere.
|
||||
|
||||
// auto-tune-d settings
|
||||
float RadiusMultiplier = XE_GTAO_DEFAULT_RADIUS_MULTIPLIER;
|
||||
float FalloffRange = XE_GTAO_DEFAULT_FALLOFF_RANGE;
|
||||
float SampleDistributionPower = XE_GTAO_DEFAULT_SAMPLE_DISTRIBUTION_POWER;
|
||||
float ThinOccluderCompensation = XE_GTAO_DEFAULT_THIN_OCCLUDER_COMPENSATION;
|
||||
float FinalValuePower = XE_GTAO_DEFAULT_FINAL_VALUE_POWER;
|
||||
float DepthMIPSamplingOffset = XE_GTAO_DEFAULT_DEPTH_MIP_SAMPLING_OFFSET;
|
||||
};
|
||||
|
||||
template<class T> inline T clamp( T const & v, T const & min, T const & max ) { assert( max >= min ); if( v < min ) return min; if( v > max ) return max; return v; }
|
||||
|
||||
// If using TAA then set noiseIndex to frameIndex % 64 - otherwise use 0
|
||||
inline void GTAOUpdateConstants( XeGTAO::GTAOConstants& consts, int viewportWidth, int viewportHeight, const XeGTAO::GTAOSettings & settings, const float projMatrix[16], bool rowMajor, unsigned int frameCounter )
|
||||
{
|
||||
consts.ViewportSize = { viewportWidth, viewportHeight };
|
||||
consts.ViewportPixelSize = { 1.0f / (float)viewportWidth, 1.0f / (float)viewportHeight };
|
||||
|
||||
float depthLinearizeMul = (rowMajor)?(-projMatrix[3 * 4 + 2]):(-projMatrix[3 + 2 * 4]); // float depthLinearizeMul = ( clipFar * clipNear ) / ( clipFar - clipNear );
|
||||
float depthLinearizeAdd = (rowMajor)?( projMatrix[2 * 4 + 2]):( projMatrix[2 + 2 * 4]); // float depthLinearizeAdd = clipFar / ( clipFar - clipNear );
|
||||
|
||||
// correct the handedness issue. need to make sure this below is correct, but I think it is.
|
||||
if( depthLinearizeMul * depthLinearizeAdd < 0 )
|
||||
depthLinearizeAdd = -depthLinearizeAdd;
|
||||
consts.DepthUnpackConsts = { -depthLinearizeMul, depthLinearizeAdd };
|
||||
|
||||
float tanHalfFOVY = 1.0f / ((rowMajor)?(projMatrix[1 * 4 + 1]):(projMatrix[1 + 1 * 4])); // = tanf( drawContext.Camera.GetYFOV( ) * 0.5f );
|
||||
float tanHalfFOVX = 1.0F / ((rowMajor)?(projMatrix[0 * 4 + 0]):(projMatrix[0 + 0 * 4])); // = tanHalfFOVY * drawContext.Camera.GetAspect( );
|
||||
consts.CameraTanHalfFOV = { tanHalfFOVX, tanHalfFOVY };
|
||||
|
||||
consts.NDCToViewMul = { consts.CameraTanHalfFOV.x * 2.0f, consts.CameraTanHalfFOV.y * -2.0f };
|
||||
consts.NDCToViewAdd = { consts.CameraTanHalfFOV.x * -1.0f, consts.CameraTanHalfFOV.y * 1.0f };
|
||||
|
||||
consts.NDCToViewMul_x_PixelSize = { consts.NDCToViewMul.x * consts.ViewportPixelSize.x, consts.NDCToViewMul.y * consts.ViewportPixelSize.y };
|
||||
|
||||
consts.EffectRadius = settings.Radius;
|
||||
|
||||
consts.EffectFalloffRange = settings.FalloffRange;
|
||||
consts.DenoiseBlurBeta = (settings.DenoisePasses==0)?(1e4f):(1.2f); // high value disables denoise - more elegant & correct way would be do set all edges to 0
|
||||
|
||||
consts.RadiusMultiplier = settings.RadiusMultiplier;
|
||||
consts.SampleDistributionPower = settings.SampleDistributionPower;
|
||||
consts.ThinOccluderCompensation = settings.ThinOccluderCompensation;
|
||||
consts.FinalValuePower = settings.FinalValuePower;
|
||||
consts.DepthMIPSamplingOffset = settings.DepthMIPSamplingOffset;
|
||||
consts.NoiseIndex = (settings.DenoisePasses>0)?(frameCounter % 64):(0);
|
||||
consts.Padding0 = 0;
|
||||
}
|
||||
|
||||
#ifdef IMGUI_API
|
||||
inline bool GTAOImGuiSettings( XeGTAO::GTAOSettings & settings )
|
||||
{
|
||||
bool hadChanges = false;
|
||||
|
||||
ImGui::PushItemWidth( 120.0f );
|
||||
|
||||
ImGui::Text( "Performance/quality settings:" );
|
||||
|
||||
ImGui::Combo( "Quality Level", &settings.QualityLevel, "Low\0Medium\0High\0Ultra\00");
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "Higher quality settings use more samples per pixel but are slower" );
|
||||
settings.QualityLevel = clamp( settings.QualityLevel , 0, 3 );
|
||||
|
||||
ImGui::Combo( "Denoising level", &settings.DenoisePasses, "Disabled\0Sharp\0Medium\0Soft\00");
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "The amount of edge-aware spatial denoise applied" );
|
||||
settings.DenoisePasses = clamp( settings.DenoisePasses , 0, 3 );
|
||||
|
||||
ImGui::Text( "Visual settings:" );
|
||||
|
||||
settings.Radius = clamp( settings.Radius, 0.0f, 100000.0f );
|
||||
|
||||
hadChanges |= ImGui::InputFloat( "Effect radius", &settings.Radius , 0.05f, 0.0f, "%.2f" );
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "World (viewspace) effect radius\nExpected range: depends on the scene & requirements, anything from 0.01 to 1000+" );
|
||||
settings.Radius = clamp( settings.Radius , 0.0f, 10000.0f );
|
||||
|
||||
if( ImGui::CollapsingHeader( "Auto-tuned settings (heuristics)" ) )
|
||||
{
|
||||
hadChanges |= ImGui::InputFloat( "Radius multiplier", &settings.RadiusMultiplier , 0.05f, 0.0f, "%.2f" );
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "Multiplies the 'Effect Radius' - used by the auto-tune to best match raytraced ground truth\nExpected range: [0.3, 3.0], defaults to %.3f", XE_GTAO_DEFAULT_RADIUS_MULTIPLIER );
|
||||
settings.RadiusMultiplier = clamp( settings.RadiusMultiplier , 0.3f, 3.0f );
|
||||
|
||||
hadChanges |= ImGui::InputFloat( "Falloff range", &settings.FalloffRange , 0.05f, 0.0f, "%.2f" );
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "Gently reduce sample impact as it gets out of 'Effect radius' bounds\nExpected range: [0.0, 1.0], defaults to %.3f", XE_GTAO_DEFAULT_FALLOFF_RANGE );
|
||||
settings.FalloffRange = clamp( settings.FalloffRange , 0.0f, 1.0f );
|
||||
|
||||
hadChanges |= ImGui::InputFloat( "Sample distribution power", &settings.SampleDistributionPower , 0.05f, 0.0f, "%.2f" );
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "Make samples on a slice equally distributed (1.0) or focus more towards the center (>1.0)\nExpected range: [1.0, 3.0], 2defaults to %.3f", XE_GTAO_DEFAULT_SAMPLE_DISTRIBUTION_POWER );
|
||||
settings.SampleDistributionPower = clamp( settings.SampleDistributionPower , 1.0f, 3.0f );
|
||||
|
||||
hadChanges |= ImGui::InputFloat( "Thin occluder compensation", &settings.ThinOccluderCompensation, 0.05f, 0.0f, "%.2f" );
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "Slightly reduce impact of samples further back to counter the bias from depth-based (incomplete) input scene geometry data\nExpected range: [0.0, 0.7], defaults to %.3f", XE_GTAO_DEFAULT_THIN_OCCLUDER_COMPENSATION );
|
||||
settings.ThinOccluderCompensation = clamp( settings.ThinOccluderCompensation , 0.0f, 0.7f );
|
||||
|
||||
hadChanges |= ImGui::InputFloat( "Final power", &settings.FinalValuePower, 0.05f, 0.0f, "%.2f" );
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "Applies power function to the final value: occlusion = pow( occlusion, finalPower )\nExpected range: [0.5, 5.0], defaults to %.3f", XE_GTAO_DEFAULT_FINAL_VALUE_POWER );
|
||||
settings.FinalValuePower = clamp( settings.FinalValuePower , 0.5f, 5.0f );
|
||||
|
||||
hadChanges |= ImGui::InputFloat( "Depth MIP sampling offset", &settings.DepthMIPSamplingOffset, 0.05f, 0.0f, "%.2f" );
|
||||
if( ImGui::IsItemHovered( ) ) ImGui::SetTooltip( "Mainly performance (texture memory bandwidth) setting but as a side-effect reduces overshadowing by thin objects and increases temporal instability\nExpected range: [2.0, 6.0], defaults to %.3f", XE_GTAO_DEFAULT_DEPTH_MIP_SAMPLING_OFFSET );
|
||||
settings.DepthMIPSamplingOffset = clamp( settings.DepthMIPSamplingOffset , 0.0f, 30.0f );
|
||||
}
|
||||
|
||||
ImGui::PopItemWidth( );
|
||||
|
||||
return hadChanges;
|
||||
}
|
||||
#endif // IMGUI_API
|
||||
|
||||
} // close the namespace
|
||||
|
||||
#endif // #ifdef __cplusplus
|
||||
|
||||
|
||||
#endif // __XE_GTAO_TYPES_H__
|
||||
113
manul/renderer/source/auto_exposure.cpp
Normal file
113
manul/renderer/source/auto_exposure.cpp
Normal file
@@ -0,0 +1,113 @@
|
||||
#include "auto_exposure.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
MaAutoExposure::MaAutoExposure(NvRenderer *renderer)
|
||||
: MaResourceRegistry(renderer), m_backend(renderer->GetBackend()) {}
|
||||
|
||||
void MaAutoExposure::Render(nvrhi::ICommandList *command_list) {
|
||||
PushConstantsAutoExposure push_constants{};
|
||||
push_constants.m_delta_time = .01f;
|
||||
push_constants.m_num_mips = m_num_mips;
|
||||
push_constants.m_num_workgroups =
|
||||
((m_width + 63) / 64) * ((m_height + 64) / 64);
|
||||
push_constants.m_min_luminance_ev =
|
||||
NvRenderer::Config()->m_lighting.m_min_luminance_ev;
|
||||
push_constants.m_max_luminance_ev =
|
||||
NvRenderer::Config()->m_lighting.m_max_luminance_ev;
|
||||
command_list->setComputeState(nvrhi::ComputeState()
|
||||
.addBindingSet(m_bindings_auto_exposure)
|
||||
.setPipeline(m_pso_auto_exposure));
|
||||
command_list->setPushConstants(&push_constants, sizeof(push_constants));
|
||||
command_list->dispatch((m_width + 63) / 64, (m_height + 64) / 64, 1);
|
||||
|
||||
command_list->setComputeState(
|
||||
nvrhi::ComputeState()
|
||||
.addBindingSet(m_bindings_auto_exposure_apply)
|
||||
.setPipeline(m_pso_auto_exposure_apply));
|
||||
command_list->dispatch((m_width + 7) / 8, (m_height + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void MaAutoExposure::Init() {
|
||||
nvrhi::TextureHandle input_texture = dynamic_cast<nvrhi::ITexture *>(
|
||||
GetResource("scene_lit_texture", nvrhi::ResourceType::Texture_SRV)
|
||||
.m_resource);
|
||||
|
||||
auto desc = input_texture->getDesc();
|
||||
m_width = desc.width;
|
||||
m_height = desc.height;
|
||||
m_num_mips =
|
||||
glm::floor(glm::log2(static_cast<float>(glm::max(m_width, m_height))));
|
||||
|
||||
m_6th_mip_img = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setFormat(nvrhi::Format::R32_FLOAT)
|
||||
.setWidth(m_width >> 6)
|
||||
.setHeight(m_height >> 6)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Auto Exposure 6th Mip"));
|
||||
|
||||
m_output_exposure_fsr2 = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setFormat(nvrhi::Format::RG16_FLOAT)
|
||||
.setWidth(1)
|
||||
.setHeight(1)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Auto Exposure Output (FSR2)"));
|
||||
|
||||
m_atomic_counter = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc()
|
||||
.setByteSize(sizeof(uint32_t))
|
||||
.setStructStride(sizeof(uint32_t))
|
||||
.setCanHaveUAVs(true)
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Auto Exposure Atomic Counter"));
|
||||
|
||||
auto cs_auto_exposure = m_backend->CreateShader(
|
||||
"autoexp_compute_avg_luminance", nvrhi::ShaderType::Compute);
|
||||
|
||||
nvrhi::BindingLayoutHandle binding_layout;
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::PushConstants(
|
||||
1, sizeof(PushConstantsAutoExposure)))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(0, input_texture))
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::Texture_UAV(0, m_output_exposure_fsr2))
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::StructuredBuffer_UAV(2, m_atomic_counter))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(3, m_6th_mip_img)),
|
||||
binding_layout, m_bindings_auto_exposure);
|
||||
|
||||
m_pso_auto_exposure = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.addBindingLayout(binding_layout)
|
||||
.setComputeShader(cs_auto_exposure));
|
||||
|
||||
auto cs_auto_exposure_apply =
|
||||
m_backend->CreateShader("autoexp_apply", nvrhi::ShaderType::Compute);
|
||||
|
||||
nvrhi::BindingLayoutHandle binding_layout_apply;
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::Texture_SRV(0, m_output_exposure_fsr2))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(0, input_texture)),
|
||||
binding_layout_apply, m_bindings_auto_exposure_apply);
|
||||
|
||||
m_pso_auto_exposure_apply = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.addBindingLayout(binding_layout_apply)
|
||||
.setComputeShader(cs_auto_exposure_apply));
|
||||
}
|
||||
39
manul/renderer/source/auto_exposure.h
Normal file
39
manul/renderer/source/auto_exposure.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include "nvrenderer/resource_registry.h"
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
class NvRenderer;
|
||||
class NvRendererBackend;
|
||||
|
||||
struct MaAutoExposure : public MaResourceRegistry {
|
||||
MaAutoExposure(NvRenderer* renderer);
|
||||
|
||||
void Init();
|
||||
void Render(nvrhi::ICommandList* command_list);
|
||||
|
||||
uint32_t m_width;
|
||||
uint32_t m_height;
|
||||
uint32_t m_num_mips;
|
||||
|
||||
struct PushConstantsAutoExposure {
|
||||
uint32_t m_num_mips;
|
||||
uint32_t m_num_workgroups;
|
||||
float m_delta_time;
|
||||
float m_min_luminance_ev;
|
||||
float m_max_luminance_ev;
|
||||
};
|
||||
|
||||
NvRendererBackend* m_backend;
|
||||
|
||||
nvrhi::TextureHandle m_output_exposure_fsr2;
|
||||
nvrhi::TextureHandle m_6th_mip_img;
|
||||
nvrhi::BufferHandle m_atomic_counter;
|
||||
|
||||
nvrhi::BindingSetHandle m_bindings_auto_exposure;
|
||||
nvrhi::ComputePipelineHandle m_pso_auto_exposure;
|
||||
|
||||
nvrhi::BindingSetHandle m_bindings_auto_exposure_apply;
|
||||
nvrhi::ComputePipelineHandle m_pso_auto_exposure_apply;
|
||||
};
|
||||
178
manul/renderer/source/bloom.cpp
Normal file
178
manul/renderer/source/bloom.cpp
Normal file
@@ -0,0 +1,178 @@
|
||||
#include "bloom.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
void Bloom::UpdateConstants(nvrhi::ICommandList* command_list) {
|
||||
BloomConstants constants{};
|
||||
constants.m_prefilter_vector =
|
||||
glm::vec4{m_threshold, m_threshold - m_knee, m_knee * 2.f, .25f / m_knee};
|
||||
constants.m_mix_factor = m_mix_factor;
|
||||
command_list->writeBuffer(m_constant_buffer, &constants, sizeof(constants));
|
||||
}
|
||||
|
||||
void Bloom::OnGui() {
|
||||
if (!m_gui_active) return;
|
||||
if (ImGui::Begin("Bloom settings", &m_gui_active,
|
||||
ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::SliderFloat("Threshold", &m_threshold, 0.f, 100.f);
|
||||
ImGui::SliderFloat("Knee", &m_knee, 0.f, 100.f);
|
||||
ImGui::SliderFloat("Mix Factor", &m_mix_factor, 0.f, 100.f);
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void Bloom::ShowGui() { m_gui_active = true; }
|
||||
|
||||
void Bloom::Init(nvrhi::ITexture* texture) {
|
||||
auto source_desc = texture->getDesc();
|
||||
|
||||
int mip_count = 7;
|
||||
m_working_texture = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setWidth(source_desc.width)
|
||||
.setHeight(source_desc.height)
|
||||
.setFormat(nvrhi::Format::RGBA16_FLOAT)
|
||||
.setMipLevels(mip_count)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_constant_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc(sizeof(BloomConstants),
|
||||
"Bloom Constants", 16)
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
auto shader_prefilter =
|
||||
m_backend->CreateShader("bloom_prefilter", nvrhi::ShaderType::Compute);
|
||||
auto shader_downsample =
|
||||
m_backend->CreateShader("bloom_downsample", nvrhi::ShaderType::Compute);
|
||||
auto shader_upsample =
|
||||
m_backend->CreateShader("bloom_upsample", nvrhi::ShaderType::Compute);
|
||||
auto shader_final =
|
||||
m_backend->CreateShader("bloom_apply", nvrhi::ShaderType::Compute);
|
||||
auto binding_layout = m_backend->GetDevice()->createBindingLayout(
|
||||
nvrhi::BindingLayoutDesc()
|
||||
.setVisibility(nvrhi::ShaderType::Compute)
|
||||
.addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_UAV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0)));
|
||||
auto binding_layout_final = m_backend->GetDevice()->createBindingLayout(
|
||||
nvrhi::BindingLayoutDesc()
|
||||
.setVisibility(nvrhi::ShaderType::Compute)
|
||||
.addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(1))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_UAV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0)));
|
||||
auto pso_prefilter = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.setComputeShader(shader_prefilter)
|
||||
.addBindingLayout(binding_layout));
|
||||
auto pso_downsample = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.setComputeShader(shader_downsample)
|
||||
.addBindingLayout(binding_layout));
|
||||
auto pso_upsample = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.setComputeShader(shader_upsample)
|
||||
.addBindingLayout(binding_layout));
|
||||
auto pso_final = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.setComputeShader(shader_final)
|
||||
.addBindingLayout(binding_layout_final));
|
||||
auto sampler_linear_clamp = m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc().setAllFilters(true).setAllAddressModes(
|
||||
nvrhi::SamplerAddressMode::ClampToEdge));
|
||||
{
|
||||
auto& stage = m_stages.emplace_back();
|
||||
stage.m_width = source_desc.width;
|
||||
stage.m_height = source_desc.height;
|
||||
stage.m_pso = pso_prefilter;
|
||||
stage.m_binding_set = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
0, texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(0, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
0, m_working_texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(0, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(0, sampler_linear_clamp)),
|
||||
binding_layout);
|
||||
}
|
||||
for (int i = 1; i < mip_count; ++i) {
|
||||
auto& stage = m_stages.emplace_back();
|
||||
stage.m_width = glm::max(1u, source_desc.width >> i);
|
||||
stage.m_height = glm::max(1u, source_desc.height >> i);
|
||||
stage.m_pso = pso_downsample;
|
||||
stage.m_binding_set = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
0, m_working_texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(glm::max(0, i - 1), 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
0, m_working_texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(i, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(0, sampler_linear_clamp)),
|
||||
binding_layout);
|
||||
}
|
||||
for (int i = mip_count - 2; i >= 1; --i) {
|
||||
auto& stage = m_stages.emplace_back();
|
||||
stage.m_width = glm::max(1u, source_desc.width >> i);
|
||||
stage.m_height = glm::max(1u, source_desc.height >> i);
|
||||
stage.m_pso = pso_upsample;
|
||||
stage.m_binding_set = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
0, m_working_texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(i + 1, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
0, m_working_texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(i, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(0, sampler_linear_clamp)),
|
||||
binding_layout);
|
||||
}
|
||||
{
|
||||
auto& stage = m_stages.emplace_back();
|
||||
stage.m_width = source_desc.width;
|
||||
stage.m_height = source_desc.height;
|
||||
stage.m_pso = pso_final;
|
||||
stage.m_binding_set = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
0, m_working_texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(1, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
1, texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(0, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
0, m_working_texture, nvrhi::Format::UNKNOWN,
|
||||
nvrhi::TextureSubresourceSet(0, 1, 0, 1)))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(0, sampler_linear_clamp)),
|
||||
binding_layout_final);
|
||||
}
|
||||
}
|
||||
|
||||
void Bloom::Render(nvrhi::ICommandList* command_list) {
|
||||
command_list->beginMarker("Bloom");
|
||||
UpdateConstants(command_list);
|
||||
for (const auto& stage : m_stages) {
|
||||
command_list->setComputeState(nvrhi::ComputeState()
|
||||
.setPipeline(stage.m_pso)
|
||||
.addBindingSet(stage.m_binding_set));
|
||||
command_list->dispatch((stage.m_width + 7) / 8,
|
||||
(stage.m_height + 7) / 8, 1);
|
||||
}
|
||||
command_list->endMarker();
|
||||
}
|
||||
36
manul/renderer/source/bloom.h
Normal file
36
manul/renderer/source/bloom.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
struct Bloom {
|
||||
struct BloomConstants {
|
||||
glm::vec4 m_prefilter_vector;
|
||||
float m_mix_factor;
|
||||
};
|
||||
float m_threshold = 3.f;
|
||||
float m_knee = .6f;
|
||||
float m_mix_factor = .04f;
|
||||
bool m_gui_active = false;
|
||||
void UpdateConstants(nvrhi::ICommandList* command_list);
|
||||
void OnGui();
|
||||
void ShowGui();
|
||||
Bloom(class NvRendererBackend* backend) : m_backend(backend) {}
|
||||
|
||||
void Init(nvrhi::ITexture* texture);
|
||||
void Render(nvrhi::ICommandList* command_list);
|
||||
|
||||
nvrhi::TextureHandle m_working_texture;
|
||||
nvrhi::BufferHandle m_constant_buffer;
|
||||
|
||||
struct BloomStage {
|
||||
int m_width;
|
||||
int m_height;
|
||||
nvrhi::BindingSetHandle m_binding_set;
|
||||
nvrhi::ComputePipelineHandle m_pso;
|
||||
};
|
||||
|
||||
std::vector<BloomStage> m_stages;
|
||||
|
||||
class NvRendererBackend* m_backend;
|
||||
};
|
||||
54
manul/renderer/source/config.cpp
Normal file
54
manul/renderer/source/config.cpp
Normal file
@@ -0,0 +1,54 @@
|
||||
#include "config.h"
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
void MaConfig::Init(const std::filesystem::path& config_file) {
|
||||
Init(YAML::LoadFile(config_file.generic_string()));
|
||||
}
|
||||
|
||||
void MaConfig::Init(const YAML::Node& node) {
|
||||
m_display.Init(node["display"]);
|
||||
m_shadow.Init(node["shadows"]);
|
||||
m_lighting.Init(node["lighting"]);
|
||||
m_weight_lines = node["wire_diameter_lines"].as<float>(.01f);
|
||||
m_weight_tractions = node["wire_diameter_tractions"].as<float>(.005f);
|
||||
}
|
||||
|
||||
void MaConfig::MaConfigDisplay::Init(const YAML::Node& node) {
|
||||
m_hdr_configs[0].Init(node["hdr_config"]["sdr"]);
|
||||
m_hdr_configs[0].m_tonemap_function = MaTonemapType::Default_Srgb;
|
||||
m_hdr_configs[1].Init(node["hdr_config"]["hdr"]);
|
||||
m_hdr_configs[1].m_tonemap_function = MaTonemapType::Linear_Rec2020;
|
||||
m_adapter_index = node["adapter"].as<int>();
|
||||
m_output_index = node["output"].as<int>();
|
||||
m_disable_hdr = node["disable_hdr"].as<bool>(false);
|
||||
}
|
||||
|
||||
MaConfig::MaConfigDisplay::MaConfigHDR MaConfig::MaConfigDisplay::GetHDRConfig()
|
||||
const {
|
||||
auto renderer = dynamic_cast<NvRenderer*>(GfxRenderer.get());
|
||||
return GetHDRConfig(renderer ? renderer->GetBackend()->IsHDRDisplay()
|
||||
: false);
|
||||
}
|
||||
|
||||
void MaConfig::MaConfigDisplay::MaConfigHDR::Init(const YAML::Node& node) {
|
||||
m_scene_exposure = node["pre_tonemap_exposure"].as<float>();
|
||||
m_ui_nits = node["ui_nits"].as<float>();
|
||||
m_scene_nits = node["scene_nits"].as<float>();
|
||||
m_scene_gamma = node["scene_gamma"].as<float>();
|
||||
}
|
||||
|
||||
void MaConfig::MaConfigShadow::Init(const YAML::Node& node) {
|
||||
m_resolution = node["resolution"].as<int>();
|
||||
m_cascade_distances = node["cascades"].as<std::vector<double>>();
|
||||
}
|
||||
|
||||
void MaConfig::MaConfigLighting::Init(const YAML::Node& node) {
|
||||
m_max_lights_per_scene = node["max_lights_per_scene"].as<int>(2048);
|
||||
m_selfillum_multiplier = node["selfillum_factor"].as<float>(1.f);
|
||||
m_freespot_multiplier = node["freespot_factor"].as<float>(10.f);
|
||||
m_luminance_threshold = node["luminance_threshold"].as<float>(.01f);
|
||||
m_min_luminance_ev = node["min_luminance_ev"].as<float>(-3.f);
|
||||
m_max_luminance_ev = node["max_luminance_ev"].as<float>(3.f);
|
||||
}
|
||||
48
manul/renderer/source/config.h
Normal file
48
manul/renderer/source/config.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#pragma once
|
||||
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
struct MaConfig {
|
||||
enum MaTonemapType { Default_Srgb = 0, Linear_Rec2020 };
|
||||
void Init(const std::filesystem::path& config_file);
|
||||
void Init(const YAML::Node& node);
|
||||
struct MaConfigDisplay {
|
||||
void Init(const YAML::Node& node);
|
||||
struct MaConfigHDR {
|
||||
void Init(const YAML::Node& node);
|
||||
MaTonemapType m_tonemap_function;
|
||||
float m_ui_nits;
|
||||
float m_scene_nits;
|
||||
float m_scene_exposure;
|
||||
float m_scene_gamma;
|
||||
float GetMaxOutputNits() const {
|
||||
return std::max(m_ui_nits, m_scene_nits);
|
||||
}
|
||||
float GetMinOutputNits() const { return 1.e-3f; }
|
||||
};
|
||||
std::array<MaConfigHDR, 2> m_hdr_configs;
|
||||
int m_adapter_index;
|
||||
int m_output_index;
|
||||
bool m_disable_hdr = false;
|
||||
MaConfigHDR GetHDRConfig(bool is_hdr) const { return m_hdr_configs[is_hdr]; }
|
||||
MaConfigHDR GetHDRConfig() const;
|
||||
} m_display;
|
||||
struct MaConfigLighting{
|
||||
void Init(const YAML::Node& node);
|
||||
int m_max_lights_per_scene;
|
||||
float m_selfillum_multiplier;
|
||||
float m_freespot_multiplier;
|
||||
float m_luminance_threshold;
|
||||
float m_min_luminance_ev;
|
||||
float m_max_luminance_ev;
|
||||
} m_lighting;
|
||||
float m_weight_lines;
|
||||
float m_weight_tractions;
|
||||
struct MaConfigShadow {
|
||||
void Init(const YAML::Node& node);
|
||||
int m_resolution;
|
||||
std::vector<double> m_cascade_distances;
|
||||
} m_shadow;
|
||||
};
|
||||
76
manul/renderer/source/contactshadows.cpp
Normal file
76
manul/renderer/source/contactshadows.cpp
Normal file
@@ -0,0 +1,76 @@
|
||||
#include "contactshadows.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "gbuffer.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
MaContactShadows::MaContactShadows(NvRenderer* renderer, NvGbuffer* gbuffer)
|
||||
: m_backend(renderer->GetBackend()),
|
||||
m_gbuffer(gbuffer),
|
||||
m_width(0),
|
||||
m_height(0) {}
|
||||
|
||||
void MaContactShadows::Init() {
|
||||
m_width = m_gbuffer->m_gbuffer_depth->getDesc().width;
|
||||
m_height = m_gbuffer->m_gbuffer_depth->getDesc().height;
|
||||
m_compute_shader = m_backend->CreateShader("contact_shadows",
|
||||
nvrhi::ShaderType::Compute);
|
||||
m_constant_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateStaticConstantBufferDesc(sizeof(ComputeConstants),
|
||||
"Contact shadow constants")
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
m_output_texture = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setFormat(nvrhi::Format::R8_UNORM)
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::Texture_SRV(0, m_gbuffer->m_gbuffer_depth))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(0, m_output_texture))
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
0, m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllFilters(true)
|
||||
.setAllAddressModes(
|
||||
nvrhi::SamplerAddressMode::ClampToEdge)
|
||||
.setReductionType(
|
||||
nvrhi::SamplerReductionType::Maximum)))),
|
||||
m_binding_layout, m_binding_set);
|
||||
m_pipeline = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.setComputeShader(m_compute_shader)
|
||||
.addBindingLayout(m_binding_layout));
|
||||
}
|
||||
|
||||
void MaContactShadows::Render(nvrhi::ICommandList* command_list) {
|
||||
command_list->setComputeState(nvrhi::ComputeState()
|
||||
.setPipeline(m_pipeline)
|
||||
.addBindingSet(m_binding_set));
|
||||
command_list->dispatch((m_width + 7) / 8, (m_height + 7) / 8, 1);
|
||||
}
|
||||
|
||||
void MaContactShadows::UpdateConstants(nvrhi::ICommandList* command_list,
|
||||
const glm::dmat4& projection,
|
||||
const glm::dmat4& view,
|
||||
const glm::dvec3& light,
|
||||
uint64_t frame_index) {
|
||||
ComputeConstants constants{};
|
||||
constants.g_InverseProjection = glm::inverse(projection);
|
||||
constants.g_Projection = projection;
|
||||
constants.g_LightDirView = view * glm::dvec4(-light, 0.);
|
||||
constants.g_NumSamples = 16;
|
||||
constants.g_SampleRange = .1;
|
||||
constants.g_Thickness = .01;
|
||||
constants.g_FrameIndex = frame_index % 64;
|
||||
command_list->writeBuffer(m_constant_buffer, &constants, sizeof(constants));
|
||||
}
|
||||
36
manul/renderer/source/contactshadows.h
Normal file
36
manul/renderer/source/contactshadows.h
Normal file
@@ -0,0 +1,36 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
struct MaContactShadows {
|
||||
MaContactShadows(class NvRenderer* renderer, class NvGbuffer* gbuffer);
|
||||
void Init();
|
||||
void Render(nvrhi::ICommandList* command_list);
|
||||
void UpdateConstants(nvrhi::ICommandList* command_list,
|
||||
const glm::dmat4& projection, const glm::dmat4& view,
|
||||
const glm::dvec3& light, uint64_t frame_index);
|
||||
|
||||
struct ComputeConstants {
|
||||
glm::mat4 g_Projection;
|
||||
glm::mat4 g_InverseProjection;
|
||||
glm::vec3 g_LightDirView;
|
||||
float g_NumSamples;
|
||||
float g_SampleRange;
|
||||
float g_Thickness;
|
||||
uint32_t g_FrameIndex;
|
||||
};
|
||||
|
||||
nvrhi::BindingLayoutHandle m_binding_layout;
|
||||
nvrhi::BindingSetHandle m_binding_set;
|
||||
nvrhi::ComputePipelineHandle m_pipeline;
|
||||
nvrhi::ShaderHandle m_compute_shader;
|
||||
nvrhi::BufferHandle m_constant_buffer;
|
||||
|
||||
nvrhi::TextureHandle m_output_texture;
|
||||
|
||||
class NvRendererBackend* m_backend;
|
||||
class NvGbuffer* m_gbuffer;
|
||||
int m_width;
|
||||
int m_height;
|
||||
};
|
||||
37
manul/renderer/source/copypass.cpp
Normal file
37
manul/renderer/source/copypass.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "copypass.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
void CopyPass::Init() {
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::Pixel, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(0, m_source))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
0, m_backend->GetDevice()->createSampler(nvrhi::SamplerDesc()))),
|
||||
m_binding_layout, m_binding_set);
|
||||
m_pixel_shader = m_backend->CreateShader("copy", nvrhi::ShaderType::Pixel);
|
||||
m_framebuffer = m_backend->GetDevice()->createFramebuffer(
|
||||
nvrhi::FramebufferDesc().addColorAttachment(m_output));
|
||||
FullScreenPass::Init();
|
||||
}
|
||||
|
||||
void CopyPass::CreatePipelineDesc(nvrhi::GraphicsPipelineDesc& pipeline_desc) {
|
||||
FullScreenPass::CreatePipelineDesc(pipeline_desc);
|
||||
pipeline_desc.addBindingLayout(m_binding_layout);
|
||||
pipeline_desc.setPixelShader(m_pixel_shader);
|
||||
}
|
||||
|
||||
void CopyPass::Render(nvrhi::ICommandList* command_list) {
|
||||
nvrhi::GraphicsState graphics_state;
|
||||
InitState(graphics_state);
|
||||
graphics_state.addBindingSet(m_binding_set);
|
||||
command_list->setGraphicsState(graphics_state);
|
||||
Draw(command_list);
|
||||
}
|
||||
|
||||
nvrhi::IFramebuffer* CopyPass::GetFramebuffer() {
|
||||
return m_framebuffer;
|
||||
}
|
||||
28
manul/renderer/source/copypass.h
Normal file
28
manul/renderer/source/copypass.h
Normal file
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "fullscreenpass.h"
|
||||
|
||||
struct CopyPass : public FullScreenPass {
|
||||
CopyPass(class NvRendererBackend* backend, nvrhi::ITexture* source, nvrhi::ITexture* output)
|
||||
: FullScreenPass(backend),
|
||||
m_source(source), m_output(output) {}
|
||||
|
||||
virtual void Init() override;
|
||||
|
||||
virtual void CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) override;
|
||||
|
||||
virtual void Render(nvrhi::ICommandList* command_list) override;
|
||||
|
||||
virtual nvrhi::IFramebuffer* GetFramebuffer() override;
|
||||
|
||||
nvrhi::BindingLayoutHandle m_binding_layout;
|
||||
nvrhi::BindingSetHandle m_binding_set;
|
||||
nvrhi::ShaderHandle m_pixel_shader;
|
||||
nvrhi::FramebufferHandle m_framebuffer;
|
||||
|
||||
nvrhi::ITexture* m_source;
|
||||
nvrhi::ITexture* m_output;
|
||||
};
|
||||
188
manul/renderer/source/csm.cpp
Normal file
188
manul/renderer/source/csm.cpp
Normal file
@@ -0,0 +1,188 @@
|
||||
#include "csm.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
MaShadowMap::MaShadowMap(NvRenderer* renderer)
|
||||
: MaResourceRegistry(renderer), m_backend(renderer->m_backend.get()) {}
|
||||
|
||||
void MaShadowMap::Init() {
|
||||
InitResourceRegistry();
|
||||
const auto& shadow_config = NvRenderer::Config()->m_shadow;
|
||||
int num_cascades = shadow_config.m_cascade_distances.size();
|
||||
m_cascade_matrices.resize(num_cascades);
|
||||
m_cascade_matrices_clamped.resize(num_cascades);
|
||||
m_shadow_planes.resize(num_cascades + 1);
|
||||
m_far_plane_first = shadow_config.m_cascade_distances.front();
|
||||
m_far_plane_last = shadow_config.m_cascade_distances.back();
|
||||
m_projection_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateStaticConstantBufferDesc(
|
||||
sizeof(ShadowProjectionConstants), "Shadow projections")
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
m_inverse_projection_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateStaticConstantBufferDesc(
|
||||
sizeof(ShadowProjectionConstants), "Inverse shadow projections")
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
RegisterResource(true, "shadow_projection_buffer", m_projection_buffer,
|
||||
nvrhi::ResourceType::ConstantBuffer);
|
||||
}
|
||||
|
||||
void MaShadowMap::CalcCascades(const glm::dmat4& projection,
|
||||
const glm::dmat4& view,
|
||||
const glm::dvec3& light) {
|
||||
const auto& shadow_config = NvRenderer::Config()->m_shadow;
|
||||
|
||||
glm::dmat4 inverse_projection = glm::inverse(projection);
|
||||
glm::dmat4 inverse_view = glm::inverse(view);
|
||||
|
||||
double projection_near, projection_far;
|
||||
{
|
||||
glm::dvec4 ndc_near{0., 0., 0., 1.};
|
||||
glm::dvec4 ndc_far{0., 0., 1., 1.};
|
||||
ndc_near = inverse_projection * ndc_near;
|
||||
ndc_far = inverse_projection * ndc_far;
|
||||
|
||||
projection_near = -ndc_near.z / ndc_near.w;
|
||||
projection_far = -ndc_far.z / ndc_far.w;
|
||||
}
|
||||
|
||||
// Set near and far plane offset
|
||||
m_shadow_planes.front() = projection_near;
|
||||
for (int i = 1; i < shadow_config.m_cascade_distances.size(); ++i)
|
||||
m_shadow_planes[i] = shadow_config.m_cascade_distances[i];
|
||||
// m_shadow_planes.back() = std::min(m_far_plane_last, projection_far);
|
||||
// m_shadow_planes[1] = std::min(m_far_plane_first, m_shadow_planes.back());
|
||||
//
|
||||
//// Fill intermediate plane offsets
|
||||
// double base = m_shadow_planes.back() / m_shadow_planes[1];
|
||||
// double denom = 1. / (m_shadow_planes.size() - 2.);
|
||||
// for (int i = 2; i < m_shadow_planes.size() - 1; ++i) {
|
||||
// m_shadow_planes[i] = m_shadow_planes[1] * glm::pow(base, (i - 1) *
|
||||
// denom);
|
||||
// }
|
||||
|
||||
static std::vector<glm::dvec3> plane_corners;
|
||||
plane_corners.resize(4 * (m_shadow_planes.size()));
|
||||
|
||||
// for (int i = 0; i < m_shadow_planes.size(); ++i) {
|
||||
// glm::dvec3* plane = &plane_corners[i * 4];
|
||||
// GetViewPlaneCornersWorldSpace(projection, inverse_projection,
|
||||
// inverse_view,
|
||||
// m_shadow_planes[i], plane[0], plane[1],
|
||||
// plane[2], plane[3]);
|
||||
// }
|
||||
|
||||
glm::dvec3 up = glm::abs(light.y) > .999 ? glm::dvec3{0., 0., 1.}
|
||||
: glm::dvec3{0., 1., 0.};
|
||||
|
||||
for (int i = 0; i < m_cascade_matrices.size(); ++i) {
|
||||
glm::dvec3 plane[8];
|
||||
GetViewPlaneCornersWorldSpace(projection, inverse_projection, inverse_view,
|
||||
m_shadow_planes[i], true, plane[0], plane[1],
|
||||
plane[2], plane[3]);
|
||||
GetViewPlaneCornersWorldSpace(projection, inverse_projection, inverse_view,
|
||||
m_shadow_planes[i + 1], false, plane[4],
|
||||
plane[5], plane[6], plane[7]);
|
||||
|
||||
glm::dvec3 world_min{std::numeric_limits<double>::max()};
|
||||
glm::dvec3 world_max{-std::numeric_limits<double>::max()};
|
||||
double offset = 0.;
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
world_min = glm::min(world_min, plane[j]);
|
||||
world_max = glm::max(world_max, plane[j]);
|
||||
}
|
||||
|
||||
double actual_size = glm::max(glm::distance(plane[0], plane[7]),
|
||||
glm::distance(plane[4], plane[7]));
|
||||
|
||||
glm::dvec3 center = -Global.pCamera.Pos;
|
||||
|
||||
glm::dmat4 shadow_view = glm::lookAtRH(center, center - light, up);
|
||||
|
||||
glm::dvec3 min{std::numeric_limits<double>::max()};
|
||||
glm::dvec3 max{-std::numeric_limits<double>::max()};
|
||||
|
||||
double frustumchunkdepth =
|
||||
m_shadow_planes[i + 1] -
|
||||
(m_shadow_planes[i] > 1.f ? m_shadow_planes[i] : 0.f);
|
||||
double quantizationstep{glm::min(frustumchunkdepth, 50.)};
|
||||
|
||||
for (int j = 0; j < 8; ++j) {
|
||||
glm::dvec3 v = shadow_view * glm::dvec4(plane[j], 1.f);
|
||||
min = glm::min(min, v);
|
||||
max = glm::max(max, v);
|
||||
}
|
||||
|
||||
glm::dvec2 size = max - min;
|
||||
glm::dvec2 diff = static_cast<glm::dvec2>(actual_size) - size;
|
||||
max.xy += glm::max(diff * .5, 0.);
|
||||
min.xy -= glm::max(diff * .5, 0.);
|
||||
|
||||
glm::dvec2 pixel_size =
|
||||
static_cast<glm::dvec2>(actual_size / shadow_config.m_resolution);
|
||||
min.xy = glm::round(min.xy / pixel_size) * pixel_size;
|
||||
max.xy = glm::round(max.xy / pixel_size) * pixel_size;
|
||||
|
||||
// max = quantizationstep * glm::ceil(max / quantizationstep);
|
||||
// min = quantizationstep * glm::floor(min / quantizationstep);
|
||||
|
||||
glm::dmat4 shadow_proj = glm::orthoRH_ZO(min.x, max.x, min.y, max.y,
|
||||
-max.z - 500., -min.z + 500.);
|
||||
glm::dmat4 shadow_proj_clamped = glm::orthoRH_ZO(
|
||||
min.x, max.x, min.y, max.y, -max.z - 500., -min.z + 500.);
|
||||
|
||||
m_cascade_matrices[i] = shadow_proj * shadow_view;
|
||||
m_cascade_matrices_clamped[i] = shadow_proj_clamped * shadow_view;
|
||||
}
|
||||
}
|
||||
|
||||
void MaShadowMap::UpdateConstants(nvrhi::ICommandList* command_list) {
|
||||
{
|
||||
ShadowProjectionConstants constants{};
|
||||
for (int i = 0; i < std::min(m_cascade_matrices.size(),
|
||||
constants.m_shadow_projection.size());
|
||||
++i) {
|
||||
constants.m_shadow_projection[i] = m_cascade_matrices[i];
|
||||
constants.m_shadow_planes[i] =
|
||||
m_shadow_planes[i + 1] * m_shadow_planes[i + 1];
|
||||
}
|
||||
command_list->writeBuffer(m_projection_buffer, &constants,
|
||||
sizeof(constants));
|
||||
}
|
||||
}
|
||||
|
||||
void MaShadowMap::GetViewPlaneCornersWorldSpace(
|
||||
const glm::dmat4& projection, const glm::dmat4& inverse_projection,
|
||||
const glm::dmat4& inverse_view, const double& d, bool normalize,
|
||||
glm::dvec3& ll, glm::dvec3& lr, glm::dvec3& ul, glm::dvec3& ur) {
|
||||
glm::dvec4 lll{-1., -1., 1., 1.};
|
||||
glm::dvec4 llr{1., -1., 1., 1.};
|
||||
glm::dvec4 lul{-1., 1., 1., 1.};
|
||||
glm::dvec4 lur{1., 1., 1., 1.};
|
||||
|
||||
auto unproject = [&](glm::dvec4& v) -> void {
|
||||
v = inverse_projection * v;
|
||||
if (normalize) {
|
||||
v /= v.w;
|
||||
v *= d / glm::length(glm::dvec3(v.xyz));
|
||||
} else {
|
||||
v *= d / -v.z;
|
||||
}
|
||||
v.w = 1.;
|
||||
};
|
||||
|
||||
unproject(lll);
|
||||
unproject(llr);
|
||||
unproject(lul);
|
||||
unproject(lur);
|
||||
|
||||
ll = inverse_view * lll;
|
||||
lr = inverse_view * llr;
|
||||
ul = inverse_view * lul;
|
||||
ur = inverse_view * lur;
|
||||
}
|
||||
30
manul/renderer/source/csm.h
Normal file
30
manul/renderer/source/csm.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "nvrenderer/resource_registry.h"
|
||||
|
||||
struct MaShadowMap : public MaResourceRegistry {
|
||||
MaShadowMap(class NvRenderer* renderer);
|
||||
void Init();
|
||||
std::vector<double> m_shadow_planes;
|
||||
std::vector<glm::dmat4> m_cascade_matrices;
|
||||
std::vector<glm::dmat4> m_cascade_matrices_clamped;
|
||||
double m_far_plane_first;
|
||||
double m_far_plane_last;
|
||||
double m_shadow_far_plane;
|
||||
nvrhi::BufferHandle m_projection_buffer;
|
||||
nvrhi::BufferHandle m_inverse_projection_buffer;
|
||||
class NvRendererBackend* m_backend;
|
||||
void CalcCascades(const glm::dmat4& projection, const glm::dmat4& view,
|
||||
const glm::dvec3& light);
|
||||
void UpdateConstants(nvrhi::ICommandList* command_list);
|
||||
static void GetViewPlaneCornersWorldSpace(
|
||||
const glm::dmat4& projection, const glm::dmat4& inverse_projection,
|
||||
const glm::dmat4& inverse_view, const double& d, bool normalize,
|
||||
glm::dvec3& ll, glm::dvec3& lr, glm::dvec3& ul, glm::dvec3& ur);
|
||||
struct ShadowProjectionConstants {
|
||||
std::array<glm::mat4, 8> m_shadow_projection;
|
||||
std::array<float, 8> m_shadow_planes;
|
||||
};
|
||||
};
|
||||
21
manul/renderer/source/ddspp/LICENSE
Normal file
21
manul/renderer/source/ddspp/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2018-2023 Emilio López
|
||||
|
||||
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.
|
||||
1122
manul/renderer/source/ddspp/ddspp.h
Normal file
1122
manul/renderer/source/ddspp/ddspp.h
Normal file
File diff suppressed because it is too large
Load Diff
932
manul/renderer/source/environment.cpp
Normal file
932
manul/renderer/source/environment.cpp
Normal file
@@ -0,0 +1,932 @@
|
||||
#include "environment.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "gbuffer.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
#include "sky.h"
|
||||
|
||||
int MaEnvironment::GetCurrentSetIndex() {
|
||||
if (m_locked_set_index >= 0 && IsReady()) {
|
||||
m_current_set_index = std::exchange(m_locked_set_index, -1);
|
||||
}
|
||||
return m_current_set_index;
|
||||
}
|
||||
|
||||
nvrhi::BindingSetHandle MaEnvironment::GetBindingSet(int pass, int mip, int set,
|
||||
NvGbuffer* gbuffer_cube) {
|
||||
using namespace nvrhi;
|
||||
static std::map<int, BindingSetHandle> cache{};
|
||||
auto& handle =
|
||||
cache[((set & 0xf) << 28) | ((pass & 0xfff) << 16) | (mip & 0xffff)];
|
||||
if (!handle) {
|
||||
switch (pass) {
|
||||
case 1:
|
||||
if (!mip) {
|
||||
int previous_set = set - 1;
|
||||
while (previous_set < 0)
|
||||
previous_set += std::size(m_dynamic_envmap_diffuse);
|
||||
handle = m_backend->GetDevice()->createBindingSet(
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::Texture_SRV(0, m_skybox))
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
1, gbuffer_cube->m_gbuffer_diffuse, Format::UNKNOWN,
|
||||
AllSubresources))
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
2, gbuffer_cube->m_gbuffer_normal, Format::UNKNOWN,
|
||||
AllSubresources))
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
3, gbuffer_cube->m_gbuffer_params, Format::UNKNOWN,
|
||||
AllSubresources))
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
4, gbuffer_cube->m_gbuffer_depth, Format::UNKNOWN,
|
||||
AllSubresources))
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
5, m_dynamic_envmap_diffuse[previous_set],
|
||||
Format::UNKNOWN, AllSubresources))
|
||||
.addItem(BindingSetItem::Texture_SRV(13, m_sky_texture))
|
||||
.addItem(BindingSetItem::Texture_SRV(14, m_aerial_lut))
|
||||
.addItem(BindingSetItem::Texture_UAV(
|
||||
0, m_dynamic_skybox[set], Format::UNKNOWN,
|
||||
TextureSubresourceSet(
|
||||
0, 1, 0, TextureSubresourceSet::AllArraySlices),
|
||||
TextureDimension::Texture2DArray))
|
||||
.addItem(BindingSetItem::Sampler(0, m_sampler_linear_clamp))
|
||||
.addItem(BindingSetItem::Sampler(1, m_sampler_point_clamp))
|
||||
.addItem(BindingSetItem::Sampler(13, m_sampler_linear_clamp))
|
||||
.addItem(BindingSetItem::ConstantBuffer(
|
||||
13, m_sky->m_sky_constants))
|
||||
.addItem(BindingSetItem::ConstantBuffer(
|
||||
1, m_face_inverse_projection_buffer))
|
||||
.addItem(BindingSetItem::PushConstants(
|
||||
0, sizeof(CubeLightingConstants))),
|
||||
m_bl_gbuffer_lighting);
|
||||
} else {
|
||||
handle = m_backend->GetDevice()->createBindingSet(
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
1, m_dynamic_skybox[set], Format::UNKNOWN,
|
||||
TextureSubresourceSet(
|
||||
mip - 1, 1, 0,
|
||||
TextureSubresourceSet::AllArraySlices)))
|
||||
.addItem(BindingSetItem::Texture_UAV(
|
||||
0, m_dynamic_skybox[set], Format::UNKNOWN,
|
||||
TextureSubresourceSet(
|
||||
mip, 1, 0, TextureSubresourceSet::AllArraySlices),
|
||||
TextureDimension::Texture2DArray))
|
||||
.addItem(BindingSetItem::Sampler(1, m_sampler_linear_clamp))
|
||||
.addItem(BindingSetItem::PushConstants(
|
||||
0, sizeof(EnvironmentFilterConstants))),
|
||||
m_bl_diffuse_ibl);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
handle = m_backend->GetDevice()->createBindingSet(
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
1, m_dynamic_skybox[set], Format::UNKNOWN,
|
||||
TextureSubresourceSet(
|
||||
0, TextureSubresourceSet::AllMipLevels, 0,
|
||||
TextureSubresourceSet::AllArraySlices)))
|
||||
.addItem(BindingSetItem::Texture_UAV(
|
||||
0, m_dynamic_envmap_diffuse[set], Format::UNKNOWN,
|
||||
AllSubresources, TextureDimension::Texture2DArray))
|
||||
.addItem(BindingSetItem::Sampler(1, m_sampler_linear_clamp))
|
||||
.addItem(BindingSetItem::PushConstants(
|
||||
0, sizeof(EnvironmentFilterConstants))),
|
||||
m_bl_diffuse_ibl);
|
||||
break;
|
||||
case 3:
|
||||
handle = m_backend->GetDevice()->createBindingSet(
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::Texture_SRV(
|
||||
1, m_dynamic_skybox[set], Format::UNKNOWN,
|
||||
TextureSubresourceSet(
|
||||
0, TextureSubresourceSet::AllMipLevels, 0,
|
||||
TextureSubresourceSet::AllArraySlices)))
|
||||
.addItem(BindingSetItem::Texture_UAV(
|
||||
0, m_dynamic_envmap_specular[set], Format::UNKNOWN,
|
||||
TextureSubresourceSet(
|
||||
mip, 1, 0, TextureSubresourceSet::AllArraySlices),
|
||||
TextureDimension::Texture2DArray))
|
||||
.addItem(BindingSetItem::Sampler(1, m_sampler_linear_clamp))
|
||||
.addItem(BindingSetItem::PushConstants(
|
||||
0, sizeof(EnvironmentFilterConstants))),
|
||||
m_bl_diffuse_ibl);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
MaEnvironment::MaEnvironment(NvRenderer* renderer)
|
||||
: MaResourceRegistry(renderer),
|
||||
m_backend(renderer->m_backend.get()),
|
||||
m_gbuffer(renderer->m_gbuffer.get()),
|
||||
m_sky(renderer->m_sky.get()) {}
|
||||
|
||||
void MaEnvironment::Init(const std::string& texture, float pre_exposure) {
|
||||
InitResourceRegistry();
|
||||
using namespace nvrhi;
|
||||
m_cs_sample_equirectangular = m_backend->CreateShader(
|
||||
"envmap_CSSampleEquirectangular", ShaderType::Compute);
|
||||
m_cs_diffuse_ibl =
|
||||
m_backend->CreateShader("envmap_CSDiffuseIBL", ShaderType::Compute);
|
||||
m_cs_specular_ibl =
|
||||
m_backend->CreateShader("envmap_CSSpecularIBL", ShaderType::Compute);
|
||||
m_cs_generate_mip =
|
||||
m_backend->CreateShader("envmap_CSGenerateCubeMip", ShaderType::Compute);
|
||||
m_cs_integrate_brdf =
|
||||
m_backend->CreateShader("envmap_CSIntegrateBRDF", ShaderType::Compute);
|
||||
m_cs_gbuffer_lighting =
|
||||
m_backend->CreateShader("gbuffer_cube_lighting", ShaderType::Compute);
|
||||
|
||||
m_face_inverse_projection_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateStaticConstantBufferDesc(
|
||||
sizeof(glm::mat4), "Inverse Face Projection Buffer")
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
{
|
||||
auto command_list = m_backend->GetDevice()->createCommandList();
|
||||
glm::mat4 inverse_projection = glm::inverse(
|
||||
glm::perspectiveFovRH_ZO(glm::radians(90.f), 1.f, 1.f, .1f,
|
||||
Global.reflectiontune.range_instances));
|
||||
command_list->open();
|
||||
command_list->writeBuffer(m_face_inverse_projection_buffer,
|
||||
&inverse_projection, sizeof(inverse_projection));
|
||||
command_list->close();
|
||||
m_backend->GetDevice()->executeCommandList(command_list);
|
||||
}
|
||||
|
||||
m_bl_gbuffer_lighting = m_backend->GetDevice()->createBindingLayout(
|
||||
BindingLayoutDesc()
|
||||
.setVisibility(ShaderType::Compute)
|
||||
.addItem(BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(1))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(2))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(3))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(4))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(5))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(13))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(14))
|
||||
.addItem(BindingLayoutItem::Texture_UAV(0))
|
||||
.addItem(BindingLayoutItem::Sampler(0))
|
||||
.addItem(BindingLayoutItem::Sampler(1))
|
||||
.addItem(BindingLayoutItem::Sampler(13))
|
||||
.addItem(BindingLayoutItem::VolatileConstantBuffer(13))
|
||||
.addItem(BindingLayoutItem::ConstantBuffer(1))
|
||||
.addItem(BindingLayoutItem::PushConstants(
|
||||
0, sizeof(CubeLightingConstants))));
|
||||
m_pso_gbuffer_lighting = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.addBindingLayout(m_bl_gbuffer_lighting)
|
||||
.setComputeShader(m_cs_gbuffer_lighting));
|
||||
|
||||
m_bl_sample_equirectangular = m_backend->GetDevice()->createBindingLayout(
|
||||
BindingLayoutDesc()
|
||||
.setVisibility(ShaderType::Compute)
|
||||
.addItem(BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(BindingLayoutItem::Texture_UAV(0))
|
||||
.addItem(BindingLayoutItem::Sampler(0))
|
||||
.addItem(BindingLayoutItem::PushConstants(
|
||||
0, sizeof(EnvironmentFilterConstants))));
|
||||
m_pso_sample_equirectangular = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.addBindingLayout(m_bl_sample_equirectangular)
|
||||
.setComputeShader(m_cs_sample_equirectangular));
|
||||
|
||||
m_bl_diffuse_ibl = m_backend->GetDevice()->createBindingLayout(
|
||||
BindingLayoutDesc()
|
||||
.setVisibility(ShaderType::Compute)
|
||||
.addItem(BindingLayoutItem::Texture_SRV(1))
|
||||
.addItem(BindingLayoutItem::Texture_UAV(0))
|
||||
.addItem(BindingLayoutItem::Sampler(1))
|
||||
.addItem(BindingLayoutItem::PushConstants(
|
||||
0, sizeof(EnvironmentFilterConstants))));
|
||||
m_pso_diffuse_ibl = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.addBindingLayout(m_bl_diffuse_ibl)
|
||||
.setComputeShader(m_cs_diffuse_ibl));
|
||||
|
||||
m_pso_generate_mip = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.addBindingLayout(m_bl_diffuse_ibl)
|
||||
.setComputeShader(m_cs_generate_mip));
|
||||
|
||||
m_pso_specular_ibl = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.addBindingLayout(m_bl_diffuse_ibl)
|
||||
.setComputeShader(m_cs_specular_ibl));
|
||||
|
||||
m_bl_integrate_brdf = m_backend->GetDevice()->createBindingLayout(
|
||||
BindingLayoutDesc()
|
||||
.setVisibility(ShaderType::Compute)
|
||||
.addItem(BindingLayoutItem::Texture_UAV(1))
|
||||
.addItem(BindingLayoutItem::PushConstants(
|
||||
0, sizeof(EnvironmentFilterConstants))));
|
||||
|
||||
m_pso_integrate_brdf = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.addBindingLayout(m_bl_integrate_brdf)
|
||||
.setComputeShader(m_cs_integrate_brdf));
|
||||
|
||||
int skybox_width = 2048;
|
||||
int dynamic_skybox_width = 512;
|
||||
int skybox_mips = static_cast<int>(floor(log2(skybox_width))) + 1;
|
||||
int dynamic_skybox_mips =
|
||||
static_cast<int>(floor(log2(dynamic_skybox_width))) + 1;
|
||||
int diffuse_width = 64;
|
||||
int specular_width = 1024;
|
||||
int dynamic_specular_width = 256;
|
||||
int specular_mips = 6;
|
||||
|
||||
m_skybox = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setDimension(TextureDimension::TextureCube)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setArraySize(6)
|
||||
.setWidth(skybox_width)
|
||||
.setHeight(skybox_width)
|
||||
.setMipLevels(skybox_mips)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Skybox"));
|
||||
|
||||
m_dynamic_skybox[0] = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setDimension(TextureDimension::TextureCube)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setArraySize(6)
|
||||
.setWidth(dynamic_skybox_width)
|
||||
.setHeight(dynamic_skybox_width)
|
||||
.setMipLevels(dynamic_skybox_mips)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(ResourceStates::UnorderedAccess)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Dynamic Skybox"));
|
||||
|
||||
m_dynamic_skybox[1] = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setDimension(TextureDimension::TextureCube)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setArraySize(6)
|
||||
.setWidth(dynamic_skybox_width)
|
||||
.setHeight(dynamic_skybox_width)
|
||||
.setMipLevels(dynamic_skybox_mips)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(ResourceStates::UnorderedAccess)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Dynamic Skybox"));
|
||||
|
||||
m_sampler_linear_clamp_v_repeat_h = m_backend->GetDevice()->createSampler(
|
||||
SamplerDesc()
|
||||
.setAllAddressModes(SamplerAddressMode::Clamp)
|
||||
.setAddressU(SamplerAddressMode::Repeat)
|
||||
.setAllFilters(true));
|
||||
|
||||
m_sampler_linear_clamp = m_backend->GetDevice()->createSampler(
|
||||
SamplerDesc()
|
||||
.setAllAddressModes(SamplerAddressMode::Clamp)
|
||||
.setAllFilters(true));
|
||||
|
||||
m_sampler_point_clamp = m_backend->GetDevice()->createSampler(
|
||||
SamplerDesc()
|
||||
.setAllAddressModes(SamplerAddressMode::Clamp)
|
||||
.setAllFilters(false));
|
||||
CommandListHandle command_list = m_backend->GetDevice()->createCommandList();
|
||||
command_list->open();
|
||||
|
||||
{
|
||||
m_brdf_lut = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setFormat(Format::RG16_FLOAT)
|
||||
.setDimension(TextureDimension::Texture2D)
|
||||
.setWidth(512)
|
||||
.setHeight(512)
|
||||
.setMipLevels(1)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("BRDF LUT"));
|
||||
|
||||
RegisterResource(true, "env_brdf_lut", m_brdf_lut,
|
||||
ResourceType::Texture_SRV);
|
||||
|
||||
BindingSetHandle binding_set = m_backend->GetDevice()->createBindingSet(
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::Texture_UAV(1, m_brdf_lut))
|
||||
.addItem(BindingSetItem::PushConstants(
|
||||
0, sizeof(EnvironmentFilterConstants))),
|
||||
m_bl_integrate_brdf);
|
||||
|
||||
ComputeState compute_state = ComputeState()
|
||||
.setPipeline(m_pso_integrate_brdf)
|
||||
.addBindingSet(binding_set);
|
||||
|
||||
int target_width = m_brdf_lut->getDesc().width;
|
||||
int target_height = m_brdf_lut->getDesc().height;
|
||||
command_list->setComputeState(compute_state);
|
||||
|
||||
EnvironmentFilterConstants filter_constants{};
|
||||
filter_constants.m_sample_count = 4096;
|
||||
command_list->setPushConstants(&filter_constants, sizeof(filter_constants));
|
||||
|
||||
command_list->dispatch((target_width + 31) / 32, (target_height + 31) / 32,
|
||||
1);
|
||||
}
|
||||
|
||||
{
|
||||
m_envmap_diffuse = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setArraySize(6)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setDimension(TextureDimension::TextureCube)
|
||||
.setWidth(diffuse_width)
|
||||
.setHeight(diffuse_width)
|
||||
.setMipLevels(1)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Diffuse IBL"));
|
||||
for (int i = 0; i < std::size(m_dynamic_envmap_diffuse); ++i) {
|
||||
auto debug_name = fmt::format("Dynamic Diffuse IBL[{}]", i);
|
||||
auto resource_name = fmt::format("env_dynamic_diffuse_{}", i);
|
||||
m_dynamic_envmap_diffuse[i] = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setArraySize(6)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setDimension(TextureDimension::TextureCube)
|
||||
.setWidth(diffuse_width)
|
||||
.setHeight(diffuse_width)
|
||||
.setMipLevels(1)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(i ? ResourceStates::UnorderedAccess
|
||||
: ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName(debug_name.c_str()));
|
||||
}
|
||||
RegisterResource(true, "env_dynamic_diffuse", m_dynamic_envmap_diffuse[0],
|
||||
ResourceType::Texture_SRV);
|
||||
}
|
||||
|
||||
{
|
||||
m_envmap_specular = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setArraySize(6)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setDimension(TextureDimension::TextureCube)
|
||||
.setWidth(specular_width)
|
||||
.setHeight(specular_width)
|
||||
.setMipLevels(specular_mips)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Specular IBL"));
|
||||
for (int i = 0; i < std::size(m_dynamic_envmap_specular); ++i) {
|
||||
auto debug_name = fmt::format("Dynamic Specular IBL[{}]", i);
|
||||
auto resource_name = fmt::format("env_dynamic_specular_{}", i);
|
||||
m_dynamic_envmap_specular[i] = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc()
|
||||
.setArraySize(6)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setDimension(TextureDimension::TextureCube)
|
||||
.setWidth(dynamic_specular_width)
|
||||
.setHeight(dynamic_specular_width)
|
||||
.setMipLevels(specular_mips)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(i ? ResourceStates::UnorderedAccess
|
||||
: ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName(debug_name.c_str()));
|
||||
}
|
||||
RegisterResource(true, "env_dynamic_specular", m_dynamic_envmap_specular[0],
|
||||
ResourceType::Texture_SRV);
|
||||
}
|
||||
|
||||
m_sky_texture = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc(m_sky->m_aerial_lut->m_sky_texture->getDesc())
|
||||
.setDebugName("Envmap Sky Texture"));
|
||||
|
||||
m_aerial_lut = m_backend->GetDevice()->createTexture(
|
||||
TextureDesc(m_sky->m_aerial_lut->m_lut->getDesc())
|
||||
.setDebugName("Envmap Aerial LUT"));
|
||||
|
||||
command_list->close();
|
||||
m_backend->GetDevice()->executeCommandList(command_list);
|
||||
|
||||
m_environment_pass = std::make_shared<EnvironmentRenderPass>(this);
|
||||
m_environment_pass->Init();
|
||||
}
|
||||
|
||||
void MaEnvironment::Render(nvrhi::ICommandList* command_list,
|
||||
glm::dmat4 const& jitter,
|
||||
glm::dmat4 const& projection, glm::dmat4 const& view,
|
||||
glm::dmat4 const& previous_view_projection) {
|
||||
m_environment_pass->UpdateConstants(command_list, jitter, projection, view,
|
||||
previous_view_projection);
|
||||
m_environment_pass->Render(command_list);
|
||||
}
|
||||
|
||||
void MaEnvironment::Filter(uint64_t sky_instance_id, NvGbuffer* gbuffer_cube) {
|
||||
using namespace nvrhi;
|
||||
int pixels_per_pass_sqr = m_pixels_per_pass * m_pixels_per_pass;
|
||||
int target_set_index = 1;
|
||||
int source_set_index = 0;
|
||||
|
||||
static uint64_t prev_instance = -1;
|
||||
if (filter_step == 0) {
|
||||
if (!IsReady()) {
|
||||
return;
|
||||
}
|
||||
// m_locked_set_index = (GetCurrentSetIndex() + 1) % 2;
|
||||
m_ready_handle = m_backend->GetDevice()->createEventQuery();
|
||||
|
||||
// CommandListHandle transition_command_list =
|
||||
// m_backend->GetDevice()->createCommandList();
|
||||
// transition_command_list->open();
|
||||
//
|
||||
// transition_command_list->setTextureState(m_sky->m_aerial_lut->m_sky_texture,
|
||||
// nvrhi::AllSubresources,
|
||||
// nvrhi::ResourceStates::Common);
|
||||
// transition_command_list->setTextureState(m_sky->m_aerial_lut->m_lut,
|
||||
// nvrhi::AllSubresources,
|
||||
// nvrhi::ResourceStates::Common);
|
||||
//
|
||||
// transition_command_list->close();
|
||||
// auto transition_id =
|
||||
// m_backend->GetDevice()->executeCommandList(transition_command_list);
|
||||
//
|
||||
// m_backend->GetDevice()->queueWaitForCommandList(
|
||||
// nvrhi::CommandQueue::Copy, nvrhi::CommandQueue::Graphics,
|
||||
// transition_id);
|
||||
|
||||
CommandListHandle command_list = m_backend->GetDevice()->createCommandList(
|
||||
CommandListParameters()
|
||||
.setQueueType(CommandQueue::Graphics)
|
||||
.setEnableImmediateExecution(false));
|
||||
command_list->open();
|
||||
|
||||
{
|
||||
auto diff_desc = m_sky_texture->getDesc();
|
||||
for (int i = 0; i < diff_desc.arraySize; ++i) {
|
||||
for (int j = 0; j < diff_desc.mipLevels; ++j) {
|
||||
auto slice = nvrhi::TextureSlice()
|
||||
.setArraySlice(i)
|
||||
.setMipLevel(j)
|
||||
.setWidth(-1)
|
||||
.setHeight(-1)
|
||||
.resolve(diff_desc);
|
||||
command_list->copyTexture(m_sky_texture, slice,
|
||||
m_sky->m_aerial_lut->m_sky_texture, slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto diff_desc = m_aerial_lut->getDesc();
|
||||
for (int i = 0; i < diff_desc.arraySize; ++i) {
|
||||
for (int j = 0; j < diff_desc.mipLevels; ++j) {
|
||||
auto slice = nvrhi::TextureSlice()
|
||||
.setArraySlice(i)
|
||||
.setMipLevel(j)
|
||||
.setWidth(-1)
|
||||
.setHeight(-1)
|
||||
.resolve(diff_desc);
|
||||
command_list->copyTexture(m_aerial_lut, slice,
|
||||
m_sky->m_aerial_lut->m_lut, slice);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// auto diff_desc = m_dynamic_envmap_diffuse[0]->getDesc();
|
||||
// for (int i = 0; i < 6; ++i) {
|
||||
// for (int j = 0; j < diff_desc.mipLevels; ++j) {
|
||||
// auto slice = nvrhi::TextureSlice()
|
||||
// .setArraySlice(i)
|
||||
// .setMipLevel(j)
|
||||
// .setWidth(-1)
|
||||
// .setHeight(-1)
|
||||
// .resolve(diff_desc);
|
||||
// command_list->copyTexture(m_dynamic_envmap_diffuse[0], slice,
|
||||
// m_dynamic_envmap_diffuse[1], slice);
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// auto spec_desc = m_dynamic_envmap_specular[0]->getDesc();
|
||||
// for (int i = 0; i < 6; ++i) {
|
||||
// for (int j = 0; j < spec_desc.mipLevels; ++j) {
|
||||
// auto slice = nvrhi::TextureSlice()
|
||||
// .setArraySlice(i)
|
||||
// .setMipLevel(j)
|
||||
// .setWidth(-1)
|
||||
// .setHeight(-1)
|
||||
// .resolve(spec_desc);
|
||||
// command_list->copyTexture(m_dynamic_envmap_specular[0], slice,
|
||||
// m_dynamic_envmap_specular[1], slice);
|
||||
// }
|
||||
//}
|
||||
|
||||
// command_list->setTextureState(m_sky_texture, nvrhi::AllSubresources,
|
||||
// nvrhi::ResourceStates::Common);
|
||||
// command_list->setTextureState(m_aerial_lut, nvrhi::AllSubresources,
|
||||
// nvrhi::ResourceStates::Common);
|
||||
command_list->close();
|
||||
prev_instance = m_backend->GetDevice()->executeCommandList(
|
||||
command_list, nvrhi::CommandQueue::Graphics);
|
||||
// CommandListHandle transition_command_list =
|
||||
// m_backend->GetDevice()->createCommandList();
|
||||
// transition_command_list->open();
|
||||
//
|
||||
// transition_command_list->setTextureState(m_skybox, AllSubresources,
|
||||
// ResourceStates::UnorderedAccess);
|
||||
// transition_command_list->setTextureState(m_dynamic_skybox[target_set_index],
|
||||
// AllSubresources,
|
||||
// ResourceStates::UnorderedAccess);
|
||||
// transition_command_list->setTextureState(
|
||||
// m_dynamic_envmap_diffuse[target_set_index], AllSubresources,
|
||||
// ResourceStates::UnorderedAccess);
|
||||
// transition_command_list->setTextureState(
|
||||
// m_dynamic_envmap_specular[target_set_index], AllSubresources,
|
||||
// ResourceStates::UnorderedAccess);
|
||||
// transition_command_list->setTextureState(
|
||||
// m_dynamic_envmap_diffuse[source_set_index], AllSubresources,
|
||||
// ResourceStates::ShaderResource);
|
||||
// transition_command_list->setTextureState(
|
||||
// m_dynamic_envmap_specular[source_set_index], AllSubresources,
|
||||
// ResourceStates::ShaderResource);
|
||||
// transition_command_list->setTextureState(gbuffer_cube->m_gbuffer_diffuse,
|
||||
// AllSubresources,
|
||||
// ResourceStates::ShaderResource);
|
||||
// transition_command_list->setTextureState(gbuffer_cube->m_gbuffer_normal,
|
||||
// AllSubresources,
|
||||
// ResourceStates::ShaderResource);
|
||||
// transition_command_list->setTextureState(gbuffer_cube->m_gbuffer_params,
|
||||
// AllSubresources,
|
||||
// ResourceStates::ShaderResource);
|
||||
// transition_command_list->setTextureState(gbuffer_cube->m_gbuffer_depth,
|
||||
// AllSubresources,
|
||||
// ResourceStates::ShaderResource);
|
||||
// transition_command_list->commitBarriers();
|
||||
//
|
||||
// transition_command_list->close();
|
||||
// auto instance =
|
||||
// m_backend->GetDevice()->executeCommandList(transition_command_list);
|
||||
// m_backend->GetDevice()->queueWaitForCommandList(
|
||||
// nvrhi::CommandQueue::Compute, nvrhi::CommandQueue::Graphics,
|
||||
// instance);
|
||||
++filter_step;
|
||||
mip = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if (filter_step == 1) {
|
||||
// CommandListHandle command_list_transition =
|
||||
// m_backend->GetDevice()->createCommandList();
|
||||
// command_list_transition->open();
|
||||
//
|
||||
// command_list_transition->setTextureState(
|
||||
// m_sky->m_aerial_lut->m_sky_texture, nvrhi::AllSubresources,
|
||||
// nvrhi::ResourceStates::ShaderResource);
|
||||
//
|
||||
// command_list_transition->close();
|
||||
// auto instance =
|
||||
// m_backend->GetDevice()->executeCommandList(command_list_transition);
|
||||
|
||||
if (prev_instance != -1) {
|
||||
//m_backend->GetDevice()->queueWaitForCommandList(
|
||||
// nvrhi::CommandQueue::Compute, nvrhi::CommandQueue::Graphics,
|
||||
// prev_instance);
|
||||
//prev_instance = -1;
|
||||
}
|
||||
CommandListHandle command_list = m_backend->GetDevice()->createCommandList(
|
||||
CommandListParameters()
|
||||
.setQueueType(CommandQueue::Graphics)
|
||||
.setEnableImmediateExecution(false));
|
||||
// m_backend->GetDevice()->queueWaitForCommandList(
|
||||
// nvrhi::CommandQueue::Compute, nvrhi::CommandQueue::Graphics,
|
||||
// instance);
|
||||
command_list->open();
|
||||
|
||||
while (true) {
|
||||
int target_width = std::max(
|
||||
m_dynamic_skybox[target_set_index]->getDesc().width >> mip, 1u);
|
||||
int target_height = std::max(
|
||||
m_dynamic_skybox[target_set_index]->getDesc().height >> mip, 1u);
|
||||
|
||||
int pixels_x = std::min(m_pixels_per_pass, target_width - x);
|
||||
int pixels_y = std::min(m_pixels_per_pass, target_height - y);
|
||||
|
||||
if (pixels_x * pixels_y > pixels_per_pass_sqr) {
|
||||
break;
|
||||
}
|
||||
|
||||
pixels_per_pass_sqr -= pixels_x * pixels_y;
|
||||
|
||||
if (mip >= m_dynamic_skybox[target_set_index]->getDesc().mipLevels) {
|
||||
break;
|
||||
}
|
||||
if (!mip) m_sky->UpdateConstants(command_list);
|
||||
ComputeState compute_state;
|
||||
compute_state
|
||||
.setPipeline(mip ? m_pso_generate_mip : m_pso_gbuffer_lighting)
|
||||
.addBindingSet(
|
||||
GetBindingSet(filter_step, mip, target_set_index, gbuffer_cube));
|
||||
command_list->setComputeState(compute_state);
|
||||
|
||||
if (!mip) {
|
||||
CubeLightingConstants filter_constants{};
|
||||
const auto& daylight = Global.DayLight;
|
||||
filter_constants.m_offset_x = x;
|
||||
filter_constants.m_offset_y = y;
|
||||
filter_constants.m_offset_z = 0;
|
||||
filter_constants.m_light_direction = -daylight.direction;
|
||||
filter_constants.m_height = Global.pCamera.Pos.y;
|
||||
filter_constants.m_light_color = glm::vec4(m_sky->CalcSunColor(), 1.f);
|
||||
command_list->setPushConstants(&filter_constants,
|
||||
sizeof(filter_constants));
|
||||
} else {
|
||||
EnvironmentFilterConstants filter_constants{};
|
||||
filter_constants.m_offset_x = x;
|
||||
filter_constants.m_offset_y = y;
|
||||
filter_constants.m_offset_z = 0;
|
||||
command_list->setPushConstants(&filter_constants,
|
||||
sizeof(filter_constants));
|
||||
}
|
||||
|
||||
command_list->dispatch((pixels_x + 31) / 32, (pixels_y + 31) / 32, 6);
|
||||
x += m_pixels_per_pass;
|
||||
if (x >= target_width) {
|
||||
x = 0;
|
||||
y += m_pixels_per_pass;
|
||||
}
|
||||
if (y >= target_height) {
|
||||
y = 0;
|
||||
++mip;
|
||||
}
|
||||
}
|
||||
|
||||
if (mip >= m_dynamic_skybox[target_set_index]->getDesc().mipLevels) {
|
||||
mip = 0;
|
||||
++filter_step;
|
||||
}
|
||||
|
||||
command_list->close();
|
||||
m_backend->GetDevice()->executeCommandList(command_list,
|
||||
nvrhi::CommandQueue::Graphics);
|
||||
}
|
||||
|
||||
if (filter_step == 2) {
|
||||
CommandListHandle command_list = m_backend->GetDevice()->createCommandList(
|
||||
CommandListParameters()
|
||||
.setQueueType(CommandQueue::Graphics)
|
||||
.setEnableImmediateExecution(false));
|
||||
command_list->open();
|
||||
|
||||
ComputeState compute_state =
|
||||
ComputeState()
|
||||
.setPipeline(m_pso_diffuse_ibl)
|
||||
.addBindingSet(
|
||||
GetBindingSet(filter_step, 0, target_set_index, gbuffer_cube));
|
||||
|
||||
int target_width =
|
||||
m_dynamic_envmap_diffuse[target_set_index]->getDesc().width;
|
||||
int target_height =
|
||||
m_dynamic_envmap_diffuse[target_set_index]->getDesc().height;
|
||||
command_list->setComputeState(compute_state);
|
||||
|
||||
EnvironmentFilterConstants filter_constants{};
|
||||
filter_constants.m_sample_count = 32;
|
||||
filter_constants.m_source_width =
|
||||
m_dynamic_skybox[target_set_index]->getDesc().width;
|
||||
filter_constants.m_offset_x = 0;
|
||||
filter_constants.m_offset_y = 0;
|
||||
filter_constants.m_offset_z = 0;
|
||||
filter_constants.m_mip_bias = 1.;
|
||||
command_list->setPushConstants(&filter_constants, sizeof(filter_constants));
|
||||
|
||||
command_list->dispatch((target_width + 31) / 32, (target_height + 31) / 32,
|
||||
6);
|
||||
command_list->close();
|
||||
m_backend->GetDevice()->executeCommandList(command_list,
|
||||
nvrhi::CommandQueue::Graphics);
|
||||
++filter_step;
|
||||
}
|
||||
|
||||
if (filter_step == 3) {
|
||||
CommandListHandle command_list = m_backend->GetDevice()->createCommandList(
|
||||
CommandListParameters()
|
||||
.setQueueType(CommandQueue::Graphics)
|
||||
.setEnableImmediateExecution(false));
|
||||
command_list->open();
|
||||
|
||||
while (true) {
|
||||
int target_width = std::max(
|
||||
1u,
|
||||
m_dynamic_envmap_specular[target_set_index]->getDesc().width >> mip);
|
||||
int target_height = std::max(
|
||||
1u,
|
||||
m_dynamic_envmap_specular[target_set_index]->getDesc().height >> mip);
|
||||
|
||||
int pixels_x = std::min(m_pixels_per_pass, target_width - x);
|
||||
int pixels_y = std::min(m_pixels_per_pass, target_height - y);
|
||||
|
||||
if (pixels_x * pixels_y > pixels_per_pass_sqr) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (mip >=
|
||||
m_dynamic_envmap_specular[target_set_index]->getDesc().mipLevels) {
|
||||
break;
|
||||
}
|
||||
|
||||
pixels_per_pass_sqr -= pixels_x * pixels_y;
|
||||
|
||||
ComputeState compute_state =
|
||||
ComputeState()
|
||||
.setPipeline(m_pso_specular_ibl)
|
||||
.addBindingSet(GetBindingSet(filter_step, mip, target_set_index,
|
||||
gbuffer_cube));
|
||||
|
||||
EnvironmentFilterConstants filter_constants{};
|
||||
filter_constants.m_sample_count = 32;
|
||||
filter_constants.m_roughness =
|
||||
glm::pow(static_cast<double>(mip) /
|
||||
(m_dynamic_envmap_specular[target_set_index]
|
||||
->getDesc()
|
||||
.mipLevels -
|
||||
1.),
|
||||
2.);
|
||||
filter_constants.m_source_width =
|
||||
m_dynamic_skybox[target_set_index]->getDesc().width;
|
||||
filter_constants.m_mip_bias =
|
||||
mip ? 1.
|
||||
: log2(target_width /
|
||||
static_cast<double>(filter_constants.m_source_width));
|
||||
filter_constants.m_offset_x = x;
|
||||
filter_constants.m_offset_y = y;
|
||||
filter_constants.m_offset_z = 0;
|
||||
command_list->setComputeState(compute_state);
|
||||
command_list->setPushConstants(&filter_constants,
|
||||
sizeof(filter_constants));
|
||||
|
||||
command_list->dispatch((pixels_x + 31) / 32, (pixels_y + 31) / 32, 6);
|
||||
|
||||
x += m_pixels_per_pass;
|
||||
if (x >= target_width) {
|
||||
x = 0;
|
||||
y += m_pixels_per_pass;
|
||||
}
|
||||
if (y >= target_height) {
|
||||
y = 0;
|
||||
++mip;
|
||||
}
|
||||
}
|
||||
command_list->close();
|
||||
m_backend->GetDevice()->executeCommandList(command_list,
|
||||
nvrhi::CommandQueue::Graphics);
|
||||
if (mip >=
|
||||
m_dynamic_envmap_specular[target_set_index]->getDesc().mipLevels) {
|
||||
mip = 0;
|
||||
filter_step = 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (filter_step == 4) {
|
||||
CommandListHandle command_list = m_backend->GetDevice()->createCommandList(
|
||||
CommandListParameters()
|
||||
.setQueueType(CommandQueue::Graphics)
|
||||
.setEnableImmediateExecution(false));
|
||||
command_list->open();
|
||||
|
||||
auto diff_desc = m_dynamic_envmap_diffuse[0]->getDesc();
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
for (int j = 0; j < diff_desc.mipLevels; ++j) {
|
||||
auto slice = nvrhi::TextureSlice()
|
||||
.setArraySlice(i)
|
||||
.setMipLevel(j)
|
||||
.setWidth(-1)
|
||||
.setHeight(-1)
|
||||
.resolve(diff_desc);
|
||||
command_list->copyTexture(m_dynamic_envmap_diffuse[0], slice,
|
||||
m_dynamic_envmap_diffuse[1], slice);
|
||||
}
|
||||
}
|
||||
|
||||
auto spec_desc = m_dynamic_envmap_specular[0]->getDesc();
|
||||
for (int i = 0; i < 6; ++i) {
|
||||
for (int j = 0; j < spec_desc.mipLevels; ++j) {
|
||||
auto slice = nvrhi::TextureSlice()
|
||||
.setArraySlice(i)
|
||||
.setMipLevel(j)
|
||||
.setWidth(-1)
|
||||
.setHeight(-1)
|
||||
.resolve(spec_desc);
|
||||
command_list->copyTexture(m_dynamic_envmap_specular[0], slice,
|
||||
m_dynamic_envmap_specular[1], slice);
|
||||
}
|
||||
}
|
||||
|
||||
command_list->close();
|
||||
m_backend->GetDevice()->executeCommandList(command_list,
|
||||
nvrhi::CommandQueue::Graphics);
|
||||
filter_step = 0;
|
||||
m_backend->GetDevice()->setEventQuery(m_ready_handle,
|
||||
nvrhi::CommandQueue::Graphics);
|
||||
}
|
||||
}
|
||||
|
||||
bool MaEnvironment::IsReady() const {
|
||||
return !m_ready_handle ||
|
||||
m_backend->GetDevice()->pollEventQuery(m_ready_handle);
|
||||
}
|
||||
|
||||
EnvironmentRenderPass::EnvironmentRenderPass(MaEnvironment* environment)
|
||||
: FullScreenPass(environment->m_backend),
|
||||
m_environment(environment),
|
||||
m_gbuffer(environment->m_gbuffer),
|
||||
m_skybox_texture(environment->m_skybox) {}
|
||||
|
||||
void EnvironmentRenderPass::Init() {
|
||||
m_environment_constants = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc(
|
||||
sizeof(EnvironmentConstants), "Skybox Draw Constants", 16)
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
m_binding_layout = m_backend->GetDevice()->createBindingLayout(
|
||||
nvrhi::BindingLayoutDesc()
|
||||
.setVisibility(nvrhi::ShaderType::Pixel)
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(13))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(13))
|
||||
.addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(0)));
|
||||
auto sampler = m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(nvrhi::SamplerAddressMode::Clamp)
|
||||
.setAllFilters(true));
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
m_binding_set[i] = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::Texture_SRV(0, m_environment->m_skybox))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
13, m_environment->m_sky->m_aerial_lut->m_sky_texture))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
0, m_environment->m_sampler_linear_clamp))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
13, m_environment->m_sampler_linear_clamp))
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
|
||||
0, m_environment_constants)),
|
||||
m_binding_layout);
|
||||
}
|
||||
|
||||
m_pixel_shader = m_backend->CreateShader("skybox", nvrhi::ShaderType::Pixel);
|
||||
FullScreenPass::Init();
|
||||
}
|
||||
|
||||
void EnvironmentRenderPass::CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) {
|
||||
FullScreenPass::CreatePipelineDesc(pipeline_desc);
|
||||
pipeline_desc.addBindingLayout(m_binding_layout);
|
||||
pipeline_desc.setPixelShader(m_pixel_shader);
|
||||
pipeline_desc.renderState.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.disableDepthWrite()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::GreaterOrEqual)
|
||||
.disableStencil());
|
||||
}
|
||||
|
||||
void EnvironmentRenderPass::UpdateConstants(
|
||||
nvrhi::ICommandList* command_list, glm::dmat4 const& jitter,
|
||||
glm::dmat4 const& projection, glm::dmat4 const& view,
|
||||
glm::dmat4 const& previous_view_projection) {
|
||||
EnvironmentConstants constants{};
|
||||
|
||||
constants.m_reproject_matrix =
|
||||
glm::inverse(projection * view) * previous_view_projection;
|
||||
constants.m_inverse_view_projection =
|
||||
glm::inverse(jitter * projection * glm::dmat4(glm::dmat3(view)));
|
||||
constants.m_sun_direction = -Global.DayLight.direction;
|
||||
constants.m_height = Global.pCamera.Pos.y;
|
||||
|
||||
command_list->writeBuffer(m_environment_constants, &constants,
|
||||
sizeof(constants));
|
||||
}
|
||||
|
||||
void EnvironmentRenderPass::Render(nvrhi::ICommandList* command_list) {
|
||||
nvrhi::GraphicsState graphics_state;
|
||||
InitState(graphics_state);
|
||||
graphics_state.addBindingSet(
|
||||
m_binding_set[m_environment->GetCurrentSetIndex()]);
|
||||
command_list->setGraphicsState(graphics_state);
|
||||
Draw(command_list);
|
||||
}
|
||||
|
||||
nvrhi::IFramebuffer* EnvironmentRenderPass::GetFramebuffer() {
|
||||
return m_gbuffer->m_framebuffer;
|
||||
}
|
||||
139
manul/renderer/source/environment.h
Normal file
139
manul/renderer/source/environment.h
Normal file
@@ -0,0 +1,139 @@
|
||||
#pragma once
|
||||
|
||||
#include "fullscreenpass.h"
|
||||
#include "nvrenderer/resource_registry.h"
|
||||
#include "nvrhi/nvrhi.h"
|
||||
|
||||
struct MaEnvironment : public MaResourceRegistry {
|
||||
nvrhi::TextureHandle m_skybox;
|
||||
nvrhi::TextureHandle m_dynamic_skybox[2];
|
||||
nvrhi::TextureHandle m_envmap_specular;
|
||||
nvrhi::TextureHandle m_dynamic_envmap_specular[2];
|
||||
nvrhi::TextureHandle m_envmap_diffuse;
|
||||
nvrhi::TextureHandle m_dynamic_envmap_diffuse[2];
|
||||
nvrhi::TextureHandle m_hdri;
|
||||
nvrhi::TextureHandle m_brdf_lut;
|
||||
nvrhi::TextureHandle m_sky_texture;
|
||||
nvrhi::TextureHandle m_aerial_lut;
|
||||
|
||||
nvrhi::SamplerHandle m_sampler_linear_clamp_v_repeat_h;
|
||||
nvrhi::SamplerHandle m_sampler_linear_clamp;
|
||||
nvrhi::SamplerHandle m_sampler_point_clamp;
|
||||
|
||||
nvrhi::ShaderHandle m_cs_sample_equirectangular;
|
||||
nvrhi::ComputePipelineHandle m_pso_sample_equirectangular;
|
||||
nvrhi::BindingLayoutHandle m_bl_sample_equirectangular;
|
||||
|
||||
nvrhi::ShaderHandle m_cs_gbuffer_lighting;
|
||||
nvrhi::ComputePipelineHandle m_pso_gbuffer_lighting;
|
||||
nvrhi::BindingLayoutHandle m_bl_gbuffer_lighting;
|
||||
|
||||
nvrhi::ShaderHandle m_cs_diffuse_ibl;
|
||||
nvrhi::ComputePipelineHandle m_pso_diffuse_ibl;
|
||||
nvrhi::BindingLayoutHandle m_bl_diffuse_ibl;
|
||||
|
||||
nvrhi::ShaderHandle m_cs_specular_ibl;
|
||||
nvrhi::ComputePipelineHandle m_pso_specular_ibl;
|
||||
|
||||
nvrhi::ShaderHandle m_cs_generate_mip;
|
||||
nvrhi::ComputePipelineHandle m_pso_generate_mip;
|
||||
|
||||
nvrhi::ShaderHandle m_cs_integrate_brdf;
|
||||
nvrhi::ComputePipelineHandle m_pso_integrate_brdf;
|
||||
nvrhi::BindingLayoutHandle m_bl_integrate_brdf;
|
||||
nvrhi::EventQueryHandle m_ready_handle;
|
||||
|
||||
nvrhi::BufferHandle m_face_inverse_projection_buffer;
|
||||
|
||||
class NvRendererBackend* m_backend;
|
||||
struct NvGbuffer* m_gbuffer;
|
||||
struct Sky* m_sky;
|
||||
int filter_step = 0;
|
||||
int mip = 0;
|
||||
int x = 0;
|
||||
int y = 0;
|
||||
|
||||
int m_current_set_index = 0;
|
||||
int m_locked_set_index = 0;
|
||||
int GetCurrentSetIndex();
|
||||
|
||||
std::shared_ptr<struct EnvironmentRenderPass> m_environment_pass;
|
||||
|
||||
const int m_pixels_per_pass = 256;
|
||||
|
||||
nvrhi::BindingSetHandle GetBindingSet(int pass, int mip, int set,
|
||||
NvGbuffer* gbuffer_cube);
|
||||
|
||||
struct EnvironmentFilterConstants {
|
||||
EnvironmentFilterConstants() {
|
||||
m_pre_exposure_mul = 1.f;
|
||||
m_roughness = 0.f;
|
||||
m_sample_count = 32.f;
|
||||
m_source_width = 2048.f;
|
||||
m_mip_bias = 0.f;
|
||||
m_offset_x = 0;
|
||||
m_offset_y = 0;
|
||||
m_offset_z = 0;
|
||||
}
|
||||
float m_pre_exposure_mul;
|
||||
float m_roughness;
|
||||
float m_sample_count;
|
||||
float m_source_width;
|
||||
float m_mip_bias;
|
||||
uint32_t m_offset_x;
|
||||
uint32_t m_offset_y;
|
||||
uint32_t m_offset_z;
|
||||
};
|
||||
|
||||
struct CubeLightingConstants {
|
||||
uint32_t m_offset_x;
|
||||
uint32_t m_offset_y;
|
||||
uint32_t m_offset_z;
|
||||
uint32_t m_unused;
|
||||
glm::vec3 m_light_direction;
|
||||
float m_height;
|
||||
glm::vec4 m_light_color;
|
||||
};
|
||||
|
||||
MaEnvironment(class NvRenderer* renderer);
|
||||
void Init(const std::string& texture, float pre_exposure);
|
||||
void Render(nvrhi::ICommandList* command_list, glm::dmat4 const& jitter,
|
||||
glm::dmat4 const& projection, glm::dmat4 const& view,
|
||||
glm::dmat4 const& previous_view_projection);
|
||||
void Filter(uint64_t sky_instance_id, NvGbuffer* gbuffer_cube);
|
||||
bool IsReady() const;
|
||||
};
|
||||
|
||||
struct EnvironmentRenderPass : public FullScreenPass {
|
||||
EnvironmentRenderPass(MaEnvironment* environment);
|
||||
|
||||
struct EnvironmentConstants {
|
||||
glm::mat4 m_inverse_view_projection;
|
||||
glm::mat4 m_reproject_matrix;
|
||||
glm::vec3 m_sun_direction;
|
||||
float m_height;
|
||||
};
|
||||
|
||||
virtual void Init() override;
|
||||
|
||||
virtual void CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) override;
|
||||
|
||||
void UpdateConstants(nvrhi::ICommandList* command_list,
|
||||
glm::dmat4 const& jitter, glm::dmat4 const& projection,
|
||||
glm::dmat4 const& view,
|
||||
glm::dmat4 const& previous_view_projection);
|
||||
|
||||
virtual void Render(nvrhi::ICommandList* command_list) override;
|
||||
|
||||
virtual nvrhi::IFramebuffer* GetFramebuffer() override;
|
||||
|
||||
struct NvGbuffer* m_gbuffer;
|
||||
MaEnvironment* m_environment;
|
||||
nvrhi::BufferHandle m_environment_constants;
|
||||
nvrhi::TextureHandle m_skybox_texture;
|
||||
nvrhi::BindingLayoutHandle m_binding_layout;
|
||||
nvrhi::BindingSetHandle m_binding_set[2];
|
||||
nvrhi::ShaderHandle m_pixel_shader;
|
||||
nvrhi::FramebufferHandle m_framebuffer;
|
||||
};
|
||||
201
manul/renderer/source/fsr.cpp
Normal file
201
manul/renderer/source/fsr.cpp
Normal file
@@ -0,0 +1,201 @@
|
||||
#include "fsr.h"
|
||||
|
||||
#if LIBMANUL_WITH_D3D12
|
||||
#include <ffx-fsr2-api/dx12/ffx_fsr2_dx12.h>
|
||||
|
||||
#include "nvrenderer_d3d12.h"
|
||||
#endif
|
||||
|
||||
#if LIBMANUL_WITH_VULKAN
|
||||
#include <ffx-fsr2-api/vk/ffx_fsr2_vk.h>
|
||||
#include <nvrhi/vulkan.h>
|
||||
|
||||
#include "nvrenderer_vulkan.h"
|
||||
#endif
|
||||
|
||||
#include "Globals.h"
|
||||
#include "gbuffer.h"
|
||||
#include "gbufferblitpass.h"
|
||||
|
||||
NvFSR::NvFSR(NvRenderer* renderer)
|
||||
: m_backend(renderer->m_backend.get()),
|
||||
m_inputpass(renderer->m_gbuffer_blit.get()),
|
||||
m_gbuffer(renderer->m_gbuffer.get()) {}
|
||||
|
||||
void OnFsrMessage(FfxFsr2MsgType type, const wchar_t* msg) {
|
||||
//__debugbreak();
|
||||
}
|
||||
|
||||
void NvFSR::Init() {
|
||||
m_width = m_backend->GetCurrentFramebuffer()->getFramebufferInfo().width;
|
||||
m_height = m_backend->GetCurrentFramebuffer()->getFramebufferInfo().height;
|
||||
m_input_width = m_gbuffer->m_framebuffer->getFramebufferInfo().width;
|
||||
m_input_height = m_gbuffer->m_framebuffer->getFramebufferInfo().height;
|
||||
|
||||
m_color = m_inputpass->m_output;
|
||||
m_depth = m_gbuffer->m_gbuffer_depth;
|
||||
m_motion = m_gbuffer->m_gbuffer_motion;
|
||||
|
||||
m_output = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setFormat(nvrhi::Format::RGBA16_FLOAT)
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setDebugName("FSR Output")
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
m_auto_exposure_buffer = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setFormat(nvrhi::Format::RG32_FLOAT)
|
||||
.setWidth(1)
|
||||
.setHeight(1)
|
||||
.setIsUAV(true)
|
||||
.setDebugName("FSR Auto Exposure Buffer")
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setKeepInitialState(true));
|
||||
auto device = m_backend->GetDevice();
|
||||
FfxFsr2ContextDescription context_description{};
|
||||
switch (device->getGraphicsAPI()) {
|
||||
#if LIBMANUL_WITH_D3D12
|
||||
case nvrhi::GraphicsAPI::D3D12:
|
||||
m_scratch_buffer.resize(ffxFsr2GetScratchMemorySizeDX12());
|
||||
ffxFsr2GetInterfaceDX12(&m_fsr2_interface,
|
||||
m_backend->GetDevice()->getNativeObject(
|
||||
nvrhi::ObjectTypes::D3D12_Device),
|
||||
m_scratch_buffer.data(), m_scratch_buffer.size());
|
||||
context_description.device = m_backend->GetDevice()->getNativeObject(
|
||||
nvrhi::ObjectTypes::D3D12_Device);
|
||||
break;
|
||||
#endif
|
||||
#if LIBMANUL_WITH_VULKAN
|
||||
case nvrhi::GraphicsAPI::VULKAN:
|
||||
m_scratch_buffer.resize(
|
||||
ffxFsr2GetScratchMemorySizeVK(m_backend->GetDevice()->getNativeObject(
|
||||
nvrhi::ObjectTypes::VK_PhysicalDevice)));
|
||||
ffxFsr2GetInterfaceVK(&m_fsr2_interface, m_scratch_buffer.data(),
|
||||
m_scratch_buffer.size(),
|
||||
m_backend->GetDevice()->getNativeObject(
|
||||
nvrhi::ObjectTypes::VK_PhysicalDevice),
|
||||
dynamic_cast<NvRendererBackend_Vulkan*>(m_backend)
|
||||
->GetDeviceProcAddr());
|
||||
context_description.device =
|
||||
ffxGetDeviceVK(m_backend->GetDevice()->getNativeObject(
|
||||
nvrhi::ObjectTypes::VK_Device));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
context_description.callbacks = m_fsr2_interface;
|
||||
context_description.displaySize.width = m_width;
|
||||
context_description.displaySize.height = m_height;
|
||||
context_description.maxRenderSize.width = 3440;
|
||||
context_description.maxRenderSize.height = 1440;
|
||||
context_description.flags = // FFX_FSR2_ENABLE_DEBUG_CHECKING |
|
||||
FFX_FSR2_ENABLE_AUTO_EXPOSURE | FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE |
|
||||
FFX_FSR2_ENABLE_DEPTH_INVERTED;
|
||||
context_description.fpMessage = &OnFsrMessage;
|
||||
ffxFsr2ContextCreate(&m_fsr2_context, &context_description);
|
||||
}
|
||||
|
||||
void NvFSR::Render(nvrhi::ICommandList* command_list, double far_plane,
|
||||
double near_plane, double fov) {
|
||||
FfxFsr2DispatchDescription dispatch_description{};
|
||||
switch (m_backend->GetDevice()->getGraphicsAPI()) {
|
||||
#if LIBMANUL_WITH_D3D12
|
||||
case nvrhi::GraphicsAPI::D3D12:
|
||||
dispatch_description.commandList =
|
||||
ffxGetCommandListDX12(command_list->getNativeObject(
|
||||
nvrhi::ObjectTypes::D3D12_GraphicsCommandList));
|
||||
break;
|
||||
#endif
|
||||
#if LIBMANUL_WITH_VULKAN
|
||||
case nvrhi::GraphicsAPI::VULKAN:
|
||||
dispatch_description.commandList = ffxGetCommandListVK(
|
||||
command_list->getNativeObject(nvrhi::ObjectTypes::VK_CommandBuffer));
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
dispatch_description.color = GetFfxResource(m_color, L"FSR2 Input Color");
|
||||
dispatch_description.depth = GetFfxResource(m_depth, L"FSR2 Input Depth");
|
||||
dispatch_description.motionVectors =
|
||||
GetFfxResource(m_motion, L"FSR2 Input Motion");
|
||||
dispatch_description.exposure =
|
||||
GetFfxResource(nullptr, L"FSR2 Empty Auto Exposure");
|
||||
dispatch_description.reactive =
|
||||
GetFfxResource(nullptr, L"FSR2 Empty Input Reactive Map");
|
||||
dispatch_description.transparencyAndComposition =
|
||||
GetFfxResource(nullptr, L"FSR2 Empty Transparency And Composition Map");
|
||||
dispatch_description.output = GetFfxResource(
|
||||
m_output, L"FSR2 Output", FFX_RESOURCE_STATE_UNORDERED_ACCESS);
|
||||
|
||||
dispatch_description.jitterOffset.x = m_current_jitter.x;
|
||||
dispatch_description.jitterOffset.y = m_current_jitter.y;
|
||||
dispatch_description.motionVectorScale.x = static_cast<float>(m_input_width);
|
||||
dispatch_description.motionVectorScale.y = static_cast<float>(m_input_height);
|
||||
dispatch_description.reset = false;
|
||||
dispatch_description.enableSharpening = true;
|
||||
dispatch_description.sharpness = .4;
|
||||
dispatch_description.frameTimeDelta = 10.f;
|
||||
dispatch_description.preExposure = 1.0f;
|
||||
dispatch_description.renderSize.width = m_input_width;
|
||||
dispatch_description.renderSize.height = m_input_height;
|
||||
dispatch_description.cameraFar = far_plane;
|
||||
dispatch_description.cameraNear = near_plane;
|
||||
dispatch_description.cameraFovAngleVertical = fov;
|
||||
|
||||
ffxFsr2ContextDispatch(&m_fsr2_context, &dispatch_description);
|
||||
command_list->clearState();
|
||||
}
|
||||
|
||||
FfxResource NvFSR::GetFfxResource(nvrhi::ITexture* texture, wchar_t const* name,
|
||||
FfxResourceStates state) {
|
||||
switch (m_backend->GetDevice()->getGraphicsAPI()) {
|
||||
#if LIBMANUL_WITH_D3D12
|
||||
case nvrhi::GraphicsAPI::D3D12:
|
||||
if (!texture) {
|
||||
return ffxGetResourceDX12(&m_fsr2_context, nullptr, name, state);
|
||||
}
|
||||
return ffxGetResourceDX12(
|
||||
&m_fsr2_context,
|
||||
texture->getNativeObject(nvrhi::ObjectTypes::D3D12_Resource), name,
|
||||
state);
|
||||
#endif
|
||||
#if LIBMANUL_WITH_VULKAN
|
||||
case nvrhi::GraphicsAPI::VULKAN: {
|
||||
if (!texture) {
|
||||
return ffxGetTextureResourceVK(&m_fsr2_context, nullptr, nullptr, 1, 1,
|
||||
VK_FORMAT_UNDEFINED, name, state);
|
||||
}
|
||||
const auto& desc = texture->getDesc();
|
||||
return ffxGetTextureResourceVK(
|
||||
&m_fsr2_context,
|
||||
texture->getNativeObject(nvrhi::ObjectTypes::VK_Image),
|
||||
texture->getNativeView(nvrhi::ObjectTypes::VK_ImageView), desc.width,
|
||||
desc.height, nvrhi::vulkan::convertFormat(desc.format), name, state);
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
void NvFSR::BeginFrame() {
|
||||
++m_current_frame;
|
||||
ComputeJitter();
|
||||
}
|
||||
|
||||
glm::dmat4 NvFSR::GetJitterMatrix() const {
|
||||
return glm::translate(glm::dvec3(2. * m_current_jitter.x / m_input_width,
|
||||
-2. * m_current_jitter.y / m_input_height,
|
||||
0.));
|
||||
}
|
||||
|
||||
void NvFSR::ComputeJitter() {
|
||||
int phase_count = ffxFsr2GetJitterPhaseCount(m_input_width, m_width);
|
||||
ffxFsr2GetJitterOffset(&m_current_jitter.x, &m_current_jitter.y,
|
||||
m_current_frame % phase_count, phase_count);
|
||||
}
|
||||
45
manul/renderer/source/fsr.h
Normal file
45
manul/renderer/source/fsr.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
|
||||
#include <ffx-fsr2-api/ffx_fsr2.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
struct NvFSR {
|
||||
NvFSR(class NvRenderer* renderer);
|
||||
void Init();
|
||||
void Render(nvrhi::ICommandList* command_list, double far_plane,
|
||||
double near_plane, double fov);
|
||||
|
||||
FfxFsr2Interface m_fsr2_interface;
|
||||
FfxFsr2Context m_fsr2_context;
|
||||
std::string m_scratch_buffer;
|
||||
|
||||
nvrhi::ITexture* m_color;
|
||||
nvrhi::ITexture* m_auto_exposure_buffer;
|
||||
nvrhi::ITexture* m_depth;
|
||||
nvrhi::ITexture* m_motion;
|
||||
nvrhi::TextureHandle m_output;
|
||||
|
||||
FfxResource GetFfxResource(
|
||||
nvrhi::ITexture* texture, wchar_t const* name = nullptr,
|
||||
FfxResourceStates state = FFX_RESOURCE_STATE_COMPUTE_READ);
|
||||
|
||||
int m_input_width;
|
||||
int m_input_height;
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
glm::vec2 m_current_jitter;
|
||||
|
||||
class NvRendererBackend* m_backend;
|
||||
struct NvGbuffer* m_gbuffer;
|
||||
struct GbufferBlitPass* m_inputpass;
|
||||
struct MaAutoExposure* m_auto_exposure;
|
||||
|
||||
size_t m_current_frame = 0;
|
||||
|
||||
void BeginFrame();
|
||||
glm::dmat4 GetJitterMatrix() const;
|
||||
void ComputeJitter();
|
||||
};
|
||||
96
manul/renderer/source/fullscreenpass.cpp
Normal file
96
manul/renderer/source/fullscreenpass.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
#include "fullscreenpass.h"
|
||||
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
FullScreenPass::FullScreenPass(NvRendererBackend* backend)
|
||||
: m_backend(backend) {}
|
||||
|
||||
nvrhi::IShader* FullScreenPass::GetVertexShader() {
|
||||
static nvrhi::ShaderHandle vertex_shader = nullptr;
|
||||
if (!vertex_shader)
|
||||
vertex_shader = m_backend->CreateShader("fx_vertex", nvrhi::ShaderType::Vertex);
|
||||
return vertex_shader;
|
||||
}
|
||||
|
||||
nvrhi::IInputLayout* FullScreenPass::GetInputLayout() {
|
||||
static nvrhi::InputLayoutHandle input_layout = nullptr;
|
||||
if (!input_layout) {
|
||||
nvrhi::VertexAttributeDesc attribute_desc =
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setName("Position")
|
||||
.setElementStride(sizeof(glm::vec2))
|
||||
.setOffset(0)
|
||||
.setFormat(nvrhi::Format::RG32_FLOAT)
|
||||
.setBufferIndex(0)
|
||||
.setIsInstanced(false);
|
||||
input_layout = m_backend->GetDevice()->createInputLayout(&attribute_desc, 1,
|
||||
GetVertexShader());
|
||||
}
|
||||
return input_layout;
|
||||
}
|
||||
|
||||
nvrhi::IBuffer* FullScreenPass::GetVertexBuffer() {
|
||||
static nvrhi::BufferHandle vertex_buffer = nullptr;
|
||||
if (!vertex_buffer) {
|
||||
glm::vec2 vertices[]{{0.f, 0.f}, {1.f, 0.f}, {0.f, 1.f}, {1.f, 1.f}};
|
||||
vertex_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc()
|
||||
.setIsVertexBuffer(true)
|
||||
.setByteSize(sizeof(vertices))
|
||||
.setInitialState(nvrhi::ResourceStates::VertexBuffer)
|
||||
.setKeepInitialState(true)
|
||||
.setCpuAccess(nvrhi::CpuAccessMode::Write));
|
||||
void* map = m_backend->GetDevice()->mapBuffer(vertex_buffer,
|
||||
nvrhi::CpuAccessMode::Write);
|
||||
memcpy(map, vertices, sizeof(vertices));
|
||||
m_backend->GetDevice()->unmapBuffer(vertex_buffer);
|
||||
}
|
||||
return vertex_buffer;
|
||||
}
|
||||
|
||||
void FullScreenPass::Init() { CreatePipeline(); }
|
||||
|
||||
void FullScreenPass::CreatePipeline() {
|
||||
nvrhi::GraphicsPipelineDesc pipeline_desc;
|
||||
CreatePipelineDesc(pipeline_desc);
|
||||
m_pipeline = m_backend->GetDevice()->createGraphicsPipeline(pipeline_desc,
|
||||
GetFramebuffer());
|
||||
}
|
||||
|
||||
void FullScreenPass::CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) {
|
||||
pipeline_desc.setVertexShader(GetVertexShader())
|
||||
.setInputLayout(GetInputLayout())
|
||||
.setPrimType(nvrhi::PrimitiveType::TriangleStrip)
|
||||
.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget().disableBlend()))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setCullNone()
|
||||
.disableScissor()
|
||||
.disableDepthClip()
|
||||
.setFillSolid())
|
||||
.setDepthStencilState(nvrhi::DepthStencilState()
|
||||
.disableDepthTest()
|
||||
.disableDepthWrite()
|
||||
.disableStencil()));
|
||||
}
|
||||
|
||||
nvrhi::IFramebuffer* FullScreenPass::GetFramebuffer() { return m_backend->GetCurrentFramebuffer(); }
|
||||
|
||||
void FullScreenPass::InitState(nvrhi::GraphicsState& render_state) {
|
||||
nvrhi::IFramebuffer* framebuffer = GetFramebuffer();
|
||||
render_state.setFramebuffer(framebuffer);
|
||||
render_state.setViewport(nvrhi::ViewportState().addViewportAndScissorRect(
|
||||
framebuffer->getFramebufferInfo().getViewport()));
|
||||
render_state.setPipeline(m_pipeline);
|
||||
render_state.addVertexBuffer(
|
||||
nvrhi::VertexBufferBinding().setSlot(0).setBuffer(GetVertexBuffer()));
|
||||
}
|
||||
|
||||
void FullScreenPass::Draw(nvrhi::ICommandList* command_list) {
|
||||
command_list->draw(nvrhi::DrawArguments().setVertexCount(4));
|
||||
}
|
||||
21
manul/renderer/source/fullscreenpass.h
Normal file
21
manul/renderer/source/fullscreenpass.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
struct FullScreenPass {
|
||||
|
||||
FullScreenPass(class NvRendererBackend* backend);
|
||||
virtual ~FullScreenPass() = default;
|
||||
nvrhi::IShader* GetVertexShader();
|
||||
nvrhi::IInputLayout* GetInputLayout();
|
||||
nvrhi::IBuffer* GetVertexBuffer();
|
||||
virtual void Init();
|
||||
void CreatePipeline();
|
||||
virtual void CreatePipelineDesc(nvrhi::GraphicsPipelineDesc& pipeline_desc);
|
||||
nvrhi::GraphicsPipelineHandle m_pipeline;
|
||||
class NvRendererBackend* m_backend;
|
||||
virtual nvrhi::IFramebuffer* GetFramebuffer();
|
||||
void InitState(nvrhi::GraphicsState& render_state);
|
||||
void Draw(nvrhi::ICommandList* command_list);
|
||||
virtual void Render(nvrhi::ICommandList* command_list) = 0;
|
||||
};
|
||||
117
manul/renderer/source/gbuffer.cpp
Normal file
117
manul/renderer/source/gbuffer.cpp
Normal file
@@ -0,0 +1,117 @@
|
||||
#include "gbuffer.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
NvGbuffer::NvGbuffer(NvRenderer* renderer)
|
||||
: m_backend(renderer->m_backend.get()) {}
|
||||
|
||||
void NvGbuffer::Init(int width, int height, bool is_cube, bool depth_only,
|
||||
int slices) {
|
||||
m_depth_only = depth_only;
|
||||
nvrhi::TextureDesc buffer_desc =
|
||||
nvrhi::TextureDesc()
|
||||
.setWidth(width)
|
||||
.setHeight(height)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setIsRenderTarget(true)
|
||||
.setKeepInitialState(true)
|
||||
.setClearValue(nvrhi::Color(0.f, 0.f, 0.f, 0.f))
|
||||
.setUseClearValue(true);
|
||||
if (is_cube) {
|
||||
buffer_desc.setDimension(nvrhi::TextureDimension::TextureCube);
|
||||
buffer_desc.setArraySize(6);
|
||||
} else if (slices > 1) {
|
||||
buffer_desc.setDimension(nvrhi::TextureDimension::Texture2DArray);
|
||||
buffer_desc.setArraySize(slices);
|
||||
}
|
||||
if (!depth_only) {
|
||||
m_gbuffer_diffuse = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(buffer_desc)
|
||||
.setFormat(nvrhi::Format::R10G10B10A2_UNORM)
|
||||
.setDebugName("GBuffer Diffuse"));
|
||||
m_gbuffer_emission = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(buffer_desc)
|
||||
.setFormat(nvrhi::Format::RGBA16_FLOAT)
|
||||
.setDebugName("GBuffer Emission"));
|
||||
m_gbuffer_params = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(buffer_desc)
|
||||
.setFormat(nvrhi::Format::RGBA8_UNORM)
|
||||
.setDebugName("GBuffer Params"));
|
||||
m_gbuffer_normal = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(buffer_desc)
|
||||
.setFormat(nvrhi::Format::R10G10B10A2_UNORM)
|
||||
.setClearValue(nvrhi::Color(.5f, .5f, 1.f, 0.f))
|
||||
.setDebugName("GBuffer Normal"));
|
||||
m_gbuffer_motion = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(buffer_desc)
|
||||
.setFormat(nvrhi::Format::RG16_FLOAT)
|
||||
.setClearValue(nvrhi::Color(0.f, 0.f, 0.f, 0.f))
|
||||
.setDebugName("GBuffer Motion"));
|
||||
}
|
||||
m_gbuffer_depth = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(buffer_desc)
|
||||
.setIsTypeless(true)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setFormat(nvrhi::Format::D32)
|
||||
.setDebugName("GBuffer Deph"));
|
||||
nvrhi::TextureSubresourceSet subresource_set =
|
||||
nvrhi::TextureSubresourceSet(0, 1, 0, buffer_desc.arraySize);
|
||||
nvrhi::FramebufferDesc fb_desc = nvrhi::FramebufferDesc().setDepthAttachment(
|
||||
m_gbuffer_depth, subresource_set);
|
||||
if (!depth_only) {
|
||||
fb_desc.addColorAttachment(m_gbuffer_diffuse, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_emission, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_params, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_normal, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_motion, subresource_set);
|
||||
}
|
||||
m_framebuffer = m_backend->GetDevice()->createFramebuffer(fb_desc);
|
||||
m_slice_framebuffers.resize(buffer_desc.arraySize);
|
||||
for (int i = 0; i < buffer_desc.arraySize; ++i) {
|
||||
nvrhi::TextureSubresourceSet subresource_set =
|
||||
nvrhi::TextureSubresourceSet(0, 1, i, 1);
|
||||
nvrhi::FramebufferDesc fb_desc =
|
||||
nvrhi::FramebufferDesc().setDepthAttachment(m_gbuffer_depth,
|
||||
subresource_set);
|
||||
if (!depth_only) {
|
||||
fb_desc.addColorAttachment(m_gbuffer_diffuse, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_emission, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_params, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_normal, subresource_set)
|
||||
.addColorAttachment(m_gbuffer_motion, subresource_set);
|
||||
}
|
||||
m_slice_framebuffers[i] =
|
||||
m_backend->GetDevice()->createFramebuffer(fb_desc);
|
||||
}
|
||||
}
|
||||
|
||||
void NvGbuffer::Clear(nvrhi::ICommandList* command_list) {
|
||||
if (!m_depth_only) {
|
||||
nvrhi::utils::ClearColorAttachment(command_list, m_framebuffer, 0,
|
||||
nvrhi::Color(0.f, 0.f, 0.f, 0.f));
|
||||
nvrhi::utils::ClearColorAttachment(command_list, m_framebuffer, 1,
|
||||
nvrhi::Color(0.f, 0.f, 0.f, 0.f));
|
||||
nvrhi::utils::ClearColorAttachment(command_list, m_framebuffer, 2,
|
||||
nvrhi::Color(0.f, 0.f, 0.f, 0.f));
|
||||
nvrhi::utils::ClearColorAttachment(command_list, m_framebuffer, 3,
|
||||
nvrhi::Color(.5f, .5f, 1.f, 0.f));
|
||||
nvrhi::utils::ClearColorAttachment(command_list, m_framebuffer, 4,
|
||||
nvrhi::Color(0.f, 0.f, 0.f, 0.f));
|
||||
}
|
||||
ClearDepthStencilAttachment(command_list, m_framebuffer,
|
||||
m_depth_only ? 0.f : 0.f, 0);
|
||||
}
|
||||
|
||||
void NvGbuffer::ClearDepthStencilAttachment(nvrhi::ICommandList* commandList,
|
||||
nvrhi::IFramebuffer* framebuffer,
|
||||
float depth, uint32_t stencil) {
|
||||
const nvrhi::FramebufferAttachment& att =
|
||||
framebuffer->getDesc().depthAttachment;
|
||||
if (att.texture) {
|
||||
commandList->clearDepthStencilTexture(att.texture, att.subresources, true,
|
||||
depth, false, stencil);
|
||||
}
|
||||
}
|
||||
27
manul/renderer/source/gbuffer.h
Normal file
27
manul/renderer/source/gbuffer.h
Normal file
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
struct NvGbuffer {
|
||||
NvGbuffer(class NvRenderer* renderer);
|
||||
void Init(int width, int height, bool is_cube, bool depth_only = false, int slices = 1);
|
||||
void Clear(nvrhi::ICommandList* command_list);
|
||||
|
||||
nvrhi::TextureHandle m_gbuffer_diffuse;
|
||||
nvrhi::TextureHandle m_gbuffer_emission;
|
||||
nvrhi::TextureHandle m_gbuffer_normal;
|
||||
nvrhi::TextureHandle m_gbuffer_params;
|
||||
nvrhi::TextureHandle m_gbuffer_motion;
|
||||
nvrhi::TextureHandle m_gbuffer_depth;
|
||||
|
||||
nvrhi::FramebufferHandle m_framebuffer;
|
||||
std::vector<nvrhi::FramebufferHandle> m_slice_framebuffers;
|
||||
|
||||
class NvRendererBackend* m_backend;
|
||||
|
||||
bool m_depth_only;
|
||||
|
||||
static void ClearDepthStencilAttachment(nvrhi::ICommandList* commandList,
|
||||
nvrhi::IFramebuffer* framebuffer,
|
||||
float depth, uint32_t stencil);
|
||||
};
|
||||
209
manul/renderer/source/gbufferblitpass.cpp
Normal file
209
manul/renderer/source/gbufferblitpass.cpp
Normal file
@@ -0,0 +1,209 @@
|
||||
#include "gbufferblitpass.h"
|
||||
|
||||
#include <chrono>
|
||||
#include <Timer.h>
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "contactshadows.h"
|
||||
#include "csm.h"
|
||||
#include "environment.h"
|
||||
#include "gbuffer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
#include "sky.h"
|
||||
#include "ssao.h"
|
||||
|
||||
GbufferBlitPass::GbufferBlitPass(NvRenderer* renderer, NvGbuffer* gbuffer,
|
||||
NvGbuffer* gbuffer_shadow, NvSsao* ssao,
|
||||
MaEnvironment* environment,
|
||||
MaShadowMap* shadow_map,
|
||||
MaContactShadows* contact_shadows, Sky* sky)
|
||||
: FullScreenPass(renderer->GetBackend()),
|
||||
MaResourceRegistry(renderer),
|
||||
m_gbuffer(gbuffer),
|
||||
m_gbuffer_shadow(gbuffer_shadow),
|
||||
m_ssao(ssao),
|
||||
m_environment(environment),
|
||||
m_shadow_map(shadow_map),
|
||||
m_contact_shadows(contact_shadows),
|
||||
m_sky(sky) {}
|
||||
|
||||
void GbufferBlitPass::Init() {
|
||||
InitResourceRegistry();
|
||||
m_draw_constants = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc(
|
||||
sizeof(DrawConstants), "GBuffer Lighting Constants", 16)
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
RegisterResource(true, "gbuffer_lighting_constants", m_draw_constants,
|
||||
nvrhi::ResourceType::VolatileConstantBuffer);
|
||||
const nvrhi::SamplerHandle sampler_shadow_comp =
|
||||
m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setReductionType(nvrhi::SamplerReductionType::Comparison)
|
||||
.setComparisonFunc(nvrhi::ComparisonFunc::Greater)
|
||||
.setAllAddressModes(nvrhi::SamplerAddressMode::ClampToEdge)
|
||||
.setAllFilters(true));
|
||||
const nvrhi::SamplerHandle sampler_linear =
|
||||
m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc().setAllFilters(true));
|
||||
const nvrhi::SamplerHandle sampler_linear_clamp =
|
||||
m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(nvrhi::SamplerAddressMode::ClampToEdge)
|
||||
.setAllFilters(true));
|
||||
RegisterResource(true, "shadow_sampler_comp", sampler_shadow_comp,
|
||||
nvrhi::ResourceType::Sampler);
|
||||
RegisterResource(true, "sampler_linear_wrap", sampler_linear,
|
||||
nvrhi::ResourceType::Sampler);
|
||||
RegisterResource(true, "sampler_linear_clamp", sampler_linear_clamp,
|
||||
nvrhi::ResourceType::Sampler);
|
||||
m_scene_depth = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(m_gbuffer->m_gbuffer_depth->getDesc())
|
||||
.setFormat(nvrhi::Format::R32_FLOAT)
|
||||
.setDebugName("Scene Depth")
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setUseClearValue(false)
|
||||
.setIsRenderTarget(false));
|
||||
RegisterResource(true, "gbuffer_depth", m_scene_depth,
|
||||
nvrhi::ResourceType::Texture_SRV);
|
||||
m_output = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setWidth(m_gbuffer->m_framebuffer->getFramebufferInfo().width)
|
||||
.setHeight(m_gbuffer->m_framebuffer->getFramebufferInfo().height)
|
||||
.setFormat(nvrhi::Format::RGBA16_FLOAT)
|
||||
.setIsUAV(true)
|
||||
.setIsRenderTarget(true)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
RegisterResource(true, "scene_lit_texture", m_output,
|
||||
nvrhi::ResourceType::Texture_SRV);
|
||||
m_binding_layout = m_backend->GetDevice()->createBindingLayout(
|
||||
nvrhi::BindingLayoutDesc()
|
||||
.addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(2))
|
||||
.addItem(nvrhi::BindingLayoutItem::ConstantBuffer(11))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(1))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(2))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(3))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(4))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(5))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(8))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(9))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(10))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(11))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(12))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(14))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(16))
|
||||
.addItem(nvrhi::BindingLayoutItem::StructuredBuffer_SRV(17))
|
||||
.addItem(nvrhi::BindingLayoutItem::StructuredBuffer_SRV(18))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(8))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(11))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(13))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_UAV(0))
|
||||
.setVisibility(nvrhi::ShaderType::Compute));
|
||||
for (int i = 0; i < std::size(m_binding_set); ++i) {
|
||||
m_binding_set[i] = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(2, m_draw_constants))
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
|
||||
11, m_shadow_map->m_projection_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
0, m_gbuffer->m_gbuffer_diffuse))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
1, m_gbuffer->m_gbuffer_emission))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
2, m_gbuffer->m_gbuffer_params))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
3, m_gbuffer->m_gbuffer_normal))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
4, m_gbuffer->m_gbuffer_depth))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(5, m_ssao->m_outputAO))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
8, m_environment->m_dynamic_envmap_diffuse[0]))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
9, m_environment->m_dynamic_envmap_specular[0]))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
10, m_environment->m_brdf_lut))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
11, m_gbuffer_shadow->m_gbuffer_depth))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
12, m_contact_shadows->m_output_texture))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
14, m_sky->m_aerial_lut->m_lut))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
16, static_cast<nvrhi::ITexture*>(
|
||||
GetResource("forwardplus_index_grid_opaque", nvrhi::ResourceType::Texture_SRV)
|
||||
.m_resource)))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_SRV(
|
||||
17, static_cast<nvrhi::IBuffer*>(
|
||||
GetResource("forwardplus_index_buffer_opaque", nvrhi::ResourceType::StructuredBuffer_SRV)
|
||||
.m_resource)))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_SRV(
|
||||
18, static_cast<nvrhi::IBuffer*>(
|
||||
GetResource("forwardplus_light_buffer", nvrhi::ResourceType::StructuredBuffer_SRV)
|
||||
.m_resource)))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(8, sampler_linear))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(11, sampler_shadow_comp))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(13, sampler_linear_clamp))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(0, m_output)),
|
||||
m_binding_layout);
|
||||
}
|
||||
m_pixel_shader =
|
||||
m_backend->CreateShader("gbuffer_lighting", nvrhi::ShaderType::Compute);
|
||||
m_pso = m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.setComputeShader(m_pixel_shader)
|
||||
.addBindingLayout(m_binding_layout));
|
||||
// m_framebuffer = m_backend->GetDevice()->createFramebuffer(
|
||||
// nvrhi::FramebufferDesc().addColorAttachment(m_output));
|
||||
// FullScreenPass::Init();
|
||||
}
|
||||
|
||||
void GbufferBlitPass::CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) {
|
||||
FullScreenPass::CreatePipelineDesc(pipeline_desc);
|
||||
pipeline_desc.addBindingLayout(m_binding_layout);
|
||||
pipeline_desc.setPixelShader(m_pixel_shader);
|
||||
}
|
||||
|
||||
void GbufferBlitPass::UpdateConstants(nvrhi::ICommandList* command_list,
|
||||
glm::dmat4& view,
|
||||
const glm::dmat4& projection) {
|
||||
DrawConstants constants{};
|
||||
constants.m_inverse_model_view = glm::inverse(glm::dmat4(glm::dmat3(view)));
|
||||
constants.m_inverse_projection = glm::inverse(projection);
|
||||
|
||||
const auto& daylight = Global.DayLight;
|
||||
constants.m_light_dir = glm::vec4(-daylight.direction, 0.f);
|
||||
constants.m_light_color = glm::vec4(m_sky->CalcSunColor(), 1.);
|
||||
constants.m_altitude = Global.pCamera.Pos.y;
|
||||
constants.m_time = Timer::GetTime();
|
||||
|
||||
command_list->writeBuffer(m_draw_constants, &constants, sizeof(constants));
|
||||
}
|
||||
|
||||
void GbufferBlitPass::Render(nvrhi::ICommandList* command_list,
|
||||
glm::dmat4& view, const glm::dmat4& projection) {
|
||||
UpdateConstants(command_list, view, projection);
|
||||
Render(command_list);
|
||||
command_list->copyTexture(
|
||||
m_scene_depth, nvrhi::TextureSlice().resolve(m_scene_depth->getDesc()),
|
||||
m_gbuffer->m_gbuffer_depth,
|
||||
nvrhi::TextureSlice().resolve(m_scene_depth->getDesc()));
|
||||
}
|
||||
|
||||
void GbufferBlitPass::Render(nvrhi::ICommandList* command_list) {
|
||||
nvrhi::ComputeState graphics_state;
|
||||
auto desc = m_output->getDesc();
|
||||
// InitState(graphics_state);
|
||||
graphics_state.setPipeline(m_pso);
|
||||
graphics_state.addBindingSet(
|
||||
m_binding_set[m_environment->GetCurrentSetIndex()]);
|
||||
command_list->setComputeState(graphics_state);
|
||||
#define DISPATCH_SIZE(size, groupsize) ((size + groupsize - 1) / groupsize)
|
||||
command_list->dispatch(DISPATCH_SIZE(desc.width, 8),
|
||||
DISPATCH_SIZE(desc.height, 8), 1);
|
||||
// Draw(command_list);
|
||||
}
|
||||
|
||||
nvrhi::IFramebuffer* GbufferBlitPass::GetFramebuffer() { return m_framebuffer; }
|
||||
53
manul/renderer/source/gbufferblitpass.h
Normal file
53
manul/renderer/source/gbufferblitpass.h
Normal file
@@ -0,0 +1,53 @@
|
||||
#pragma once
|
||||
|
||||
#include "fullscreenpass.h"
|
||||
#include "nvrenderer/resource_registry.h"
|
||||
|
||||
struct GbufferBlitPass : public FullScreenPass, public MaResourceRegistry {
|
||||
GbufferBlitPass(class NvRenderer* renderer, struct NvGbuffer* gbuffer,
|
||||
struct NvGbuffer* gbuffer_shadow, struct NvSsao* ssao,
|
||||
struct MaEnvironment* environment,
|
||||
struct MaShadowMap* shadow_map,
|
||||
struct MaContactShadows* contact_shadows, struct Sky* sky);
|
||||
|
||||
virtual void Init() override;
|
||||
|
||||
virtual void CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) override;
|
||||
|
||||
void UpdateConstants(nvrhi::ICommandList* command_list, glm::dmat4& view,
|
||||
const glm::dmat4& projection);
|
||||
|
||||
void Render(nvrhi::ICommandList* command_list, glm::dmat4& view,
|
||||
const glm::dmat4& projection);
|
||||
virtual void Render(nvrhi::ICommandList* command_list) override;
|
||||
|
||||
struct DrawConstants {
|
||||
glm::mat4 m_inverse_model_view;
|
||||
glm::mat4 m_inverse_projection;
|
||||
glm::vec3 m_light_dir;
|
||||
float m_altitude;
|
||||
glm::vec4 m_light_color;
|
||||
float m_time;
|
||||
};
|
||||
|
||||
nvrhi::BindingLayoutHandle m_binding_layout;
|
||||
nvrhi::BindingSetHandle m_binding_set[2];
|
||||
nvrhi::ShaderHandle m_pixel_shader;
|
||||
nvrhi::FramebufferHandle m_framebuffer;
|
||||
nvrhi::BufferHandle m_draw_constants;
|
||||
nvrhi::TextureHandle m_scene_depth;
|
||||
|
||||
NvGbuffer* m_gbuffer;
|
||||
NvGbuffer* m_gbuffer_shadow;
|
||||
NvSsao* m_ssao;
|
||||
MaEnvironment* m_environment;
|
||||
MaShadowMap* m_shadow_map;
|
||||
MaContactShadows* m_contact_shadows;
|
||||
Sky* m_sky;
|
||||
|
||||
nvrhi::ComputePipelineHandle m_pso;
|
||||
|
||||
nvrhi::TextureHandle m_output;
|
||||
virtual nvrhi::IFramebuffer* GetFramebuffer() override;
|
||||
};
|
||||
365
manul/renderer/source/gbufferlighting.cpp
Normal file
365
manul/renderer/source/gbufferlighting.cpp
Normal file
@@ -0,0 +1,365 @@
|
||||
#include "gbufferlighting.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include <glm/gtc/packing.hpp>
|
||||
|
||||
#include "gbuffer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
#include "ssao.h"
|
||||
#include "config.h"
|
||||
|
||||
void GbufferLighting::Init() {
|
||||
auto fb_info = m_renderer->m_gbuffer->m_framebuffer->getFramebufferInfo();
|
||||
m_width = fb_info.width;
|
||||
m_height = fb_info.height;
|
||||
|
||||
m_tiles_x = (m_width + 7) / 8;
|
||||
m_tiles_y = (m_height + 7) / 8;
|
||||
|
||||
m_frustum_buffer = m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc()
|
||||
.setDebugName("Forward Plus Frustum Buffer")
|
||||
.setStructStride(4 * sizeof(glm::vec4) + 10 * sizeof(float))
|
||||
.setByteSize(m_tiles_x * m_tiles_y * (4 * sizeof(glm::vec4) + 10 * sizeof(float)))
|
||||
.setCanHaveUAVs(true)
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_view_params_buffer = m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc(
|
||||
sizeof(ViewParams), "Forward Plus View Parameters", 16)
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_dispatch_params_buffer =
|
||||
m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc(
|
||||
sizeof(ViewParams), "Forward Plus Dispatch Parameters", 16)
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
{
|
||||
auto atomic_counter_desc =
|
||||
nvrhi::BufferDesc()
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setStructStride(sizeof(uint32_t))
|
||||
.setKeepInitialState(true)
|
||||
.setByteSize(sizeof(uint32_t))
|
||||
.setCanHaveUAVs(true);
|
||||
|
||||
m_atomic_counter_lights_opaque =
|
||||
m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc(atomic_counter_desc)
|
||||
.setDebugName("Forward Plus Atomic Counter Lights Opaque"));
|
||||
|
||||
m_atomic_counter_lights_transparent =
|
||||
m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc(atomic_counter_desc)
|
||||
.setDebugName(
|
||||
"Forward Plus Atomic Counter Lights Transparent"));
|
||||
}
|
||||
|
||||
{
|
||||
auto index_buffer_desc =
|
||||
nvrhi::BufferDesc()
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setStructStride(sizeof(uint32_t))
|
||||
.setKeepInitialState(true)
|
||||
.setByteSize(sizeof(uint32_t) * m_tiles_x * m_tiles_y * 64)
|
||||
.setCanHaveUAVs(true);
|
||||
|
||||
m_index_buffer_lights_opaque =
|
||||
m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc(index_buffer_desc)
|
||||
.setDebugName("Forward Plus Index Buffer Lights Opaque"));
|
||||
|
||||
m_index_buffer_lights_transparent =
|
||||
m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc(index_buffer_desc)
|
||||
.setDebugName("Forward Plus Index Buffer Lights Transparent"));
|
||||
}
|
||||
|
||||
{
|
||||
auto index_grid_desc =
|
||||
nvrhi::TextureDesc()
|
||||
.setInitialState(nvrhi::ResourceStates::UnorderedAccess)
|
||||
.setFormat(nvrhi::Format::RG32_UINT)
|
||||
.setKeepInitialState(true)
|
||||
.setWidth(m_tiles_x)
|
||||
.setHeight(m_tiles_y)
|
||||
.setIsUAV(true);
|
||||
|
||||
m_index_grid_lights_opaque =
|
||||
m_renderer->GetBackend()->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(index_grid_desc)
|
||||
.setDebugName("Forward Plus Index Grid Lights Opaque"));
|
||||
|
||||
m_index_grid_lights_transparent =
|
||||
m_renderer->GetBackend()->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc(index_grid_desc)
|
||||
.setDebugName("Forward Plus Index Grid Lights Transparent"));
|
||||
}
|
||||
|
||||
{
|
||||
m_lighting_buffer_capacity =
|
||||
NvRenderer::Config()->m_lighting.m_max_lights_per_scene;
|
||||
m_light_buffer = m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
nvrhi::BufferDesc()
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true)
|
||||
.setByteSize(m_lighting_buffer_capacity *
|
||||
sizeof(m_packed_buffer[0]))
|
||||
.setStructStride(sizeof(m_packed_buffer[0]))
|
||||
.setDebugName("Light Buffer"));
|
||||
}
|
||||
|
||||
RegisterResource(true, "forwardplus_light_buffer", m_light_buffer,
|
||||
nvrhi::ResourceType::StructuredBuffer_SRV);
|
||||
RegisterResource(true, "forwardplus_index_grid_opaque",
|
||||
m_index_grid_lights_opaque,
|
||||
nvrhi::ResourceType::Texture_SRV);
|
||||
RegisterResource(true, "forwardplus_index_grid_transparent",
|
||||
m_index_grid_lights_transparent,
|
||||
nvrhi::ResourceType::Texture_SRV);
|
||||
RegisterResource(true, "forwardplus_index_buffer_opaque",
|
||||
m_index_buffer_lights_opaque,
|
||||
nvrhi::ResourceType::StructuredBuffer_SRV);
|
||||
RegisterResource(true, "forwardplus_index_buffer_transparent",
|
||||
m_index_buffer_lights_transparent,
|
||||
nvrhi::ResourceType::StructuredBuffer_SRV);
|
||||
|
||||
{
|
||||
nvrhi::BindingLayoutHandle binding_layout_comp_frustums;
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_renderer->GetBackend()->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(3, m_view_params_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
|
||||
4, m_dispatch_params_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_UAV(
|
||||
0, m_frustum_buffer)),
|
||||
binding_layout_comp_frustums, m_bindings_comp_frustums);
|
||||
|
||||
auto cs_comp_frustums = m_renderer->m_backend->CreateShader(
|
||||
"forwardplus_compute_frustums", nvrhi::ShaderType::Compute);
|
||||
|
||||
m_pso_comp_frustums =
|
||||
m_renderer->GetBackend()->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.addBindingLayout(binding_layout_comp_frustums)
|
||||
.setComputeShader(cs_comp_frustums));
|
||||
}
|
||||
|
||||
{
|
||||
nvrhi::BindingLayoutHandle binding_layout_cull_lights;
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_renderer->GetBackend()->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(3, m_view_params_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
|
||||
4, m_dispatch_params_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
3, m_renderer->m_gbuffer->m_gbuffer_depth))
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::StructuredBuffer_SRV(8, m_light_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_SRV(
|
||||
9, m_frustum_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_UAV(
|
||||
1, m_atomic_counter_lights_opaque))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_UAV(
|
||||
2, m_atomic_counter_lights_transparent))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_UAV(
|
||||
3, m_index_buffer_lights_opaque))
|
||||
.addItem(nvrhi::BindingSetItem::StructuredBuffer_UAV(
|
||||
4, m_index_buffer_lights_transparent))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
5, m_index_grid_lights_opaque))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
6, m_index_grid_lights_transparent)),
|
||||
binding_layout_cull_lights, m_bindings_cull_lights);
|
||||
|
||||
auto cs_cull_lights = m_renderer->m_backend->CreateShader(
|
||||
"forwardplus_cull_lights", nvrhi::ShaderType::Compute);
|
||||
|
||||
m_pso_cull_lights =
|
||||
m_renderer->GetBackend()->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.addBindingLayout(binding_layout_cull_lights)
|
||||
.setComputeShader(cs_cull_lights));
|
||||
}
|
||||
|
||||
// auto texture_desc =
|
||||
// nvrhi::TextureDesc()
|
||||
// .setWidth(m_width)
|
||||
// .setHeight(m_height)
|
||||
// .setFormat(nvrhi::Format::R11G11B10_FLOAT)
|
||||
// .setIsUAV(true)
|
||||
// .setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
// .setKeepInitialState(true);
|
||||
//texture_desc
|
||||
// texture_desc.setDebugName("Deferred Diffuse Buffer");
|
||||
// m_diffuse_texture =
|
||||
// m_renderer->GetBackend()->GetDevice()->createTexture(texture_desc);
|
||||
// RegisterResource(true, "deferred_lights", m_diffuse_texture,
|
||||
// nvrhi::ResourceType::Texture_SRV);
|
||||
//
|
||||
// m_view_constants = m_renderer->GetBackend()->GetDevice()->createBuffer(
|
||||
// nvrhi::utils::CreateVolatileConstantBufferDesc(
|
||||
// sizeof(ViewConstants), "Deferred Lighting Constants", 16)
|
||||
// .setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
// .setKeepInitialState(true));
|
||||
//
|
||||
// nvrhi::BindingLayoutHandle binding_layout_spot;
|
||||
// nvrhi::BindingLayoutHandle binding_layout_clear;
|
||||
//
|
||||
// nvrhi::utils::CreateBindingSetAndLayout(
|
||||
// m_renderer->GetBackend()->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
// nvrhi::BindingSetDesc().addItem(
|
||||
// nvrhi::BindingSetItem::Texture_UAV(0, m_diffuse_texture)),
|
||||
// binding_layout_clear, m_binding_set_clear);
|
||||
//
|
||||
// nvrhi::utils::CreateBindingSetAndLayout(
|
||||
// m_renderer->GetBackend()->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
// nvrhi::BindingSetDesc()
|
||||
// .addItem(nvrhi::BindingSetItem::ConstantBuffer(0, m_view_constants))
|
||||
// .addItem(nvrhi::BindingSetItem::PushConstants(
|
||||
// 1, sizeof(PushConstantsSpotLight)))
|
||||
// .addItem(nvrhi::BindingSetItem::Texture_UAV(0, m_diffuse_texture))
|
||||
// .addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
// 0, m_renderer->m_gbuffer->m_gbuffer_depth))
|
||||
// .addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
// 1, m_renderer->m_gbuffer->m_gbuffer_normal))
|
||||
// .addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
// 2, m_renderer->m_gbuffer->m_gbuffer_params))
|
||||
// .addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
// 3, m_renderer->m_gbuffer->m_gbuffer_diffuse))
|
||||
// .addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
// 5, m_renderer->m_ssao->m_outputAO)),
|
||||
// binding_layout_spot, m_binding_set_spotlight);
|
||||
//
|
||||
// auto clear_shader = m_renderer->m_backend->CreateShader(
|
||||
// "gbuffer_light_clear", nvrhi::ShaderType::Compute);
|
||||
// auto spotlight_shader = m_renderer->m_backend->CreateShader(
|
||||
// "gbuffer_light_spot", nvrhi::ShaderType::Compute);
|
||||
//
|
||||
// m_pso_clear = m_renderer->m_backend->GetDevice()->createComputePipeline(
|
||||
// nvrhi::ComputePipelineDesc()
|
||||
// .setComputeShader(clear_shader)
|
||||
// .addBindingLayout(binding_layout_clear));
|
||||
//
|
||||
// m_pso_spotlight = m_renderer->m_backend->GetDevice()->createComputePipeline(
|
||||
// nvrhi::ComputePipelineDesc()
|
||||
// .setComputeShader(spotlight_shader)
|
||||
// .addBindingLayout(binding_layout_spot));
|
||||
}
|
||||
|
||||
void GbufferLighting::Render(const NvRenderer::RenderPass& pass) {
|
||||
// ViewConstants view_constants{};
|
||||
// view_constants.m_inverse_model_view =
|
||||
// static_cast<glm::mat4>(glm::inverse(pass.m_transform));
|
||||
// view_constants.m_inverse_projection =
|
||||
// static_cast<glm::mat4>(glm::inverse(pass.m_projection));
|
||||
// pass.m_command_list_draw->writeBuffer(m_view_constants, &view_constants,
|
||||
// sizeof(view_constants));
|
||||
m_packed_buffer.clear();
|
||||
for (int i = 0; i < m_renderer->m_renderable_spotlights.size(); ++i) {
|
||||
if (i >= m_lighting_buffer_capacity) break;
|
||||
auto& light = m_packed_buffer.emplace_back(
|
||||
m_renderer->m_renderable_spotlights[i], pass.m_origin);
|
||||
}
|
||||
|
||||
pass.m_command_list_draw->writeBuffer(
|
||||
m_light_buffer, m_packed_buffer.data(),
|
||||
m_packed_buffer.size() * sizeof(m_packed_buffer[0]));
|
||||
|
||||
ViewParams view_params{};
|
||||
view_params.m_inverse_projection =
|
||||
static_cast<glm::mat4>(glm::inverse(pass.m_projection));
|
||||
view_params.m_view = static_cast<glm::mat4>(pass.m_transform);
|
||||
view_params.m_screen_dimensions = {m_width, m_height};
|
||||
view_params.m_num_lights = m_packed_buffer.size();
|
||||
pass.m_command_list_draw->writeBuffer(m_view_params_buffer, &view_params,
|
||||
sizeof(view_params));
|
||||
|
||||
{
|
||||
DispatchParams dispatch_params{};
|
||||
dispatch_params.m_num_threads = {m_tiles_x, m_tiles_y, 1u};
|
||||
dispatch_params.m_num_thread_groups =
|
||||
(dispatch_params.m_num_threads + 7u) / 8u;
|
||||
pass.m_command_list_draw->writeBuffer(
|
||||
m_dispatch_params_buffer, &dispatch_params, sizeof(dispatch_params));
|
||||
|
||||
pass.m_command_list_draw->setComputeState(
|
||||
nvrhi::ComputeState()
|
||||
.setPipeline(m_pso_comp_frustums)
|
||||
.addBindingSet(m_bindings_comp_frustums));
|
||||
pass.m_command_list_draw->dispatch(dispatch_params.m_num_thread_groups.x,
|
||||
dispatch_params.m_num_thread_groups.y,
|
||||
dispatch_params.m_num_thread_groups.z);
|
||||
}
|
||||
|
||||
{
|
||||
DispatchParams dispatch_params{};
|
||||
dispatch_params.m_num_thread_groups = {m_tiles_x, m_tiles_y, 1u};
|
||||
dispatch_params.m_num_threads = dispatch_params.m_num_thread_groups * 8u;
|
||||
pass.m_command_list_draw->writeBuffer(
|
||||
m_dispatch_params_buffer, &dispatch_params, sizeof(dispatch_params));
|
||||
|
||||
uint32_t zero = 0;
|
||||
pass.m_command_list_draw->writeBuffer(m_atomic_counter_lights_opaque, &zero,
|
||||
sizeof(zero));
|
||||
pass.m_command_list_draw->writeBuffer(m_atomic_counter_lights_transparent,
|
||||
&zero, sizeof(zero));
|
||||
|
||||
pass.m_command_list_draw->setComputeState(
|
||||
nvrhi::ComputeState()
|
||||
.setPipeline(m_pso_cull_lights)
|
||||
.addBindingSet(m_bindings_cull_lights));
|
||||
pass.m_command_list_draw->dispatch(dispatch_params.m_num_thread_groups.x,
|
||||
dispatch_params.m_num_thread_groups.y,
|
||||
dispatch_params.m_num_thread_groups.z);
|
||||
}
|
||||
|
||||
// {
|
||||
// pass.m_command_list_draw->setComputeState(
|
||||
// nvrhi::ComputeState()
|
||||
// .setPipeline(m_pso_clear)
|
||||
// .addBindingSet(m_binding_set_clear));
|
||||
// pass.m_command_list_draw->dispatch((m_width + 7) / 8, (m_height + 7) / 8);
|
||||
// }
|
||||
//
|
||||
// for (const auto& spotlight : m_renderer->m_renderable_spotlights) {
|
||||
// PushConstantsSpotLight push_constants{};
|
||||
// push_constants.m_origin = spotlight.m_origin - pass.m_origin;
|
||||
// push_constants.m_radius_sqr = spotlight.m_radius * spotlight.m_radius;
|
||||
// push_constants.m_direction = spotlight.m_direction;
|
||||
// push_constants.m_cos_inner_cone = spotlight.m_cos_inner_cone;
|
||||
// push_constants.m_cos_outer_cone = spotlight.m_cos_outer_cone;
|
||||
// push_constants.m_color = spotlight.m_color;
|
||||
//
|
||||
// pass.m_command_list_draw->setComputeState(
|
||||
// nvrhi::ComputeState()
|
||||
// .setPipeline(m_pso_spotlight)
|
||||
// .addBindingSet(m_binding_set_spotlight));
|
||||
// pass.m_command_list_draw->setPushConstants(&push_constants,
|
||||
// sizeof(push_constants));
|
||||
// pass.m_command_list_draw->dispatch((m_width + 7) / 8, (m_height + 7) / 8);
|
||||
// }
|
||||
}
|
||||
|
||||
GbufferLighting::PackedSpotLight::PackedSpotLight(
|
||||
const NvRenderer::Renderable::SpotLight& spotlight,
|
||||
glm::dvec3 const& origin) {
|
||||
m_origin = spotlight.m_origin - origin;
|
||||
m_radius = spotlight.m_radius;
|
||||
m_direction_cos_inner =
|
||||
glm::packHalf4x16({spotlight.m_direction, spotlight.m_cos_inner_cone});
|
||||
glm::vec3 color =
|
||||
spotlight.m_color.r * glm::vec3(0.4123908f, 0.21263901f, 0.01933082f) +
|
||||
spotlight.m_color.g * glm::vec3(0.35758434f, 0.71516868f, 0.11919478f) +
|
||||
spotlight.m_color.b * glm::vec3(0.18048079f, 0.07219232f, 0.95053215f);
|
||||
m_color_cos_outer = glm::packHalf4x16({color, spotlight.m_cos_outer_cone});
|
||||
}
|
||||
84
manul/renderer/source/gbufferlighting.h
Normal file
84
manul/renderer/source/gbufferlighting.h
Normal file
@@ -0,0 +1,84 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrenderer/nvrenderer.h>
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
struct GbufferLighting : public MaResourceRegistry {
|
||||
GbufferLighting(NvRenderer* renderer)
|
||||
: MaResourceRegistry(renderer), m_renderer(renderer) {}
|
||||
|
||||
struct ViewConstants {
|
||||
glm::mat4 m_inverse_model_view;
|
||||
glm::mat4 m_inverse_projection;
|
||||
};
|
||||
|
||||
struct PushConstantsSpotLight {
|
||||
glm::vec3 m_origin;
|
||||
float m_radius_sqr;
|
||||
glm::vec3 m_direction;
|
||||
float m_cos_inner_cone;
|
||||
glm::vec3 m_color;
|
||||
float m_cos_outer_cone;
|
||||
};
|
||||
|
||||
struct PackedSpotLight {
|
||||
explicit PackedSpotLight(NvRenderer::Renderable::SpotLight const& spotlight,
|
||||
glm::dvec3 const& origin);
|
||||
glm::vec3 m_origin;
|
||||
float m_radius;
|
||||
uint64_t m_direction_cos_inner;
|
||||
uint64_t m_color_cos_outer;
|
||||
};
|
||||
|
||||
struct DispatchParams {
|
||||
alignas(sizeof(glm::vec4)) glm::uvec3 m_num_thread_groups;
|
||||
alignas(sizeof(glm::vec4)) glm::uvec3 m_num_threads;
|
||||
};
|
||||
|
||||
struct ViewParams {
|
||||
glm::mat4 m_inverse_projection;
|
||||
glm::mat4 m_view;
|
||||
glm::vec2 m_screen_dimensions;
|
||||
uint32_t m_num_lights;
|
||||
};
|
||||
|
||||
std::vector<PackedSpotLight> m_packed_buffer;
|
||||
size_t m_lighting_buffer_capacity;
|
||||
|
||||
nvrhi::BindingSetHandle m_bindings_cull_lights;
|
||||
nvrhi::ComputePipelineHandle m_pso_cull_lights;
|
||||
|
||||
nvrhi::BindingSetHandle m_bindings_comp_frustums;
|
||||
nvrhi::ComputePipelineHandle m_pso_comp_frustums;
|
||||
|
||||
nvrhi::BufferHandle m_atomic_counter_lights_opaque;
|
||||
nvrhi::BufferHandle m_atomic_counter_lights_transparent;
|
||||
nvrhi::BufferHandle m_index_buffer_lights_opaque;
|
||||
nvrhi::BufferHandle m_index_buffer_lights_transparent;
|
||||
nvrhi::TextureHandle m_index_grid_lights_opaque;
|
||||
nvrhi::TextureHandle m_index_grid_lights_transparent;
|
||||
|
||||
nvrhi::TextureHandle m_diffuse_texture;
|
||||
nvrhi::TextureHandle m_specular_texture;
|
||||
nvrhi::BufferHandle m_light_buffer;
|
||||
nvrhi::BufferHandle m_view_constants;
|
||||
nvrhi::BufferHandle m_frustum_buffer;
|
||||
nvrhi::BufferHandle m_dispatch_params_buffer;
|
||||
nvrhi::BufferHandle m_view_params_buffer;
|
||||
nvrhi::BindingSetHandle m_binding_set_spotlight;
|
||||
nvrhi::ComputePipelineHandle m_pso_spotlight;
|
||||
nvrhi::BindingSetHandle m_binding_set_clear;
|
||||
nvrhi::ComputePipelineHandle m_pso_clear;
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_tiles_x;
|
||||
int m_tiles_y;
|
||||
|
||||
void Init();
|
||||
void Render(const NvRenderer::RenderPass& pass);
|
||||
|
||||
NvRenderer* m_renderer;
|
||||
};
|
||||
408
manul/renderer/source/imgui_nvrhi.cpp
Normal file
408
manul/renderer/source/imgui_nvrhi.cpp
Normal file
@@ -0,0 +1,408 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
License for Dear ImGui
|
||||
|
||||
Copyright (c) 2014-2019 Omar Cornut
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "imgui_nvrhi.h"
|
||||
#include "nvrendererbackend.h"
|
||||
#include "config.h"
|
||||
|
||||
struct VERTEX_CONSTANT_BUFFER
|
||||
{
|
||||
float mvp[4][4];
|
||||
};
|
||||
|
||||
struct ImguiPushConstants {
|
||||
glm::vec2 m_inv_display_size;
|
||||
float m_ui_nits;
|
||||
MaConfig::MaTonemapType m_tonemap_function;
|
||||
};
|
||||
|
||||
bool ImGui_NVRHI::createFontTexture(nvrhi::ICommandList* commandList)
|
||||
{
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
unsigned char *pixels;
|
||||
int width, height;
|
||||
|
||||
io.Fonts->GetTexDataAsRGBA32(&pixels, &width, &height);
|
||||
|
||||
{
|
||||
nvrhi::TextureDesc desc;
|
||||
desc.width = width;
|
||||
desc.height = height;
|
||||
desc.format = nvrhi::Format::RGBA8_UNORM;
|
||||
desc.debugName = "ImGui font texture";
|
||||
|
||||
fontTexture = renderer->createTexture(desc);
|
||||
|
||||
commandList->beginTrackingTextureState(fontTexture, nvrhi::AllSubresources, nvrhi::ResourceStates::Common);
|
||||
|
||||
if (fontTexture == nullptr)
|
||||
return false;
|
||||
|
||||
commandList->writeTexture(fontTexture, 0, 0, pixels, width * 4);
|
||||
|
||||
commandList->setPermanentTextureState(fontTexture, nvrhi::ResourceStates::ShaderResource);
|
||||
commandList->commitBarriers();
|
||||
|
||||
io.Fonts->TexID = fontTexture;
|
||||
}
|
||||
|
||||
{
|
||||
const auto desc = nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(nvrhi::SamplerAddressMode::Wrap)
|
||||
.setAllFilters(true);
|
||||
|
||||
fontSampler = renderer->createSampler(desc);
|
||||
|
||||
if (fontSampler == nullptr)
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::init(NvRendererBackend *backend)
|
||||
{
|
||||
this->renderer = renderer;
|
||||
|
||||
m_commandList = renderer->createCommandList();
|
||||
|
||||
m_commandList->open();
|
||||
|
||||
vertexShader = backend->CreateShader("imgui_vertex", nvrhi::ShaderType::Vertex);
|
||||
if (vertexShader == nullptr)
|
||||
{
|
||||
printf("error creating NVRHI vertex shader object\n");
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
pixelShader = backend->CreateShader("imgui_pixel", nvrhi::ShaderType::Pixel);
|
||||
if (pixelShader == nullptr)
|
||||
{
|
||||
printf("error creating NVRHI pixel shader object\n");
|
||||
assert(0);
|
||||
return false;
|
||||
}
|
||||
|
||||
// create attribute layout object
|
||||
nvrhi::VertexAttributeDesc vertexAttribLayout[] = {
|
||||
{ "POSITION", nvrhi::Format::RG32_FLOAT, 1, 0, offsetof(ImDrawVert,pos), sizeof(ImDrawVert), false },
|
||||
{ "TEXCOORD", nvrhi::Format::RG32_FLOAT, 1, 0, offsetof(ImDrawVert,uv), sizeof(ImDrawVert), false },
|
||||
{ "COLOR", nvrhi::Format::RGBA8_UNORM, 1, 0, offsetof(ImDrawVert,col), sizeof(ImDrawVert), false },
|
||||
};
|
||||
|
||||
shaderAttribLayout = renderer->createInputLayout(vertexAttribLayout, sizeof(vertexAttribLayout) / sizeof(vertexAttribLayout[0]), vertexShader);
|
||||
|
||||
// add the default font - before creating the font texture
|
||||
auto& io = ImGui::GetIO();
|
||||
io.Fonts->AddFontDefault();
|
||||
|
||||
// create font texture
|
||||
if (!createFontTexture(m_commandList))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// create PSO
|
||||
{
|
||||
nvrhi::BlendState blendState;
|
||||
blendState.targets[0].setBlendEnable(true)
|
||||
.setSrcBlend(nvrhi::BlendFactor::SrcAlpha)
|
||||
.setDestBlend(nvrhi::BlendFactor::InvSrcAlpha)
|
||||
.setSrcBlendAlpha(nvrhi::BlendFactor::InvSrcAlpha)
|
||||
.setDestBlendAlpha(nvrhi::BlendFactor::Zero);
|
||||
|
||||
auto rasterState = nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.setCullNone()
|
||||
.setScissorEnable(true)
|
||||
.setDepthClipEnable(true);
|
||||
|
||||
auto depthStencilState = nvrhi::DepthStencilState()
|
||||
.disableDepthTest()
|
||||
.enableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Always);
|
||||
|
||||
nvrhi::RenderState renderState;
|
||||
renderState.blendState = blendState;
|
||||
renderState.depthStencilState = depthStencilState;
|
||||
renderState.rasterState = rasterState;
|
||||
|
||||
nvrhi::BindingLayoutDesc layoutDesc;
|
||||
layoutDesc.visibility = nvrhi::ShaderType::All;
|
||||
layoutDesc.bindings = {
|
||||
nvrhi::BindingLayoutItem::PushConstants(0, sizeof(ImguiPushConstants)),
|
||||
nvrhi::BindingLayoutItem::Texture_SRV(0),
|
||||
nvrhi::BindingLayoutItem::Sampler(0)
|
||||
};
|
||||
bindingLayout = renderer->createBindingLayout(layoutDesc);
|
||||
|
||||
basePSODesc.primType = nvrhi::PrimitiveType::TriangleList;
|
||||
basePSODesc.inputLayout = shaderAttribLayout;
|
||||
basePSODesc.VS = vertexShader;
|
||||
basePSODesc.PS = pixelShader;
|
||||
basePSODesc.renderState = renderState;
|
||||
basePSODesc.bindingLayouts = { bindingLayout };
|
||||
}
|
||||
|
||||
m_commandList->close();
|
||||
renderer->executeCommandList(m_commandList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::reallocateBuffer(nvrhi::BufferHandle& buffer, size_t requiredSize, size_t reallocateSize, const bool indexBuffer)
|
||||
{
|
||||
if (buffer == nullptr || size_t(buffer->getDesc().byteSize) < requiredSize)
|
||||
{
|
||||
nvrhi::BufferDesc desc;
|
||||
desc.byteSize = uint32_t(reallocateSize);
|
||||
desc.structStride = 0;
|
||||
desc.debugName = indexBuffer ? "ImGui index buffer" : "ImGui vertex buffer";
|
||||
desc.canHaveUAVs = false;
|
||||
desc.isVertexBuffer = !indexBuffer;
|
||||
desc.isIndexBuffer = indexBuffer;
|
||||
desc.isDrawIndirectArgs = false;
|
||||
desc.isVolatile = false;
|
||||
desc.initialState = indexBuffer ? nvrhi::ResourceStates::IndexBuffer : nvrhi::ResourceStates::VertexBuffer;
|
||||
desc.keepInitialState = true;
|
||||
|
||||
buffer = renderer->createBuffer(desc);
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::beginFrame()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
nvrhi::IGraphicsPipeline* ImGui_NVRHI::getPSO(nvrhi::IFramebuffer* fb)
|
||||
{
|
||||
if (pso)
|
||||
return pso;
|
||||
|
||||
pso = renderer->createGraphicsPipeline(basePSODesc, fb);
|
||||
assert(pso);
|
||||
|
||||
return pso;
|
||||
}
|
||||
|
||||
nvrhi::IBindingSet* ImGui_NVRHI::getBindingSet(void* handle)
|
||||
{
|
||||
nvrhi::ITexture* texture = reinterpret_cast<nvrhi::ITexture*>(handle);
|
||||
auto iter = bindingsCache.find(texture);
|
||||
if (iter != bindingsCache.end())
|
||||
{
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
nvrhi::BindingSetDesc desc;
|
||||
|
||||
desc.bindings = {
|
||||
nvrhi::BindingSetItem::PushConstants(0, sizeof(ImguiPushConstants)),
|
||||
nvrhi::BindingSetItem::Texture_SRV(0, texture),
|
||||
nvrhi::BindingSetItem::Sampler(0, fontSampler)
|
||||
};
|
||||
|
||||
nvrhi::BindingSetHandle binding;
|
||||
binding = renderer->createBindingSet(desc, bindingLayout);
|
||||
assert(binding);
|
||||
|
||||
bindingsCache[texture] = binding;
|
||||
return binding;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::updateGeometry(nvrhi::ICommandList* commandList)
|
||||
{
|
||||
ImDrawData *drawData = ImGui::GetDrawData();
|
||||
|
||||
// create/resize vertex and index buffers if needed
|
||||
if (!reallocateBuffer(vertexBuffer,
|
||||
drawData->TotalVtxCount * sizeof(ImDrawVert),
|
||||
(drawData->TotalVtxCount + 5000) * sizeof(ImDrawVert),
|
||||
false))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!reallocateBuffer(indexBuffer,
|
||||
drawData->TotalIdxCount * sizeof(ImDrawIdx),
|
||||
(drawData->TotalIdxCount + 5000) * sizeof(ImDrawIdx),
|
||||
true))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
vtxBuffer.resize(vertexBuffer->getDesc().byteSize / sizeof(ImDrawVert));
|
||||
idxBuffer.resize(indexBuffer->getDesc().byteSize / sizeof(ImDrawIdx));
|
||||
|
||||
// copy and convert all vertices into a single contiguous buffer
|
||||
ImDrawVert *vtxDst = &vtxBuffer[0];
|
||||
ImDrawIdx *idxDst = &idxBuffer[0];
|
||||
|
||||
for(int n = 0; n < drawData->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList *cmdList = drawData->CmdLists[n];
|
||||
|
||||
memcpy(vtxDst, cmdList->VtxBuffer.Data, cmdList->VtxBuffer.Size * sizeof(ImDrawVert));
|
||||
memcpy(idxDst, cmdList->IdxBuffer.Data, cmdList->IdxBuffer.Size * sizeof(ImDrawIdx));
|
||||
|
||||
vtxDst += cmdList->VtxBuffer.Size;
|
||||
idxDst += cmdList->IdxBuffer.Size;
|
||||
}
|
||||
|
||||
commandList->writeBuffer(vertexBuffer, &vtxBuffer[0], vertexBuffer->getDesc().byteSize);
|
||||
commandList->writeBuffer(indexBuffer, &idxBuffer[0], indexBuffer->getDesc().byteSize);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ImGui_NVRHI::render(nvrhi::IFramebuffer* framebuffer)
|
||||
{
|
||||
ImDrawData *drawData = ImGui::GetDrawData();
|
||||
const auto& io = ImGui::GetIO();
|
||||
|
||||
m_commandList->open();
|
||||
m_commandList->beginMarker("ImGUI");
|
||||
|
||||
if (!updateGeometry(m_commandList))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// handle DPI scaling
|
||||
drawData->ScaleClipRects(io.DisplayFramebufferScale);
|
||||
|
||||
ImguiPushConstants push_constants{};
|
||||
push_constants.m_inv_display_size = {1.f / io.DisplaySize.x, 1.f / io.DisplaySize.y};
|
||||
push_constants.m_ui_nits = NvRenderer::Config()->m_display.GetHDRConfig().m_ui_nits;
|
||||
push_constants.m_tonemap_function = NvRenderer::Config()->m_display.GetHDRConfig().m_tonemap_function;
|
||||
|
||||
// set up graphics state
|
||||
nvrhi::GraphicsState drawState;
|
||||
|
||||
drawState.framebuffer = framebuffer;
|
||||
assert(drawState.framebuffer);
|
||||
|
||||
drawState.pipeline = getPSO(drawState.framebuffer);
|
||||
|
||||
drawState.viewport.viewports.push_back(nvrhi::Viewport(io.DisplaySize.x * io.DisplayFramebufferScale.x,
|
||||
io.DisplaySize.y * io.DisplayFramebufferScale.y));
|
||||
drawState.viewport.scissorRects.resize(1); // updated below
|
||||
|
||||
nvrhi::VertexBufferBinding vbufBinding;
|
||||
vbufBinding.buffer = vertexBuffer;
|
||||
vbufBinding.slot = 0;
|
||||
vbufBinding.offset = 0;
|
||||
drawState.vertexBuffers.push_back(vbufBinding);
|
||||
|
||||
drawState.indexBuffer.buffer = indexBuffer;
|
||||
drawState.indexBuffer.format = (sizeof(ImDrawIdx) == 2 ? nvrhi::Format::R16_UINT : nvrhi::Format::R32_UINT);
|
||||
drawState.indexBuffer.offset = 0;
|
||||
|
||||
// render command lists
|
||||
int vtxOffset = 0;
|
||||
int idxOffset = 0;
|
||||
for(int n = 0; n < drawData->CmdListsCount; n++)
|
||||
{
|
||||
const ImDrawList *cmdList = drawData->CmdLists[n];
|
||||
for(int i = 0; i < cmdList->CmdBuffer.Size; i++)
|
||||
{
|
||||
const ImDrawCmd *pCmd = &cmdList->CmdBuffer[i];
|
||||
|
||||
if (pCmd->UserCallback)
|
||||
{
|
||||
pCmd->UserCallback(cmdList, pCmd);
|
||||
} else {
|
||||
drawState.bindings = { getBindingSet(pCmd->TextureId) };
|
||||
assert(drawState.bindings[0]);
|
||||
|
||||
drawState.viewport.scissorRects[0] = nvrhi::Rect(int(pCmd->ClipRect.x),
|
||||
int(pCmd->ClipRect.z),
|
||||
int(pCmd->ClipRect.y),
|
||||
int(pCmd->ClipRect.w));
|
||||
|
||||
nvrhi::DrawArguments drawArguments;
|
||||
drawArguments.vertexCount = pCmd->ElemCount;
|
||||
drawArguments.startIndexLocation = idxOffset;
|
||||
drawArguments.startVertexLocation = vtxOffset;
|
||||
|
||||
m_commandList->setGraphicsState(drawState);
|
||||
m_commandList->setPushConstants(&push_constants, sizeof(push_constants));
|
||||
m_commandList->drawIndexed(drawArguments);
|
||||
}
|
||||
|
||||
idxOffset += pCmd->ElemCount;
|
||||
}
|
||||
|
||||
vtxOffset += cmdList->VtxBuffer.Size;
|
||||
}
|
||||
|
||||
m_commandList->endMarker();
|
||||
m_commandList->close();
|
||||
renderer->executeCommandList(m_commandList);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui_NVRHI::backbufferResizing()
|
||||
{
|
||||
pso = nullptr;
|
||||
}
|
||||
98
manul/renderer/source/imgui_nvrhi.h
Normal file
98
manul/renderer/source/imgui_nvrhi.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
* Copyright (c) 2014-2021, NVIDIA CORPORATION. All rights reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*/
|
||||
|
||||
/*
|
||||
License for Dear ImGui
|
||||
|
||||
Copyright (c) 2014-2019 Omar Cornut
|
||||
|
||||
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 <memory>
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include <imgui/imgui.h>
|
||||
#include "nvtexture.h"
|
||||
|
||||
struct ImGui_NVRHI
|
||||
{
|
||||
nvrhi::DeviceHandle renderer;
|
||||
nvrhi::CommandListHandle m_commandList;
|
||||
|
||||
nvrhi::ShaderHandle vertexShader;
|
||||
nvrhi::ShaderHandle pixelShader;
|
||||
nvrhi::InputLayoutHandle shaderAttribLayout;
|
||||
|
||||
nvrhi::TextureHandle fontTexture;
|
||||
nvrhi::SamplerHandle fontSampler;
|
||||
|
||||
nvrhi::BufferHandle vertexBuffer;
|
||||
nvrhi::BufferHandle indexBuffer;
|
||||
|
||||
nvrhi::BindingLayoutHandle bindingLayout;
|
||||
nvrhi::GraphicsPipelineDesc basePSODesc;
|
||||
|
||||
nvrhi::GraphicsPipelineHandle pso;
|
||||
std::unordered_map<nvrhi::ITexture*, nvrhi::BindingSetHandle> bindingsCache;
|
||||
|
||||
std::vector<ImDrawVert> vtxBuffer;
|
||||
std::vector<ImDrawIdx> idxBuffer;
|
||||
|
||||
NvTextureManager* textureManager;
|
||||
|
||||
bool init(class NvRendererBackend *backend);
|
||||
bool beginFrame();
|
||||
bool render(nvrhi::IFramebuffer* framebuffer);
|
||||
void backbufferResizing();
|
||||
|
||||
private:
|
||||
bool reallocateBuffer(nvrhi::BufferHandle& buffer, size_t requiredSize, size_t reallocateSize, bool isIndexBuffer);
|
||||
|
||||
bool createFontTexture(nvrhi::ICommandList* commandList);
|
||||
|
||||
nvrhi::IGraphicsPipeline* getPSO(nvrhi::IFramebuffer* fb);
|
||||
nvrhi::IBindingSet* getBindingSet(void* handle);
|
||||
bool updateGeometry(nvrhi::ICommandList* commandList);
|
||||
};
|
||||
1
manul/renderer/source/instancecache.cpp
Normal file
1
manul/renderer/source/instancecache.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "instancecache.h"
|
||||
54
manul/renderer/source/instancecache.h
Normal file
54
manul/renderer/source/instancecache.h
Normal file
@@ -0,0 +1,54 @@
|
||||
#pragma once
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
struct InstanceCacheId {
|
||||
gfx::geometry_handle m_geometry;
|
||||
material_handle m_material;
|
||||
InstanceCacheId(gfx::geometry_handle geometry, material_handle material)
|
||||
: m_geometry(geometry), m_material(material) {}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::hash<InstanceCacheId> {
|
||||
std::size_t operator()(const InstanceCacheId& op) const {
|
||||
size_t hash_geometry = std::hash<uint64_t>()(op.m_geometry);
|
||||
size_t hash_material = std::hash<uint32_t>()(op.m_material);
|
||||
return hash_geometry ^ hash_material + 0x9e3779b9 + (hash_geometry << 6) +
|
||||
(hash_geometry >> 2);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::equal_to<InstanceCacheId> {
|
||||
bool operator()(const InstanceCacheId& lhs,
|
||||
const InstanceCacheId& rhs) const {
|
||||
return lhs.m_geometry == rhs.m_geometry && lhs.m_material == rhs.m_material;
|
||||
}
|
||||
};
|
||||
|
||||
struct InstanceCache {
|
||||
struct Instance {
|
||||
glm::mat3x4 m_transform;
|
||||
glm::mat3x4 m_transform_history;
|
||||
Instance(const glm::dmat4& transform, const glm::dmat4& transform_history)
|
||||
: m_transform(static_cast<glm::mat3x4>(glm::transpose(transform))),
|
||||
m_transform_history(
|
||||
static_cast<glm::mat3x4>(glm::transpose(transform_history))) {}
|
||||
};
|
||||
std::vector<Instance> m_instances;
|
||||
};
|
||||
|
||||
struct InstanceBank {
|
||||
std::unordered_map<InstanceCacheId, InstanceCache> m_cache;
|
||||
void Clear() {
|
||||
for (auto& [id, cache] : m_cache) {
|
||||
cache.m_instances.clear();
|
||||
}
|
||||
}
|
||||
void AddInstance(gfx::geometry_handle geometry, material_handle material,
|
||||
const glm::dmat4& transform, const glm::dmat4& history) {
|
||||
auto& cache = m_cache[{geometry, material}];
|
||||
cache.m_instances.emplace_back(transform, history);
|
||||
}
|
||||
};
|
||||
149
manul/renderer/source/ma_dds.cpp
Normal file
149
manul/renderer/source/ma_dds.cpp
Normal file
@@ -0,0 +1,149 @@
|
||||
#include "ddspp/ddspp.h"
|
||||
#include "nvtexture.h"
|
||||
|
||||
#include <sstream>
|
||||
|
||||
bool NvTexture::LoadDDS(std::string &data, int size_bias) {
|
||||
ddspp::Descriptor desc{};
|
||||
if (ddspp::decode_header(reinterpret_cast<uint8_t *>(data.data()), desc) !=
|
||||
ddspp::Success)
|
||||
return false;
|
||||
std::stringstream ss(data, std::ios::in | std::ios::binary);
|
||||
// auto sd = opengl_texture::deserialize_ddsd(ss);
|
||||
// int blksize = 16;
|
||||
// m_bc = true;
|
||||
m_has_alpha = false;
|
||||
switch (desc.format) {
|
||||
case ddspp::DXGIFormat::BC1_UNORM:
|
||||
case ddspp::DXGIFormat::BC1_UNORM_SRGB:
|
||||
m_format =
|
||||
m_srgb ? nvrhi::Format::BC1_UNORM_SRGB : nvrhi::Format::BC1_UNORM;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC2_UNORM:
|
||||
case ddspp::DXGIFormat::BC2_UNORM_SRGB:
|
||||
m_format =
|
||||
m_srgb ? nvrhi::Format::BC2_UNORM_SRGB : nvrhi::Format::BC2_UNORM;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC3_UNORM:
|
||||
case ddspp::DXGIFormat::BC3_UNORM_SRGB:
|
||||
m_format =
|
||||
m_srgb ? nvrhi::Format::BC3_UNORM_SRGB : nvrhi::Format::BC3_UNORM;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC4_UNORM:
|
||||
m_format = nvrhi::Format::BC4_UNORM;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC4_SNORM:
|
||||
m_format = nvrhi::Format::BC4_SNORM;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC5_UNORM:
|
||||
m_format = nvrhi::Format::BC5_UNORM;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC5_SNORM:
|
||||
m_format = nvrhi::Format::BC5_SNORM;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC6H_SF16:
|
||||
m_format = nvrhi::Format::BC6H_SFLOAT;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC6H_UF16:
|
||||
m_format = nvrhi::Format::BC6H_UFLOAT;
|
||||
break;
|
||||
|
||||
case ddspp::DXGIFormat::BC7_UNORM:
|
||||
case ddspp::DXGIFormat::BC7_UNORM_SRGB:
|
||||
m_format =
|
||||
m_srgb ? nvrhi::Format::BC7_UNORM_SRGB : nvrhi::Format::BC7_UNORM;
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
//
|
||||
m_width = desc.width;
|
||||
m_height = desc.height;
|
||||
|
||||
struct Bc2Block {
|
||||
uint64_t alpha;
|
||||
uint16_t color0;
|
||||
uint16_t color1;
|
||||
uint32_t pixels;
|
||||
[[nodiscard]] bool HasTransparency() const {
|
||||
return alpha != static_cast<uint64_t>(-1);
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(Bc2Block) == 16);
|
||||
|
||||
struct Bc3Block {
|
||||
uint16_t alpha;
|
||||
uint16_t pixels0;
|
||||
uint16_t pixels1;
|
||||
uint16_t pixels2;
|
||||
uint64_t color_block;
|
||||
[[nodiscard]] bool HasTransparency() const {
|
||||
return alpha != static_cast<uint16_t>(-1);
|
||||
}
|
||||
};
|
||||
|
||||
struct Bc7Block {
|
||||
uint8_t data[16];
|
||||
[[nodiscard]] bool HasTransparency() const {
|
||||
int mode = 0;
|
||||
if (!data[0]) return false;
|
||||
for (; !(data[0] & (1 << (7 - mode))); ++mode)
|
||||
;
|
||||
return mode > 3;
|
||||
}
|
||||
};
|
||||
|
||||
static_assert(sizeof(Bc3Block) == 16);
|
||||
for (int mip = 0; mip < desc.numMips; ++mip) {
|
||||
int width = std::max(m_width >> mip, 1);
|
||||
int height = std::max(m_height >> mip, 1);
|
||||
int blkx = (width + desc.blockWidth - 1) / desc.blockWidth;
|
||||
int blky = (height + desc.blockHeight - 1) / desc.blockHeight;
|
||||
auto &[pitch, mip_data] = m_data.emplace_back();
|
||||
pitch = ddspp::get_row_pitch(desc, mip);
|
||||
mip_data.resize(pitch * blky, '\0');
|
||||
ss.seekg(desc.headerSize + ddspp::get_offset(desc, mip, 0));
|
||||
ss.read(mip_data.data(), mip_data.size());
|
||||
if (!mip) {
|
||||
switch (desc.format) {
|
||||
case ddspp::DXGIFormat::BC2_UNORM:
|
||||
case ddspp::DXGIFormat::BC2_UNORM_SRGB:
|
||||
for (size_t j = 0; !m_has_alpha && j < blkx * blky; ++j) {
|
||||
const Bc2Block &block =
|
||||
reinterpret_cast<const Bc2Block *>(data.data())[j];
|
||||
if (block.HasTransparency()) m_has_alpha = true;
|
||||
}
|
||||
break;
|
||||
case ddspp::DXGIFormat::BC3_UNORM:
|
||||
case ddspp::DXGIFormat::BC3_UNORM_SRGB:
|
||||
for (size_t j = 0; !m_has_alpha && j < blkx * blky; ++j) {
|
||||
const Bc3Block &block =
|
||||
reinterpret_cast<const Bc3Block *>(data.data())[j];
|
||||
if (block.HasTransparency()) m_has_alpha = true;
|
||||
}
|
||||
break;
|
||||
case ddspp::DXGIFormat::BC7_UNORM:
|
||||
case ddspp::DXGIFormat::BC7_UNORM_SRGB:
|
||||
for (size_t j = 0; !m_has_alpha && j < blkx * blky; ++j) {
|
||||
const Bc7Block &block =
|
||||
reinterpret_cast<const Bc7Block *>(data.data())[j];
|
||||
if (block.HasTransparency()) m_has_alpha = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
336
manul/renderer/source/materialparser.cpp
Normal file
336
manul/renderer/source/materialparser.cpp
Normal file
@@ -0,0 +1,336 @@
|
||||
#include "materialparser.h"
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
#include <Globals.h>
|
||||
#include <Logs.h>
|
||||
#include <fmt/format.h>
|
||||
#include <material.h>
|
||||
#include <parser.h>
|
||||
#include <utilities.h>
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
std::string_view MaterialAdapter::GetTexturePathForEntry(
|
||||
std::string_view key) const {
|
||||
if (m_material_internal) {
|
||||
return m_material_internal->GetTexturePathForEntry(key);
|
||||
}
|
||||
return std::string_view();
|
||||
}
|
||||
|
||||
int MaterialAdapter::GetTextureSizeBiasForEntry(std::string_view key) const {
|
||||
if (m_material_internal) {
|
||||
return m_material_internal->GetTextureSizeBiasForEntry(key);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::string_view MaterialAdapter::GetShader() const {
|
||||
if (m_material_internal) {
|
||||
return m_material_internal->GetShader();
|
||||
}
|
||||
return std::string_view();
|
||||
}
|
||||
|
||||
int MaterialAdapter::GetShadowRank() const {
|
||||
if (m_material_internal) {
|
||||
return m_material_internal->GetShadowRank();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
glm::dvec2 MaterialAdapter::GetSize() const {
|
||||
if (m_material_internal) {
|
||||
return m_material_internal->GetSize();
|
||||
}
|
||||
return {-1., -1.};
|
||||
}
|
||||
|
||||
std::optional<float> MaterialAdapter::GetOpacity() const {
|
||||
if (m_material_internal) {
|
||||
return m_material_internal->GetOpacity();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool MaterialAdapter::Parse(std::string_view filepath) {
|
||||
if (m_material_internal = MaterialAdapterManul::Parse(filepath);
|
||||
m_material_internal) {
|
||||
return true;
|
||||
}
|
||||
if (m_material_internal = MaterialAdapterLegacyMatFile::Parse(filepath);
|
||||
m_material_internal) {
|
||||
return true;
|
||||
}
|
||||
if (m_material_internal = MaterialAdapterSingleTexture::Parse(filepath);
|
||||
m_material_internal) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
std::optional<bool> MaterialAdapter::GetMaskedShadowOverride() const {
|
||||
if (m_material_internal) {
|
||||
return m_material_internal->GetMaskedShadowOverride();
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialAdapterInternal> MaterialAdapterLegacyMatFile::Parse(
|
||||
std::string_view path) {
|
||||
auto const locator{material_manager::find_on_disk(std::string(path))};
|
||||
|
||||
if (locator.first.size()) {
|
||||
// try to parse located file resource
|
||||
cParser materialparser(locator.first + locator.second,
|
||||
cParser::buffer_FILE);
|
||||
auto material = std::make_shared<MaterialAdapterLegacyMatFile>();
|
||||
while (material->ParseLevel(materialparser, 0)) {
|
||||
}
|
||||
return material;
|
||||
} else {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::string_view MaterialAdapterLegacyMatFile::GetTexturePathForEntry(
|
||||
std::string_view key) const {
|
||||
if (key == "diffuse") {
|
||||
if (auto it = m_texture_mapping.find("_diffuse:");
|
||||
it != m_texture_mapping.end()) {
|
||||
return it->second.m_path;
|
||||
}
|
||||
if (auto it = m_texture_mapping.find("1:"); it != m_texture_mapping.end()) {
|
||||
return it->second.m_path;
|
||||
}
|
||||
} else if (key == "normal") {
|
||||
if (auto it = m_texture_mapping.find("_normals:");
|
||||
it != m_texture_mapping.end()) {
|
||||
return it->second.m_path;
|
||||
}
|
||||
if (auto it = m_texture_mapping.find("_normalmap:");
|
||||
it != m_texture_mapping.end()) {
|
||||
return it->second.m_path;
|
||||
}
|
||||
if (auto it = m_texture_mapping.find("2:"); it != m_texture_mapping.end()) {
|
||||
return it->second.m_path;
|
||||
}
|
||||
} else {
|
||||
if (auto it = m_texture_mapping.find(fmt::format("_{}:", key));
|
||||
it != m_texture_mapping.end()) {
|
||||
return it->second.m_path;
|
||||
}
|
||||
}
|
||||
return std::string_view();
|
||||
}
|
||||
|
||||
std::string_view MaterialAdapterLegacyMatFile::GetShader() const {
|
||||
if (m_shader == "water") {
|
||||
return "legacy_water";
|
||||
}
|
||||
if (IsNormalMapShader() && HasNormalMap()) {
|
||||
return "legacy_normalmap";
|
||||
}
|
||||
return "legacy";
|
||||
}
|
||||
|
||||
bool MaterialAdapterLegacyMatFile::ParseLevel(cParser& parser, int priority) {
|
||||
// NOTE: comma can be part of legacy file names, so we don't treat it as a
|
||||
// separator here
|
||||
auto key{parser.getToken<std::string>(true, "\n\r\t ;[]")};
|
||||
// key can be an actual key or block end
|
||||
if ((true == key.empty()) || (key == "}")) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (priority != -1) {
|
||||
// regular attribute processing mode
|
||||
|
||||
// mark potential material change
|
||||
// update_on_weather_change |= is_weather(key);
|
||||
// update_on_season_change |= is_season(key);
|
||||
|
||||
if (key == Global.Weather) {
|
||||
// weather textures override generic (pri 0) and seasonal (pri 1) textures
|
||||
// seasonal weather textures (pri 1+2=3) override generic weather (pri 2)
|
||||
// textures skip the opening bracket
|
||||
auto const value{parser.getToken<std::string>(true, "\n\r\t ;")};
|
||||
while (ParseLevel(parser, priority + 2)) {
|
||||
; // all work is done in the header
|
||||
}
|
||||
} else if (key == Global.Season) {
|
||||
// seasonal textures override generic textures
|
||||
// skip the opening bracket
|
||||
auto const value{parser.getToken<std::string>(true, "\n\r\t ;")};
|
||||
while (ParseLevel(parser, priority + 1)) {
|
||||
; // all work is done in the header
|
||||
}
|
||||
}
|
||||
|
||||
else if (key.compare(0, 7, "texture") == 0) {
|
||||
key.erase(0, 7);
|
||||
|
||||
auto value{deserialize_random_set(parser)};
|
||||
replace_slashes(value);
|
||||
auto& [tex_priority, texture] = m_texture_mapping[key];
|
||||
if (tex_priority < priority) {
|
||||
texture = value;
|
||||
tex_priority = priority;
|
||||
}
|
||||
} else if (key.compare(0, 5, "param") == 0) {
|
||||
// key.erase(0, 5);
|
||||
//
|
||||
parser.getToken<std::string>(true, "\n\r\t;");
|
||||
// std::istringstream stream(value);
|
||||
// glm::vec4 data;
|
||||
// stream >> data.r;
|
||||
// stream >> data.g;
|
||||
// stream >> data.b;
|
||||
// stream >> data.a;
|
||||
//
|
||||
// auto it = parse_info->param_mapping.find(key);
|
||||
// if (it == parse_info->param_mapping.end())
|
||||
// parse_info->param_mapping.emplace(
|
||||
// std::make_pair(key, parse_info_s::param_def({data, Priority})));
|
||||
// else if (Priority > it->second.priority) {
|
||||
// parse_info->param_mapping.erase(it);
|
||||
// parse_info->param_mapping.emplace(
|
||||
// std::make_pair(key, parse_info_s::param_def({data, Priority})));
|
||||
// }
|
||||
} else if (key == "shader:" &&
|
||||
(m_shader.empty() || priority > m_shader_priority)) {
|
||||
m_shader = deserialize_random_set(parser);
|
||||
m_shader_priority = priority;
|
||||
} else if (key == "opacity:" && priority > m_opacity_priority) {
|
||||
std::string value = deserialize_random_set(parser);
|
||||
m_opacity = std::stof(value); // m7t: handle exception
|
||||
m_opacity_priority = priority;
|
||||
} else if (key == "selfillum:" && priority > m_selfillum_priority) {
|
||||
std::string value = deserialize_random_set(parser);
|
||||
m_selfillum = std::stof(value); // m7t: handle exception
|
||||
m_selfillum_priority = priority;
|
||||
} else if (key == "glossiness:" /* && Priority > m_glossiness_priority*/) {
|
||||
deserialize_random_set(parser);
|
||||
// glossiness = std::stof(value); // m7t: handle exception
|
||||
// m_glossiness_priority = Priority;
|
||||
} else if (key == "shadow_rank:") {
|
||||
std::string value = deserialize_random_set(parser);
|
||||
m_shadow_rank = std::stoi(value); // m7t: handle exception
|
||||
} else if (key == "size:") {
|
||||
parser.getTokens(2);
|
||||
parser >> m_size.x >> m_size.y;
|
||||
} else {
|
||||
auto const value = parser.getToken<std::string>(true, "\n\r\t ;");
|
||||
if (value == "{") {
|
||||
// unrecognized or ignored token, but comes with attribute block and
|
||||
// potential further nesting go through it and discard the content
|
||||
while (ParseLevel(parser, -1)) {
|
||||
; // all work is done in the header
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// discard mode; ignores all retrieved tokens
|
||||
auto const value{parser.getToken<std::string>(true, "\n\r\t ;")};
|
||||
if (value == "{") {
|
||||
// ignored tokens can come with their own blocks, ignore these recursively
|
||||
// go through it and discard the content
|
||||
while (true == ParseLevel(parser, -1)) {
|
||||
; // all work is done in the header
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true; // return value marks a key: value pair was extracted, nothing
|
||||
// about whether it's recognized
|
||||
}
|
||||
|
||||
bool MaterialAdapterLegacyMatFile::HasNormalMap() const {
|
||||
return m_texture_mapping.find("_normals:") != m_texture_mapping.end() ||
|
||||
m_texture_mapping.find("_normalmap:") != m_texture_mapping.end() ||
|
||||
m_texture_mapping.find("2:") != m_texture_mapping.end();
|
||||
}
|
||||
|
||||
bool MaterialAdapterLegacyMatFile::IsNormalMapShader() const {
|
||||
return m_shader.find("normalmap") != std::string::npos ||
|
||||
m_shader.find("parallax") != std::string::npos;
|
||||
}
|
||||
|
||||
std::optional<float> MaterialAdapterLegacyMatFile::GetOpacity() const {
|
||||
return m_opacity;
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialAdapterInternal> MaterialAdapterSingleTexture::Parse(
|
||||
std::string_view path) {
|
||||
return std::make_shared<MaterialAdapterSingleTexture>(path);
|
||||
}
|
||||
|
||||
std::string_view MaterialAdapterSingleTexture::GetTexturePathForEntry(
|
||||
std::string_view key) const {
|
||||
if (key == "diffuse") {
|
||||
return m_tex_diffuse;
|
||||
}
|
||||
return std::string_view();
|
||||
}
|
||||
|
||||
std::string_view MaterialAdapterSingleTexture::GetShader() const {
|
||||
return "legacy";
|
||||
}
|
||||
|
||||
std::optional<float> MaterialAdapterSingleTexture::GetOpacity() const {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::shared_ptr<MaterialAdapterInternal> MaterialAdapterManul::Parse(
|
||||
std::string_view path) {
|
||||
std::string entries[]{
|
||||
Global.asCurrentTexturePath + std::string(path) + ".manul",
|
||||
std::string(path) + ".manul"};
|
||||
for (auto it = std::begin(entries); it != std::end(entries); ++it) {
|
||||
if (!std::filesystem::exists(*it)) {
|
||||
continue;
|
||||
}
|
||||
auto root = YAML::LoadFile(*it);
|
||||
auto material = std::make_shared<MaterialAdapterManul>();
|
||||
material->m_shader = root["shader"].as<std::string>();
|
||||
for (const auto it : root["textures"]) {
|
||||
material->m_textures[it.first.as<std::string>()] =
|
||||
it.second.as<std::string>();
|
||||
}
|
||||
if (auto alpha_threshold = root["alpha_threshold"];
|
||||
alpha_threshold.IsScalar()) {
|
||||
material->m_alpha_threshold = alpha_threshold.as<float>();
|
||||
}
|
||||
if (auto size_bias = root["max_resolution_bias"]; size_bias.IsScalar())
|
||||
material->m_size_bias = size_bias.as<int>();
|
||||
return material;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
std::string_view MaterialAdapterManul::GetTexturePathForEntry(
|
||||
std::string_view key) const {
|
||||
if (auto it = m_textures.find(std::string(key)); it != m_textures.end()) {
|
||||
return it->second;
|
||||
}
|
||||
return std::string_view();
|
||||
}
|
||||
|
||||
int MaterialAdapterManul::GetTextureSizeBiasForEntry(
|
||||
std::string_view key) const {
|
||||
return m_size_bias;
|
||||
}
|
||||
|
||||
std::string_view MaterialAdapterManul::GetShader() const { return m_shader; }
|
||||
|
||||
std::optional<float> MaterialAdapterManul::GetOpacity() const {
|
||||
return m_alpha_threshold;
|
||||
}
|
||||
|
||||
std::optional<bool> MaterialAdapterInternal::GetMaskedShadowOverride() const {
|
||||
auto threshold = GetOpacity();
|
||||
if (threshold.has_value()) {
|
||||
return !!*threshold;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
94
manul/renderer/source/materialparser.h
Normal file
94
manul/renderer/source/materialparser.h
Normal file
@@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string_view>
|
||||
#include <optional>
|
||||
#include <unordered_map>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
struct MaterialAdapterInternal {
|
||||
virtual ~MaterialAdapterInternal() = default;
|
||||
virtual std::string_view GetTexturePathForEntry(
|
||||
std::string_view key) const = 0;
|
||||
virtual int GetTextureSizeBiasForEntry(
|
||||
std::string_view key) const = 0;
|
||||
virtual std::string_view GetShader() const = 0;
|
||||
virtual int GetShadowRank() const { return 0; }
|
||||
virtual glm::dvec2 GetSize() const { return {-1., -1.}; }
|
||||
virtual std::optional<float> GetOpacity() const = 0;
|
||||
virtual std::optional<bool> GetMaskedShadowOverride() const;
|
||||
};
|
||||
|
||||
struct MaterialAdapter {
|
||||
std::string_view GetTexturePathForEntry(std::string_view key) const;
|
||||
int GetTextureSizeBiasForEntry(std::string_view key) const;
|
||||
std::string_view GetShader() const;
|
||||
int GetShadowRank() const;
|
||||
glm::dvec2 GetSize() const;
|
||||
std::optional<float> GetOpacity() const;
|
||||
bool Parse(std::string_view filepath);
|
||||
std::shared_ptr<MaterialAdapterInternal> m_material_internal;
|
||||
std::optional<bool> GetMaskedShadowOverride() const;
|
||||
};
|
||||
|
||||
struct MaterialAdapterManul : public MaterialAdapterInternal {
|
||||
static std::shared_ptr<MaterialAdapterInternal> Parse(std::string_view path);
|
||||
virtual std::string_view GetTexturePathForEntry(
|
||||
std::string_view key) const override;
|
||||
virtual int GetTextureSizeBiasForEntry(std::string_view key) const override;
|
||||
virtual std::string_view GetShader() const override;
|
||||
virtual std::optional<float> GetOpacity() const override;
|
||||
std::string m_shader;
|
||||
std::unordered_map<std::string, std::string> m_textures;
|
||||
int m_size_bias;
|
||||
std::optional<float> m_alpha_threshold = std::nullopt;
|
||||
glm::dvec2 m_size{-1., -1.};
|
||||
virtual glm::dvec2 GetSize() const override { return m_size; }
|
||||
};
|
||||
|
||||
struct MaterialAdapterLegacyMatFile : public MaterialAdapterInternal {
|
||||
static std::shared_ptr<MaterialAdapterInternal> Parse(std::string_view path);
|
||||
virtual std::string_view GetTexturePathForEntry(
|
||||
std::string_view key) const override;
|
||||
virtual int GetTextureSizeBiasForEntry(std::string_view key) const override {
|
||||
return 0;
|
||||
}
|
||||
virtual std::string_view GetShader() const override;
|
||||
bool ParseLevel(class cParser& parser, int priority);
|
||||
std::optional<float> m_opacity = std::nullopt;
|
||||
int m_shadow_rank;
|
||||
float m_selfillum;
|
||||
std::string m_tex_diffuse;
|
||||
std::string m_tex_normal;
|
||||
std::string m_shader;
|
||||
int m_shader_priority = -1;
|
||||
struct TextureEntry {
|
||||
int m_priority = -1;
|
||||
std::string m_path = "";
|
||||
};
|
||||
glm::dvec2 m_size{-1., -1.};
|
||||
virtual glm::dvec2 GetSize() const override { return m_size; }
|
||||
bool HasNormalMap() const;
|
||||
bool IsNormalMapShader() const;
|
||||
std::unordered_map<std::string, TextureEntry> m_texture_mapping;
|
||||
virtual int GetShadowRank() const override { return m_shadow_rank; }
|
||||
virtual std::optional<float> GetOpacity() const override;
|
||||
int m_opacity_priority = -1;
|
||||
int m_selfillum_priority = -1;
|
||||
int m_diffuse_priority = -1;
|
||||
int m_normal_priority = -1;
|
||||
};
|
||||
|
||||
struct MaterialAdapterSingleTexture : public MaterialAdapterInternal {
|
||||
static std::shared_ptr<MaterialAdapterInternal> Parse(std::string_view path);
|
||||
MaterialAdapterSingleTexture(std::string_view path) : m_tex_diffuse(path){};
|
||||
virtual std::string_view GetTexturePathForEntry(
|
||||
std::string_view key) const override;
|
||||
virtual int GetTextureSizeBiasForEntry(std::string_view key) const override {
|
||||
return 0;
|
||||
}
|
||||
virtual std::string_view GetShader() const override;
|
||||
virtual std::optional<float> GetOpacity() const override;
|
||||
std::string m_tex_diffuse;
|
||||
};
|
||||
10
manul/renderer/source/motioncache.cpp
Normal file
10
manul/renderer/source/motioncache.cpp
Normal file
@@ -0,0 +1,10 @@
|
||||
#include "motioncache.h"
|
||||
|
||||
MotionCacheScope::MotionCacheScope(void const* instance, MotionCache* cache)
|
||||
: m_instance(instance), m_cache(cache) {
|
||||
m_cache->SetActiveScope(this);
|
||||
}
|
||||
|
||||
MotionCacheScope::~MotionCacheScope() {
|
||||
m_cache->UnsetActiveScope(this);
|
||||
}
|
||||
76
manul/renderer/source/motioncache.h
Normal file
76
manul/renderer/source/motioncache.h
Normal file
@@ -0,0 +1,76 @@
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
#include <functional>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
struct MotionCacheId {
|
||||
union {
|
||||
struct {
|
||||
void const* m_instance;
|
||||
void const* m_sub;
|
||||
};
|
||||
struct {
|
||||
size_t m_key[2];
|
||||
};
|
||||
};
|
||||
MotionCacheId(void const* instance, void const* sub)
|
||||
: m_instance(instance), m_sub(sub) {}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::hash<MotionCacheId> {
|
||||
std::size_t operator()(const MotionCacheId& k) const {
|
||||
using hash = std::hash<size_t>;
|
||||
size_t hash_instance = hash()(k.m_key[0]);
|
||||
size_t hash_sub = hash()(k.m_key[1]);
|
||||
return hash_instance ^
|
||||
hash_sub + 0x9e3779b9 + (hash_instance << 6) + (hash_instance >> 2);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct std::equal_to<MotionCacheId> {
|
||||
bool operator()(const MotionCacheId& lhs, const MotionCacheId& rhs) const{
|
||||
return lhs.m_key[0] == rhs.m_key[0] && lhs.m_key[1] == rhs.m_key[1];
|
||||
}
|
||||
};
|
||||
|
||||
struct MotionCacheEntry {
|
||||
glm::dmat4x3 m_cached_transform{};
|
||||
glm::dmat4x3 m_history_transform{};
|
||||
size_t m_cached_frame = static_cast<size_t>(-1);
|
||||
};
|
||||
|
||||
struct MotionCacheScope {
|
||||
friend struct MotionCache;
|
||||
~MotionCacheScope();
|
||||
|
||||
private:
|
||||
MotionCacheScope(void const* instance, struct MotionCache* cache);
|
||||
void const* m_instance;
|
||||
MotionCache* m_cache;
|
||||
};
|
||||
|
||||
struct MotionCache {
|
||||
friend struct MotionCacheScope;
|
||||
[[nodiscard]] MotionCacheScope SetInstance(void const* instance) {
|
||||
return {instance, this};
|
||||
}
|
||||
MotionCacheEntry& Get(void const* sub) {
|
||||
assert(m_active_scope);
|
||||
return m_cache[MotionCacheId{m_active_scope->m_instance, sub}];
|
||||
}
|
||||
|
||||
private:
|
||||
std::unordered_map<MotionCacheId, MotionCacheEntry> m_cache{};
|
||||
MotionCacheScope* m_active_scope{};
|
||||
void SetActiveScope(MotionCacheScope* scope) {
|
||||
assert(!m_active_scope);
|
||||
m_active_scope = scope;
|
||||
}
|
||||
void UnsetActiveScope(const MotionCacheScope* scope) {
|
||||
assert(m_active_scope == scope);
|
||||
m_active_scope = nullptr;
|
||||
}
|
||||
};
|
||||
590
manul/renderer/source/nvmaterial.cpp
Normal file
590
manul/renderer/source/nvmaterial.cpp
Normal file
@@ -0,0 +1,590 @@
|
||||
#include "nvmaterial.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "Logs.h"
|
||||
#include "csm.h"
|
||||
#include "environment.h"
|
||||
#include "gbuffer.h"
|
||||
#include "gbufferblitpass.h"
|
||||
#include "nvrendererbackend.h"
|
||||
#include "nvtexture.h"
|
||||
#include "sky.h"
|
||||
|
||||
bool NvRenderer::MaterialTemplate::CreateBindingSet(size_t pipeline_index,
|
||||
MaterialCache &cache) {
|
||||
// for (size_t i = 0; i < cache.m_pipelines.size(); ++i) {
|
||||
auto pipeline = cache.m_pipelines[pipeline_index];
|
||||
if (!pipeline) return false;
|
||||
|
||||
nvrhi::BindingSetDesc binding_set_desc{};
|
||||
|
||||
auto binding_layout = pipeline->getDesc().bindingLayouts[0];
|
||||
|
||||
if (!m_resource_mappings[pipeline_index].ToBindingSet(
|
||||
binding_set_desc, &cache, binding_layout->getDesc()))
|
||||
return false;
|
||||
|
||||
cache.m_binding_sets[pipeline_index] =
|
||||
m_renderer->GetBackend()->GetDevice()->createBindingSet(binding_set_desc,
|
||||
binding_layout);
|
||||
//}
|
||||
// nvrhi::BindingSetDesc binding_set_desc = nvrhi::BindingSetDesc();
|
||||
// nvrhi::BindingSetDesc binding_set_desc_cube = nvrhi::BindingSetDesc();
|
||||
// nvrhi::BindingSetDesc binding_set_desc_shadow = nvrhi::BindingSetDesc();
|
||||
// nvrhi::static_vector<nvrhi::SamplerHandle, 8 + 1> samplers{};
|
||||
// for (int i = 0; i < m_texture_bindings.size(); ++i) {
|
||||
// const auto &binding = m_texture_bindings[i];
|
||||
// if (binding.m_name.empty()) continue;
|
||||
// auto texture = m_renderer->m_texture_manager->GetRhiTexture(
|
||||
// cache.m_textures[i], pass.m_command_list_preparation);
|
||||
// if (!texture) {
|
||||
// texture = m_renderer->m_texture_manager->GetRhiTexture(
|
||||
// 1, pass.m_command_list_preparation);
|
||||
// }
|
||||
// auto &sampler = samplers.emplace_back();
|
||||
// auto &sampler_cubemap = samplers.emplace_back();
|
||||
// sampler = m_renderer->m_texture_manager->GetSamplerForTraits(
|
||||
// m_renderer->m_texture_manager->GetTraits(cache.m_textures[i]),
|
||||
// RenderPassType::Deferred);
|
||||
// sampler_cubemap = m_renderer->m_texture_manager->GetSamplerForTraits(
|
||||
// m_renderer->m_texture_manager->GetTraits(cache.m_textures[i]),
|
||||
// RenderPassType::CubeMap);
|
||||
// binding_set_desc.addItem(nvrhi::BindingSetItem::Texture_SRV(i, texture));
|
||||
// binding_set_desc.addItem(nvrhi::BindingSetItem::Sampler(i, sampler));
|
||||
// binding_set_desc_cube.addItem(
|
||||
// nvrhi::BindingSetItem::Texture_SRV(i, texture));
|
||||
// binding_set_desc_cube.addItem(
|
||||
// nvrhi::BindingSetItem::Sampler(i, sampler_cubemap));
|
||||
// if (cache.m_masked_shadow && i == m_masked_shadow_texture) {
|
||||
// auto &shadow_sampler = samplers.emplace_back();
|
||||
// shadow_sampler = m_renderer->m_texture_manager->GetSamplerForTraits(
|
||||
// m_renderer->m_texture_manager->GetTraits(cache.m_textures[i]),
|
||||
// RenderPassType::ShadowMap);
|
||||
// binding_set_desc_shadow.addItem(
|
||||
// nvrhi::BindingSetItem::Texture_SRV(0, texture));
|
||||
// binding_set_desc_shadow.addItem(
|
||||
// nvrhi::BindingSetItem::Sampler(0, shadow_sampler));
|
||||
// }
|
||||
// }
|
||||
// cache.m_binding_set =
|
||||
// m_renderer->GetBackend()->GetDevice()->createBindingSet(
|
||||
// binding_set_desc, m_binding_layout);
|
||||
// cache.m_binding_set_cubemap =
|
||||
// m_renderer->GetBackend()->GetDevice()->createBindingSet(
|
||||
// binding_set_desc_cube, m_binding_layout);
|
||||
// if (cache.m_masked_shadow) {
|
||||
// cache.m_binding_set_shadow =
|
||||
// m_renderer->GetBackend()->GetDevice()->createBindingSet(
|
||||
// binding_set_desc_shadow,
|
||||
// m_renderer->m_binding_layout_shadow_masked);
|
||||
// }
|
||||
cache.m_last_texture_updates[pipeline_index] = NvTexture::s_change_counter;
|
||||
return true;
|
||||
}
|
||||
|
||||
nvrhi::IGraphicsPipeline *NvRenderer::MaterialTemplate::GetPipeline(
|
||||
RenderPassType pass_type, DrawType draw_type, bool alpha_masked) const {
|
||||
if (auto pipeline =
|
||||
m_pipelines[Constants::GetPipelineIndex(pass_type, draw_type)])
|
||||
return pipeline;
|
||||
if (pass_type == RenderPassType::ShadowMap) {
|
||||
return m_renderer->m_pso_shadow[Constants::GetDefaultShadowPipelineIndex(
|
||||
draw_type, alpha_masked)];
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NvRenderer::MaterialTemplate::Init(const YAML::Node &conf) {
|
||||
InitResourceRegistry();
|
||||
std::vector<MaResourceMapping> texture_mappings{};
|
||||
std::vector<MaResourceMapping> sampler_mappings{};
|
||||
MaResourceMapping texture_mapping_shadow{};
|
||||
MaResourceMapping sampler_mapping_shadow{};
|
||||
m_pipelines.fill(nullptr);
|
||||
m_masked_shadow_texture = conf["masked_shadow_texture"].as<std::string>();
|
||||
for (const auto it : conf["textures"]) {
|
||||
auto index = it.second["binding"].as<int>();
|
||||
m_texture_bindings.resize(
|
||||
glm::max(m_texture_bindings.size(), static_cast<size_t>(index) + 1));
|
||||
auto &[name, sampler_name, hint, default_texture] =
|
||||
m_texture_bindings[index];
|
||||
|
||||
name = it.first.as<std::string>();
|
||||
sampler_name = fmt::format("{:s}_sampler", name.c_str());
|
||||
|
||||
texture_mappings.emplace_back(
|
||||
MaResourceMapping::Texture_SRV(index, name.c_str()));
|
||||
sampler_mappings.emplace_back(
|
||||
MaResourceMapping::Sampler(index, sampler_name.c_str()));
|
||||
|
||||
RegisterTexture(name.c_str(), 1);
|
||||
RegisterResource(
|
||||
false, "masked_shadow_sampler",
|
||||
GetTextureManager()->GetSamplerForTraits(0, RenderPassType::ShadowMap),
|
||||
nvrhi::ResourceType::Sampler);
|
||||
|
||||
const static std::unordered_map<std::string_view, int> hints{
|
||||
{"color", GL_SRGB_ALPHA}, {"linear", GL_RGBA}, {"normalmap", GL_RG}};
|
||||
hint = hints.at(it.second["hint"].as<std::string_view>());
|
||||
|
||||
if (it.first.Scalar() == conf["masked_shadow_texture"].Scalar()) {
|
||||
texture_mapping_shadow = MaResourceMapping::Texture_SRV(0, name.c_str());
|
||||
sampler_mapping_shadow =
|
||||
MaResourceMapping::Sampler(0, "masked_shadow_sampler");
|
||||
}
|
||||
}
|
||||
std::array<nvrhi::ShaderHandle, static_cast<size_t>(RenderPassType::Num)>
|
||||
pixel_shaders;
|
||||
for (int i = 0; i < pixel_shaders.size(); ++i) {
|
||||
pixel_shaders[i] = m_renderer->GetBackend()->CreateMaterialShader(
|
||||
m_name, static_cast<RenderPassType>(i));
|
||||
}
|
||||
|
||||
{
|
||||
nvrhi::BindingLayoutDesc binding_layout_desc;
|
||||
binding_layout_desc.setVisibility(nvrhi::ShaderType::Pixel);
|
||||
for (int i = 0; i < m_texture_bindings.size(); ++i) {
|
||||
if (m_texture_bindings[i].m_name.empty()) continue;
|
||||
binding_layout_desc.addItem(nvrhi::BindingLayoutItem::Texture_SRV(i))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(i));
|
||||
}
|
||||
m_binding_layout =
|
||||
m_renderer->GetBackend()->GetDevice()->createBindingLayout(
|
||||
binding_layout_desc);
|
||||
}
|
||||
for (size_t i = 0; i < Constants::NumMaterialPasses(); ++i) {
|
||||
auto pass = static_cast<RenderPassType>(i);
|
||||
for (size_t j = 0; j < Constants::NumDrawTypes(); ++j) {
|
||||
auto draw = static_cast<DrawType>(j);
|
||||
auto &mappings =
|
||||
m_resource_mappings[Constants::GetPipelineIndex(pass, draw)];
|
||||
nvrhi::GraphicsPipelineDesc pipeline_desc{};
|
||||
auto pixel_shader = pixel_shaders[static_cast<size_t>(pass)];
|
||||
if (!pixel_shader) {
|
||||
if (pass == RenderPassType::ShadowMap) {
|
||||
mappings.Add(MaResourceMapping::PushConstants<PushConstantsShadow>(1))
|
||||
.Add(texture_mapping_shadow)
|
||||
.Add(sampler_mapping_shadow);
|
||||
}
|
||||
continue;
|
||||
}
|
||||
pipeline_desc.setPixelShader(pixel_shader)
|
||||
.setPrimType(nvrhi::PrimitiveType::TriangleList);
|
||||
|
||||
for (const auto &mapping : texture_mappings) mappings.Add(mapping);
|
||||
for (const auto &mapping : sampler_mappings) mappings.Add(mapping);
|
||||
|
||||
nvrhi::IFramebuffer *framebuffer;
|
||||
pipeline_desc.setInputLayout(
|
||||
m_renderer->m_input_layout[static_cast<size_t>(draw)]);
|
||||
switch (pass) {
|
||||
case RenderPassType::Deferred:
|
||||
case RenderPassType::Forward:
|
||||
pipeline_desc.setVertexShader(
|
||||
m_renderer->m_vertex_shader[static_cast<size_t>(draw)]);
|
||||
break;
|
||||
case RenderPassType::CubeMap:
|
||||
pipeline_desc.setVertexShader(
|
||||
m_renderer->m_vertex_shader_cubemap[static_cast<size_t>(draw)]);
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
switch (pass) {
|
||||
case RenderPassType::Deferred:
|
||||
case RenderPassType::Forward:
|
||||
mappings.Add(MaResourceMapping::PushConstants<PushConstantsDraw>(1))
|
||||
.Add(MaResourceMapping::ConstantBuffer(
|
||||
0, "cb_draw_constants_static"));
|
||||
break;
|
||||
case RenderPassType::CubeMap:
|
||||
mappings
|
||||
.Add(MaResourceMapping::PushConstants<PushConstantsCubemap>(1))
|
||||
.Add(MaResourceMapping::ConstantBuffer(
|
||||
0, "cb_draw_constants_static_cubemap"));
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
switch (pass) {
|
||||
case RenderPassType::Forward:
|
||||
mappings
|
||||
.Add(MaResourceMapping::VolatileConstantBuffer(
|
||||
2, "gbuffer_lighting_constants"))
|
||||
.Add(MaResourceMapping::ConstantBuffer(
|
||||
11, "shadow_projection_buffer"))
|
||||
.Add(MaResourceMapping::Texture_SRV(8, "env_dynamic_diffuse"))
|
||||
.Add(MaResourceMapping::Texture_SRV(9, "env_dynamic_specular"))
|
||||
.Add(MaResourceMapping::Texture_SRV(10, "env_brdf_lut"))
|
||||
.Add(MaResourceMapping::Texture_SRV(11, "shadow_depths"))
|
||||
.Add(MaResourceMapping::Texture_SRV(12, "gbuffer_depth"))
|
||||
.Add(MaResourceMapping::Texture_SRV(14, "sky_aerial_lut"))
|
||||
.Add(MaResourceMapping::Texture_SRV(16, "forwardplus_index_grid_transparent"))
|
||||
.Add(MaResourceMapping::StructuredBuffer_SRV(17, "forwardplus_index_buffer_transparent"))
|
||||
.Add(MaResourceMapping::StructuredBuffer_SRV(18, "forwardplus_light_buffer"))
|
||||
.Add(MaResourceMapping::Sampler(8, "sampler_linear_wrap"))
|
||||
.Add(MaResourceMapping::Sampler(11, "shadow_sampler_comp"))
|
||||
.Add(MaResourceMapping::Sampler(13, "sampler_linear_clamp"));
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
switch (pass) {
|
||||
case RenderPassType::Deferred:
|
||||
framebuffer = m_renderer->m_gbuffer->m_framebuffer;
|
||||
break;
|
||||
case RenderPassType::Forward:
|
||||
framebuffer = m_renderer->m_framebuffer_forward;
|
||||
break;
|
||||
case RenderPassType::CubeMap:
|
||||
framebuffer = m_renderer->m_gbuffer_cube->m_framebuffer;
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
switch (pass) {
|
||||
case RenderPassType::Deferred:
|
||||
case RenderPassType::CubeMap:
|
||||
pipeline_desc.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.enableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Greater))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.enableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullFront())
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget().disableBlend())));
|
||||
break;
|
||||
case RenderPassType::Forward:
|
||||
pipeline_desc.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.disableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Greater))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.enableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullFront())
|
||||
.setBlendState(
|
||||
nvrhi::BlendState()
|
||||
.setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget()
|
||||
.enableBlend()
|
||||
.setBlendOp(nvrhi::BlendOp::Add)
|
||||
.setSrcBlend(nvrhi::BlendFactor::One)
|
||||
.setDestBlend(
|
||||
nvrhi::BlendFactor::OneMinusSrcAlpha))
|
||||
.setRenderTarget(1, nvrhi::BlendState::RenderTarget()
|
||||
.disableBlend())));
|
||||
break;
|
||||
default:;
|
||||
}
|
||||
|
||||
nvrhi::BindingLayoutDesc bl_desc{};
|
||||
bl_desc.visibility = nvrhi::ShaderType::All;
|
||||
// for (const auto &bl : pipeline_desc.bindingLayouts) {
|
||||
// bl_desc.visibility = bl_desc.visibility | bl->getDesc()->visibility;
|
||||
// for (const auto &element : bl->getDesc()->bindings) {
|
||||
// bl_desc.addItem(element);
|
||||
// }
|
||||
// }
|
||||
|
||||
mappings.ToBindingLayout(bl_desc);
|
||||
|
||||
pipeline_desc.bindingLayouts.resize(0);
|
||||
pipeline_desc.addBindingLayout(
|
||||
m_renderer->GetBackend()->GetDevice()->createBindingLayout(bl_desc));
|
||||
|
||||
m_pipelines[Constants::GetPipelineIndex(pass, draw)] =
|
||||
m_renderer->GetBackend()->GetDevice()->createGraphicsPipeline(
|
||||
pipeline_desc, framebuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool NvRenderer::InitMaterials() {
|
||||
m_drawconstant_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateStaticConstantBufferDesc(sizeof(DrawConstants),
|
||||
"Draw Constants")
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
m_cubedrawconstant_buffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateStaticConstantBufferDesc(sizeof(CubeDrawConstants),
|
||||
"Draw Data")
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
RegisterResource(true, "cb_draw_constants_static", m_drawconstant_buffer,
|
||||
nvrhi::ResourceType::ConstantBuffer);
|
||||
RegisterResource(true, "cb_draw_constants_static_cubemap",
|
||||
m_cubedrawconstant_buffer,
|
||||
nvrhi::ResourceType::ConstantBuffer);
|
||||
|
||||
{
|
||||
nvrhi::CommandListHandle command_list =
|
||||
GetBackend()->GetDevice()->createCommandList();
|
||||
command_list->open();
|
||||
CubeDrawConstants data;
|
||||
data.m_face_projection = glm::perspectiveFovRH_ZO(
|
||||
M_PI_2, 1., 1., .1,
|
||||
static_cast<double>(Global.reflectiontune.range_instances));
|
||||
command_list->writeBuffer(m_cubedrawconstant_buffer, &data, sizeof(data));
|
||||
command_list->close();
|
||||
GetBackend()->GetDevice()->executeCommandList(command_list);
|
||||
}
|
||||
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::AllGraphics, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_drawconstant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::PushConstants(
|
||||
1, sizeof(PushConstantsDraw))),
|
||||
m_binding_layout_drawconstants, m_binding_set_drawconstants);
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::AllGraphics, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
|
||||
0, m_cubedrawconstant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::PushConstants(
|
||||
1, sizeof(PushConstantsCubemap))),
|
||||
m_binding_layout_cubedrawconstants, m_binding_set_cubedrawconstants);
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::AllGraphics, 0,
|
||||
nvrhi::BindingSetDesc().addItem(
|
||||
nvrhi::BindingSetItem::PushConstants(1, sizeof(PushConstantsShadow))),
|
||||
m_binding_layout_shadowdrawconstants, m_binding_set_shadowdrawconstants);
|
||||
m_binding_layout_forward = GetBackend()->GetDevice()->createBindingLayout(
|
||||
nvrhi::BindingLayoutDesc()
|
||||
.setVisibility(nvrhi::ShaderType::Pixel)
|
||||
.addItem(nvrhi::BindingLayoutItem::VolatileConstantBuffer(2))
|
||||
.addItem(nvrhi::BindingLayoutItem::ConstantBuffer(11))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(8))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(9))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(10))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(11))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(12))
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(14))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(8))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(11))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(13)));
|
||||
for (int i = 0; i < m_binding_set_forward.size(); ++i) {
|
||||
m_binding_set_forward[i] = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
|
||||
2, m_gbuffer_blit->m_draw_constants))
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(
|
||||
11, m_shadow_map->m_projection_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
8, m_environment->m_dynamic_envmap_diffuse[0]))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
9, m_environment->m_dynamic_envmap_specular[0]))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
10, m_environment->m_brdf_lut))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
11, m_gbuffer_shadow->m_gbuffer_depth))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
12, m_gbuffer->m_gbuffer_depth))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
14, m_sky->m_aerial_lut->m_lut))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
8, m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc().setAllFilters(true))))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
11, m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setReductionType(
|
||||
nvrhi::SamplerReductionType::Comparison)
|
||||
.setComparisonFunc(nvrhi::ComparisonFunc::Greater)
|
||||
.setAllAddressModes(
|
||||
nvrhi::SamplerAddressMode::ClampToEdge)
|
||||
.setAllFilters(true))))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
13, m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(
|
||||
nvrhi::SamplerAddressMode::ClampToEdge)
|
||||
.setAllFilters(true)))),
|
||||
m_binding_layout_forward);
|
||||
}
|
||||
|
||||
m_vertex_shader[static_cast<size_t>(DrawType::Model)] =
|
||||
m_backend->CreateShader("default_vertex", nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader[static_cast<size_t>(DrawType::InstancedModel)] =
|
||||
m_backend->CreateShader("instanced_vertex", nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_shadow[static_cast<size_t>(DrawType::Model)] =
|
||||
m_backend->CreateShader("shadow_vertex", nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_shadow[static_cast<size_t>(DrawType::InstancedModel)] =
|
||||
m_backend->CreateShader("instanced_shadow_vertex",
|
||||
nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_cubemap[static_cast<size_t>(DrawType::Model)] =
|
||||
m_backend->CreateShader("cubemap_vertex", nvrhi::ShaderType::Vertex);
|
||||
m_vertex_shader_cubemap[static_cast<size_t>(DrawType::InstancedModel)] =
|
||||
m_backend->CreateShader("instanced_cubemap_vertex",
|
||||
nvrhi::ShaderType::Vertex);
|
||||
m_pixel_shader_shadow_masked =
|
||||
m_backend->CreateShader("shadow_masked", nvrhi::ShaderType::Pixel);
|
||||
|
||||
nvrhi::VertexAttributeDesc desc[]{
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setBufferIndex(0)
|
||||
.setElementStride(sizeof(gfx::basic_vertex))
|
||||
.setFormat(nvrhi::Format::RGB32_FLOAT)
|
||||
.setName("Position")
|
||||
.setIsInstanced(false)
|
||||
.setOffset(offsetof(gfx::basic_vertex, position)),
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setBufferIndex(0)
|
||||
.setElementStride(sizeof(gfx::basic_vertex))
|
||||
.setFormat(nvrhi::Format::RGB32_FLOAT)
|
||||
.setName("Normal")
|
||||
.setIsInstanced(false)
|
||||
.setOffset(offsetof(gfx::basic_vertex, normal)),
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setBufferIndex(0)
|
||||
.setElementStride(sizeof(gfx::basic_vertex))
|
||||
.setFormat(nvrhi::Format::RG32_FLOAT)
|
||||
.setName("TexCoord")
|
||||
.setIsInstanced(false)
|
||||
.setOffset(offsetof(gfx::basic_vertex, texture)),
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setBufferIndex(0)
|
||||
.setElementStride(sizeof(gfx::basic_vertex))
|
||||
.setFormat(nvrhi::Format::RGBA32_FLOAT)
|
||||
.setName("Tangent")
|
||||
.setIsInstanced(false)
|
||||
.setOffset(offsetof(gfx::basic_vertex, tangent)),
|
||||
nvrhi::VertexAttributeDesc()
|
||||
.setBufferIndex(1)
|
||||
.setElementStride(sizeof(glm::mat3x4))
|
||||
.setFormat(nvrhi::Format::RGBA32_FLOAT)
|
||||
.setName("InstanceTransform")
|
||||
.setIsInstanced(true)
|
||||
.setArraySize(3)
|
||||
.setOffset(0)};
|
||||
m_input_layout[static_cast<size_t>(DrawType::Model)] =
|
||||
m_backend->GetDevice()->createInputLayout(
|
||||
desc, std::size(desc) - 1,
|
||||
m_vertex_shader[static_cast<size_t>(DrawType::Model)]);
|
||||
m_input_layout[static_cast<size_t>(DrawType::InstancedModel)] =
|
||||
m_backend->GetDevice()->createInputLayout(
|
||||
desc, std::size(desc),
|
||||
m_vertex_shader[static_cast<size_t>(DrawType::InstancedModel)]);
|
||||
|
||||
{
|
||||
m_binding_layout_shadow_masked =
|
||||
m_backend->GetDevice()->createBindingLayout(
|
||||
nvrhi::BindingLayoutDesc()
|
||||
.setVisibility(nvrhi::ShaderType::Pixel)
|
||||
.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0)));
|
||||
for (int i = 0; i < Constants::NumDrawTypes(); ++i) {
|
||||
for (int j = 0; j < 2; ++j) {
|
||||
DrawType draw = static_cast<DrawType>(i);
|
||||
bool masked = j;
|
||||
nvrhi::BindingLayoutDesc desc =
|
||||
*m_binding_layout_shadowdrawconstants->getDesc();
|
||||
desc.visibility = nvrhi::ShaderType::All;
|
||||
if (masked)
|
||||
desc.addItem(nvrhi::BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(nvrhi::BindingLayoutItem::Sampler(0));
|
||||
auto binding_layout =
|
||||
GetBackend()->GetDevice()->createBindingLayout(desc);
|
||||
auto pipeline_desc =
|
||||
nvrhi::GraphicsPipelineDesc()
|
||||
.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.enableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Greater))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.disableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullBack()
|
||||
.setDepthBias(1)
|
||||
.setSlopeScaleDepthBias(-4.f))
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0,
|
||||
nvrhi::BlendState::RenderTarget().disableBlend())))
|
||||
.setVertexShader(
|
||||
m_vertex_shader_shadow[static_cast<size_t>(draw)])
|
||||
.setInputLayout(m_input_layout[static_cast<size_t>(draw)]);
|
||||
if (masked) {
|
||||
pipeline_desc.setPixelShader(m_pixel_shader_shadow_masked);
|
||||
}
|
||||
pipeline_desc.addBindingLayout(binding_layout);
|
||||
|
||||
m_pso_shadow[Constants::GetDefaultShadowPipelineIndex(draw, masked)] =
|
||||
GetBackend()->GetDevice()->createGraphicsPipeline(
|
||||
pipeline_desc, m_gbuffer_shadow->m_framebuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
auto vs_line =
|
||||
m_backend->CreateShader("vtx_line", nvrhi::ShaderType::Vertex);
|
||||
auto gs_line =
|
||||
m_backend->CreateShader("geo_line", nvrhi::ShaderType::Geometry);
|
||||
auto ps_line =
|
||||
m_backend->CreateShader("pix_line", nvrhi::ShaderType::Pixel);
|
||||
nvrhi::BindingLayoutHandle binding_layout_line;
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
GetBackend()->GetDevice(), nvrhi::ShaderType::AllGraphics, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_drawconstant_buffer))
|
||||
.addItem(nvrhi::BindingSetItem::PushConstants(
|
||||
1, sizeof(PushConstantsLine))),
|
||||
binding_layout_line, m_binding_set_line);
|
||||
|
||||
m_pso_line = GetBackend()->GetDevice()->createGraphicsPipeline(
|
||||
nvrhi::GraphicsPipelineDesc()
|
||||
.setRenderState(
|
||||
nvrhi::RenderState()
|
||||
.setDepthStencilState(
|
||||
nvrhi::DepthStencilState()
|
||||
.enableDepthTest()
|
||||
.enableDepthWrite()
|
||||
.disableStencil()
|
||||
.setDepthFunc(nvrhi::ComparisonFunc::Greater))
|
||||
.setRasterState(nvrhi::RasterState()
|
||||
.setFillSolid()
|
||||
.enableDepthClip()
|
||||
.disableScissor()
|
||||
.setCullFront())
|
||||
.setBlendState(nvrhi::BlendState().setRenderTarget(
|
||||
0, nvrhi::BlendState::RenderTarget().disableBlend())))
|
||||
.setPrimType(nvrhi::PrimitiveType::LineList)
|
||||
.setVertexShader(vs_line)
|
||||
.setGeometryShader(gs_line)
|
||||
.setPixelShader(ps_line)
|
||||
.setInputLayout(
|
||||
m_input_layout[static_cast<size_t>(DrawType::Model)])
|
||||
.addBindingLayout(binding_layout_line),
|
||||
m_gbuffer->m_framebuffer);
|
||||
}
|
||||
|
||||
auto config = YAML::LoadFile("shaders/project.manul");
|
||||
for (const auto item : config["shaders"]["materials"]) {
|
||||
auto material =
|
||||
std::make_shared<MaterialTemplate>(item.first.as<std::string>(), this);
|
||||
m_material_templates[material->m_name] = material;
|
||||
material->Init(item.second);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
7
manul/renderer/source/nvmaterial.h
Normal file
7
manul/renderer/source/nvmaterial.h
Normal file
@@ -0,0 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
struct NvMaterial {
|
||||
|
||||
|
||||
|
||||
};
|
||||
1
manul/renderer/source/nvmaterial_legacyloader.cpp
Normal file
1
manul/renderer/source/nvmaterial_legacyloader.cpp
Normal file
@@ -0,0 +1 @@
|
||||
#include "nvmaterial.h"
|
||||
1992
manul/renderer/source/nvrenderer.cpp
Normal file
1992
manul/renderer/source/nvrenderer.cpp
Normal file
File diff suppressed because it is too large
Load Diff
413
manul/renderer/source/nvrenderer_d3d12.cpp
Normal file
413
manul/renderer/source/nvrenderer_d3d12.cpp
Normal file
@@ -0,0 +1,413 @@
|
||||
#include "nvrenderer_d3d12.h"
|
||||
|
||||
#include <fmt/format.h>
|
||||
|
||||
#include "Globals.h"
|
||||
#include "Logs.h"
|
||||
#include "config.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
#if LIBMANUL_WITH_D3D12
|
||||
|
||||
#include <GLFW/glfw3native.h>
|
||||
#include <nvrhi/validation.h>
|
||||
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
#define HR_RETURN(op) \
|
||||
hr = (HRESULT)(op); \
|
||||
if (FAILED(hr)) { \
|
||||
ErrorLog(fmt::format(#op " returned HRESULT={}", hr)); \
|
||||
return false; \
|
||||
}
|
||||
|
||||
bool NvRenderer::InitForD3D12(GLFWwindow *Window) {
|
||||
// Create d3d device
|
||||
std::shared_ptr<NvRendererBackend_D3D12> Backend =
|
||||
std::make_shared<NvRendererBackend_D3D12>();
|
||||
m_backend = Backend;
|
||||
|
||||
Backend->m_renderer = this;
|
||||
Backend->m_hwnd = glfwGetWin32Window(Window);
|
||||
|
||||
if (!Backend->CreateDevice()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Backend->CreateSwapChain(Window)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!Backend->CreateRenderTarget()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string NvRendererBackend_D3D12::LoadShaderBlob(
|
||||
const std::string &filename, const std::string &entrypoint) {
|
||||
std::string path = "shaders/shaders_dxil/" + filename;
|
||||
if (entrypoint != "main") path += "_" + entrypoint;
|
||||
path += ".bin";
|
||||
std::ifstream ifs(path, std::ios::binary | std::ios::ate);
|
||||
std::string blob(ifs.tellg(), '\0');
|
||||
ifs.seekg(0, std::ios_base::beg);
|
||||
ifs.read(blob.data(), blob.size());
|
||||
return blob;
|
||||
}
|
||||
|
||||
int NvRendererBackend_D3D12::GetCurrentBackBufferIndex() {
|
||||
return m_swapchain->GetCurrentBackBufferIndex();
|
||||
}
|
||||
|
||||
int NvRendererBackend_D3D12::GetBackBufferCount() {
|
||||
return m_swapchain_desc.BufferCount;
|
||||
}
|
||||
|
||||
nvrhi::TextureHandle NvRendererBackend_D3D12::GetBackBuffer(int index) {
|
||||
return m_RhiSwapChainBuffers[index];
|
||||
}
|
||||
|
||||
bool NvRendererBackend_D3D12::BeginFrame() {
|
||||
WaitForSingleObject(
|
||||
m_FrameFenceEvents[m_swapchain->GetCurrentBackBufferIndex()], INFINITE);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NvRendererBackend_D3D12::SetHDRMetaData(float MaxOutputNits /*=1000.0f*/,
|
||||
float MinOutputNits /*=0.001f*/,
|
||||
float MaxCLL /*=2000.0f*/,
|
||||
float MaxFALL /*=500.0f*/) {
|
||||
HRESULT hr;
|
||||
struct DisplayChromaticities {
|
||||
float RedX;
|
||||
float RedY;
|
||||
float GreenX;
|
||||
float GreenY;
|
||||
float BlueX;
|
||||
float BlueY;
|
||||
float WhiteX;
|
||||
float WhiteY;
|
||||
};
|
||||
|
||||
if (!m_swapchain) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto hdr_config =
|
||||
NvRenderer::Config()->m_display.GetHDRConfig(IsHDRDisplay());
|
||||
|
||||
// Clean the hdr metadata if the display doesn't support HDR
|
||||
// if (!m_hdrSupport) {
|
||||
// ThrowIfFailed(
|
||||
// m_swapChain->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_NONE, 0, nullptr));
|
||||
// return;
|
||||
//}
|
||||
|
||||
static const DisplayChromaticities DisplayChromaticityList[] = {
|
||||
{0.64000f, 0.33000f, 0.30000f, 0.60000f, 0.15000f, 0.06000f, 0.31270f,
|
||||
0.32900f}, // Display Gamut Rec709
|
||||
{0.70800f, 0.29200f, 0.17000f, 0.79700f, 0.13100f, 0.04600f, 0.31270f,
|
||||
0.32900f}, // Display Gamut Rec2020
|
||||
};
|
||||
|
||||
// Select the chromaticity based on HDR format of the DWM.
|
||||
int selectedChroma = 1;
|
||||
// if (true//m_currentSwapChainBitDepth == _16 &&
|
||||
// m_currentSwapChainColorSpace ==
|
||||
// DXGI_COLOR_SPACE_RGB_FULL_G10_NONE_P709) {
|
||||
// selectedChroma = 0;
|
||||
// } else if (m_currentSwapChainBitDepth == _10 &&
|
||||
// m_currentSwapChainColorSpace ==
|
||||
// DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020) {
|
||||
// selectedChroma = 1;
|
||||
// } else {
|
||||
// // Reset the metadata since this is not a supported HDR format.
|
||||
// HR_RETURN(
|
||||
// m_swapChain->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_NONE, 0,
|
||||
// nullptr));
|
||||
// return;
|
||||
// }
|
||||
|
||||
// Set HDR meta data
|
||||
const DisplayChromaticities &Chroma = DisplayChromaticityList[selectedChroma];
|
||||
DXGI_HDR_METADATA_HDR10 HDR10MetaData = {};
|
||||
HDR10MetaData.RedPrimary[0] = static_cast<UINT16>(Chroma.RedX * 50000.0f);
|
||||
HDR10MetaData.RedPrimary[1] = static_cast<UINT16>(Chroma.RedY * 50000.0f);
|
||||
HDR10MetaData.GreenPrimary[0] = static_cast<UINT16>(Chroma.GreenX * 50000.0f);
|
||||
HDR10MetaData.GreenPrimary[1] = static_cast<UINT16>(Chroma.GreenY * 50000.0f);
|
||||
HDR10MetaData.BluePrimary[0] = static_cast<UINT16>(Chroma.BlueX * 50000.0f);
|
||||
HDR10MetaData.BluePrimary[1] = static_cast<UINT16>(Chroma.BlueY * 50000.0f);
|
||||
HDR10MetaData.WhitePoint[0] = static_cast<UINT16>(Chroma.WhiteX * 50000.0f);
|
||||
HDR10MetaData.WhitePoint[1] = static_cast<UINT16>(Chroma.WhiteY * 50000.0f);
|
||||
HDR10MetaData.MaxMasteringLuminance =
|
||||
static_cast<UINT>(hdr_config.GetMaxOutputNits() * 10000.0f);
|
||||
HDR10MetaData.MinMasteringLuminance =
|
||||
static_cast<UINT>(hdr_config.GetMinOutputNits() * 10000.0f);
|
||||
HDR10MetaData.MaxContentLightLevel = static_cast<UINT16>(MaxCLL);
|
||||
HDR10MetaData.MaxFrameAverageLightLevel = static_cast<UINT16>(MaxFALL);
|
||||
if (IsHDRDisplay()) {
|
||||
HR_RETURN(m_swapchain->SetHDRMetaData(DXGI_HDR_METADATA_TYPE_HDR10,
|
||||
sizeof(DXGI_HDR_METADATA_HDR10),
|
||||
&HDR10MetaData))
|
||||
HR_RETURN(
|
||||
m_swapchain->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G2084_NONE_P2020))
|
||||
} else {
|
||||
HR_RETURN(
|
||||
m_swapchain->SetColorSpace1(DXGI_COLOR_SPACE_RGB_FULL_G22_NONE_P709))
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NvRendererBackend_D3D12::Present() {
|
||||
// if (!m_windowVisible)
|
||||
// return;
|
||||
|
||||
auto bufferIndex = m_swapchain->GetCurrentBackBufferIndex();
|
||||
|
||||
UINT presentFlags = 0;
|
||||
if (false /*!vsync_enabled*/ && !Global.bFullScreen && m_TearingSupported)
|
||||
presentFlags |= DXGI_PRESENT_ALLOW_TEARING;
|
||||
|
||||
m_swapchain->Present(1, presentFlags);
|
||||
|
||||
m_FrameFence->SetEventOnCompletion(m_FrameCount,
|
||||
m_FrameFenceEvents[bufferIndex]);
|
||||
m_graphics_queue->Signal(m_FrameFence, m_FrameCount);
|
||||
m_FrameCount++;
|
||||
}
|
||||
|
||||
bool NvRendererBackend_D3D12::IsHDRDisplay() const {
|
||||
return m_output_desc.BitsPerColor > 8 &&
|
||||
!NvRenderer::Config()->m_display.m_disable_hdr;
|
||||
}
|
||||
|
||||
bool NvRendererBackend_D3D12::CreateDevice() {
|
||||
HRESULT hr;
|
||||
HR_RETURN(
|
||||
CreateDXGIFactory2(Global.gfx_gldebug ? DXGI_CREATE_FACTORY_DEBUG : 0,
|
||||
IID_PPV_ARGS(&m_dxgi_factory)))
|
||||
|
||||
if (Global.gfx_gldebug) {
|
||||
nvrhi::RefCountPtr<ID3D12Debug> pDebug;
|
||||
HR_RETURN(D3D12GetDebugInterface(IID_PPV_ARGS(&pDebug)))
|
||||
|
||||
pDebug->EnableDebugLayer();
|
||||
}
|
||||
|
||||
WriteLog("Available graphics adapters:");
|
||||
for (int i = 0;; ++i) {
|
||||
nvrhi::RefCountPtr<IDXGIAdapter> adapter = nullptr;
|
||||
if (FAILED(m_dxgi_factory->EnumAdapters(i, &adapter))) break;
|
||||
DXGI_ADAPTER_DESC desc{};
|
||||
HR_RETURN(adapter->GetDesc(&desc));
|
||||
std::string str_desc{};
|
||||
str_desc.resize(
|
||||
wcstombs(nullptr, desc.Description, std::size(desc.Description)));
|
||||
wcstombs(str_desc.data(), desc.Description, str_desc.size());
|
||||
WriteLog(fmt::format("- adapter{}: {}", i, str_desc));
|
||||
}
|
||||
|
||||
if (FAILED(m_dxgi_factory->EnumAdapters(
|
||||
NvRenderer::Config()->m_display.m_adapter_index, &m_dxgi_adapter))) {
|
||||
ErrorLog(fmt::format("Invalid adapter index: {}",
|
||||
NvRenderer::Config()->m_display.m_adapter_index));
|
||||
return false;
|
||||
}
|
||||
|
||||
nvrhi::RefCountPtr<IDXGIOutput> output;
|
||||
nvrhi::RefCountPtr<IDXGIOutput6> output6;
|
||||
if (FAILED(m_dxgi_adapter->EnumOutputs(
|
||||
NvRenderer::Config()->m_display.m_output_index, &output))) {
|
||||
ErrorLog(fmt::format("Invalid output index: {}",
|
||||
NvRenderer::Config()->m_display.m_output_index));
|
||||
}
|
||||
|
||||
HR_RETURN(output->QueryInterface<IDXGIOutput6>(&output6));
|
||||
HR_RETURN(output6->GetDesc1(&m_output_desc));
|
||||
|
||||
// {
|
||||
// DXGI_ADAPTER_DESC aDesc;
|
||||
// m_DxgiAdapter->GetDesc(&aDesc);
|
||||
//
|
||||
// m_RendererString = GetAdapterName(aDesc);
|
||||
// m_IsNvidia = IsNvDeviceID(aDesc.VendorId);
|
||||
// }
|
||||
|
||||
HR_RETURN(D3D12CreateDevice(m_dxgi_adapter, D3D_FEATURE_LEVEL_12_0,
|
||||
IID_PPV_ARGS(&m_d3d_device)))
|
||||
|
||||
if (Global.gfx_gldebug) {
|
||||
nvrhi::RefCountPtr<ID3D12InfoQueue> pInfoQueue;
|
||||
m_d3d_device->QueryInterface(&pInfoQueue);
|
||||
|
||||
if (pInfoQueue) {
|
||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_CORRUPTION, true);
|
||||
pInfoQueue->SetBreakOnSeverity(D3D12_MESSAGE_SEVERITY_ERROR, true);
|
||||
|
||||
D3D12_MESSAGE_ID disableMessageIDs[] = {
|
||||
D3D12_MESSAGE_ID_CLEARDEPTHSTENCILVIEW_MISMATCHINGCLEARVALUE,
|
||||
D3D12_MESSAGE_ID_COMMAND_LIST_STATIC_DESCRIPTOR_RESOURCE_DIMENSION_MISMATCH, // descriptor validation doesn't understand acceleration structures
|
||||
};
|
||||
|
||||
D3D12_INFO_QUEUE_FILTER filter = {};
|
||||
filter.DenyList.pIDList = disableMessageIDs;
|
||||
filter.DenyList.NumIDs =
|
||||
sizeof(disableMessageIDs) / sizeof(disableMessageIDs[0]);
|
||||
pInfoQueue->AddStorageFilterEntries(&filter);
|
||||
}
|
||||
}
|
||||
|
||||
D3D12_COMMAND_QUEUE_DESC queueDesc;
|
||||
ZeroMemory(&queueDesc, sizeof(queueDesc));
|
||||
queueDesc.Flags = D3D12_COMMAND_QUEUE_FLAG_NONE;
|
||||
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_HIGH;
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_DIRECT;
|
||||
queueDesc.NodeMask = 1;
|
||||
HR_RETURN(m_d3d_device->CreateCommandQueue(&queueDesc,
|
||||
IID_PPV_ARGS(&m_graphics_queue)))
|
||||
m_graphics_queue->SetName(L"Graphics Queue");
|
||||
|
||||
if (true) {
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COMPUTE;
|
||||
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
|
||||
HR_RETURN(m_d3d_device->CreateCommandQueue(&queueDesc,
|
||||
IID_PPV_ARGS(&m_compute_queue)))
|
||||
m_compute_queue->SetName(L"Compute Queue");
|
||||
}
|
||||
|
||||
if (true) {
|
||||
queueDesc.Type = D3D12_COMMAND_LIST_TYPE_COPY;
|
||||
queueDesc.Priority = D3D12_COMMAND_QUEUE_PRIORITY_NORMAL;
|
||||
HR_RETURN(m_d3d_device->CreateCommandQueue(&queueDesc,
|
||||
IID_PPV_ARGS(&m_copy_queue)))
|
||||
m_copy_queue->SetName(L"Copy Queue");
|
||||
}
|
||||
|
||||
nvrhi::d3d12::DeviceDesc deviceDesc;
|
||||
deviceDesc.errorCB = GetMessageCallback();
|
||||
deviceDesc.pDevice = m_d3d_device;
|
||||
deviceDesc.pGraphicsCommandQueue = m_graphics_queue;
|
||||
deviceDesc.pComputeCommandQueue = m_compute_queue;
|
||||
deviceDesc.pCopyCommandQueue = m_copy_queue;
|
||||
|
||||
m_device = nvrhi::d3d12::createDevice(deviceDesc);
|
||||
|
||||
if (Global.gfx_gldebug) {
|
||||
m_device = nvrhi::validation::createValidationLayer(m_device);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NvRendererBackend_D3D12::CreateSwapChain(GLFWwindow *window) {
|
||||
HRESULT hr;
|
||||
ZeroMemory(&m_swapchain_desc, sizeof(m_swapchain_desc));
|
||||
|
||||
if (Global.bFullScreen) {
|
||||
const GLFWvidmode *mode = glfwGetVideoMode(glfwGetWindowMonitor(window));
|
||||
m_swapchain_desc.Width = mode->width;
|
||||
m_swapchain_desc.Height = mode->height;
|
||||
} else {
|
||||
int fbWidth = 0, fbHeight = 0;
|
||||
glfwGetFramebufferSize(window, &fbWidth, &fbHeight);
|
||||
m_swapchain_desc.Width = fbWidth;
|
||||
m_swapchain_desc.Height = fbHeight;
|
||||
}
|
||||
|
||||
m_swapchain_desc.BufferCount = 3;
|
||||
m_swapchain_desc.BufferUsage =
|
||||
DXGI_USAGE_SHADER_INPUT | DXGI_USAGE_RENDER_TARGET_OUTPUT;
|
||||
m_swapchain_desc.SampleDesc.Count = 1;
|
||||
m_swapchain_desc.SampleDesc.Quality = 0;
|
||||
m_swapchain_desc.SwapEffect = DXGI_SWAP_EFFECT_FLIP_DISCARD;
|
||||
m_swapchain_desc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
|
||||
m_swapchain_desc.Format = IsHDRDisplay() ? DXGI_FORMAT_R10G10B10A2_UNORM : DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
|
||||
nvrhi::RefCountPtr<IDXGIFactory5> pDxgiFactory5;
|
||||
if (SUCCEEDED(m_dxgi_factory->QueryInterface(IID_PPV_ARGS(&pDxgiFactory5)))) {
|
||||
BOOL supported = 0;
|
||||
if (SUCCEEDED(pDxgiFactory5->CheckFeatureSupport(
|
||||
DXGI_FEATURE_PRESENT_ALLOW_TEARING, &supported, sizeof(supported))))
|
||||
m_TearingSupported = (supported != 0);
|
||||
}
|
||||
|
||||
if (m_TearingSupported) {
|
||||
m_swapchain_desc.Flags |= DXGI_SWAP_CHAIN_FLAG_ALLOW_TEARING;
|
||||
}
|
||||
|
||||
m_fullscreen_desc = {};
|
||||
m_fullscreen_desc.RefreshRate.Numerator = 0;
|
||||
m_fullscreen_desc.RefreshRate.Denominator = 1;
|
||||
m_fullscreen_desc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_PROGRESSIVE;
|
||||
m_fullscreen_desc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
|
||||
m_fullscreen_desc.Windowed = !Global.bFullScreen;
|
||||
|
||||
nvrhi::RefCountPtr<IDXGISwapChain1> pSwapChain1;
|
||||
HR_RETURN(m_dxgi_factory->CreateSwapChainForHwnd(
|
||||
m_graphics_queue, m_hwnd, &m_swapchain_desc, &m_fullscreen_desc, nullptr,
|
||||
&pSwapChain1))
|
||||
|
||||
HR_RETURN(pSwapChain1->QueryInterface(IID_PPV_ARGS(&m_swapchain)))
|
||||
|
||||
if (!CreateRenderTarget()) return false;
|
||||
|
||||
HR_RETURN(m_d3d_device->CreateFence(0, D3D12_FENCE_FLAG_NONE,
|
||||
IID_PPV_ARGS(&m_FrameFence)));
|
||||
|
||||
for (UINT bufferIndex = 0; bufferIndex < m_swapchain_desc.BufferCount;
|
||||
bufferIndex++) {
|
||||
m_FrameFenceEvents.push_back(CreateEvent(nullptr, false, true, nullptr));
|
||||
}
|
||||
if (!SetHDRMetaData()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NvRendererBackend_D3D12::CreateRenderTarget() {
|
||||
m_SwapChainBuffers.resize(m_swapchain_desc.BufferCount);
|
||||
m_RhiSwapChainBuffers.resize(m_swapchain_desc.BufferCount);
|
||||
|
||||
HRESULT hr;
|
||||
|
||||
for (UINT n = 0; n < m_swapchain_desc.BufferCount; n++) {
|
||||
HR_RETURN(m_swapchain->GetBuffer(n, IID_PPV_ARGS(&m_SwapChainBuffers[n])))
|
||||
|
||||
nvrhi::TextureDesc textureDesc;
|
||||
textureDesc.width = m_swapchain_desc.Width;
|
||||
textureDesc.height = m_swapchain_desc.Height;
|
||||
textureDesc.sampleCount = m_swapchain_desc.SampleDesc.Count;
|
||||
textureDesc.sampleQuality = m_swapchain_desc.SampleDesc.Quality;
|
||||
textureDesc.format = IsHDRDisplay() ? nvrhi::Format::R10G10B10A2_UNORM : nvrhi::Format::RGBA8_UNORM;
|
||||
textureDesc.debugName = "SwapChainBuffer";
|
||||
textureDesc.isRenderTarget = true;
|
||||
textureDesc.isUAV = false;
|
||||
textureDesc.initialState = nvrhi::ResourceStates::Present;
|
||||
textureDesc.keepInitialState = true;
|
||||
|
||||
m_RhiSwapChainBuffers[n] = m_device->createHandleForNativeTexture(
|
||||
nvrhi::ObjectTypes::D3D12_Resource,
|
||||
nvrhi::Object(m_SwapChainBuffers[n]), textureDesc);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NvRendererBackend_D3D12::ReleaseRenderTarget() {
|
||||
// Make sure that all frames have finished rendering
|
||||
m_device->waitForIdle();
|
||||
|
||||
// Release all in-flight references to the render targets
|
||||
m_device->runGarbageCollection();
|
||||
|
||||
// Set the events so that WaitForSingleObject in OneFrame will not hang later
|
||||
for (auto e : m_FrameFenceEvents) SetEvent(e);
|
||||
|
||||
// Release the old buffers because ResizeBuffers requires that
|
||||
m_RhiSwapChainBuffers.clear();
|
||||
m_SwapChainBuffers.clear();
|
||||
}
|
||||
|
||||
#endif
|
||||
72
manul/renderer/source/nvrenderer_d3d12.h
Normal file
72
manul/renderer/source/nvrenderer_d3d12.h
Normal file
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
#if LIBMANUL_WITH_D3D12
|
||||
|
||||
#include <Windows.h>
|
||||
#include <dxgi1_6.h>
|
||||
#include <dxgidebug.h>
|
||||
#include <nvrhi/d3d12.h>
|
||||
|
||||
class NvRendererBackend_D3D12 : public NvRendererBackend {
|
||||
friend class NvRenderer;
|
||||
|
||||
virtual std::string LoadShaderBlob(const std::string &filename,
|
||||
const std::string &entrypoint) override;
|
||||
virtual int GetCurrentBackBufferIndex() override;
|
||||
virtual int GetBackBufferCount() override;
|
||||
virtual nvrhi::TextureHandle GetBackBuffer(int index) override;
|
||||
virtual bool BeginFrame() override;
|
||||
virtual void Present() override;
|
||||
virtual bool IsHDRDisplay() const override;
|
||||
virtual void UpdateWindowSize() override{}
|
||||
|
||||
bool SetHDRMetaData(float MaxOutputNits = 1000.0f,
|
||||
float MinOutputNits = 0.001f, float MaxCLL = 2000.0f,
|
||||
float MaxFALL = 500.0f);
|
||||
|
||||
// Window handle
|
||||
HWND m_hwnd;
|
||||
|
||||
// Direct3D resources
|
||||
nvrhi::RefCountPtr<ID3D12Device> m_d3d_device;
|
||||
nvrhi::RefCountPtr<ID3D12CommandQueue> m_graphics_queue;
|
||||
nvrhi::RefCountPtr<ID3D12CommandQueue> m_aux_graphics_queue;
|
||||
nvrhi::RefCountPtr<ID3D12CommandQueue> m_compute_queue;
|
||||
nvrhi::RefCountPtr<ID3D12CommandQueue> m_copy_queue;
|
||||
nvrhi::RefCountPtr<IDXGIFactory2> m_dxgi_factory;
|
||||
nvrhi::RefCountPtr<IDXGIAdapter> m_dxgi_adapter;
|
||||
nvrhi::RefCountPtr<IDXGISwapChain4> m_swapchain;
|
||||
DXGI_SWAP_CHAIN_DESC1 m_swapchain_desc;
|
||||
DXGI_SWAP_CHAIN_FULLSCREEN_DESC m_fullscreen_desc;
|
||||
DXGI_OUTPUT_DESC1 m_output_desc;
|
||||
|
||||
bool m_TearingSupported = false;
|
||||
|
||||
std::vector<nvrhi::RefCountPtr<ID3D12Resource>> m_SwapChainBuffers;
|
||||
std::vector<nvrhi::TextureHandle> m_RhiSwapChainBuffers;
|
||||
nvrhi::RefCountPtr<ID3D12Fence> m_FrameFence;
|
||||
std::vector<HANDLE> m_FrameFenceEvents;
|
||||
|
||||
UINT64 m_FrameCount = 1;
|
||||
|
||||
// RHI resources
|
||||
|
||||
// Utility functions
|
||||
bool CreateDevice();
|
||||
bool CreateSwapChain(GLFWwindow *window);
|
||||
bool CreateRenderTarget();
|
||||
void ReleaseRenderTarget();
|
||||
virtual void LoadShaderBlobs() override;
|
||||
|
||||
nvrhi::DeviceHandle m_device;
|
||||
|
||||
public:
|
||||
nvrhi::IDevice *GetDevice() override { return m_device.Get(); }
|
||||
};
|
||||
|
||||
#endif
|
||||
19
manul/renderer/source/nvrenderer_imgui.cpp
Normal file
19
manul/renderer/source/nvrenderer_imgui.cpp
Normal file
@@ -0,0 +1,19 @@
|
||||
#include "nvrenderer_imgui.h"
|
||||
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
bool NvImguiRenderer::Init() { return m_rhi.init(m_backend.get()); }
|
||||
|
||||
void NvImguiRenderer::Shutdown() {}
|
||||
|
||||
void NvImguiRenderer::BeginFrame() { m_rhi.beginFrame(); }
|
||||
|
||||
void NvImguiRenderer::Render() {
|
||||
m_rhi.render(m_backend->GetCurrentFramebuffer());
|
||||
}
|
||||
|
||||
NvImguiRenderer::NvImguiRenderer(NvRenderer *renderer)
|
||||
: m_backend(renderer->m_backend) {
|
||||
m_rhi.renderer = m_backend->GetDevice();
|
||||
m_rhi.textureManager = renderer->GetTextureManager();
|
||||
}
|
||||
17
manul/renderer/source/nvrenderer_imgui.h
Normal file
17
manul/renderer/source/nvrenderer_imgui.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "imgui_nvrhi.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
class NvImguiRenderer : public imgui_renderer {
|
||||
virtual bool Init() override;
|
||||
virtual void Shutdown() override;
|
||||
virtual void BeginFrame() override;
|
||||
virtual void Render() override;
|
||||
|
||||
std::shared_ptr<class NvRendererBackend> m_backend;
|
||||
ImGui_NVRHI m_rhi;
|
||||
|
||||
public:
|
||||
NvImguiRenderer(class NvRenderer *renderer);
|
||||
};
|
||||
1088
manul/renderer/source/nvrenderer_vulkan.cpp
Normal file
1088
manul/renderer/source/nvrenderer_vulkan.cpp
Normal file
File diff suppressed because it is too large
Load Diff
182
manul/renderer/source/nvrenderer_vulkan.h
Normal file
182
manul/renderer/source/nvrenderer_vulkan.h
Normal file
@@ -0,0 +1,182 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
#if LIBMANUL_WITH_VULKAN
|
||||
|
||||
#define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1
|
||||
#include <nvrhi/vulkan.h>
|
||||
|
||||
#include <vulkan/vulkan.hpp>
|
||||
|
||||
class NvRendererBackend_Vulkan : public NvRendererBackend {
|
||||
friend class NvRenderer;
|
||||
|
||||
nvrhi::IDevice *GetDevice() override;
|
||||
std::string LoadShaderBlob(const std::string &filename,
|
||||
const std::string &entrypoint) override;
|
||||
virtual int GetCurrentBackBufferIndex() override;
|
||||
virtual int GetBackBufferCount() override;
|
||||
virtual nvrhi::TextureHandle GetBackBuffer(int index) override;
|
||||
virtual bool BeginFrame() override;
|
||||
virtual void Present() override;
|
||||
virtual void UpdateWindowSize() override;
|
||||
bool IsHDRDisplay() const override;
|
||||
|
||||
// bool SetHDRMetaData(float MaxOutputNits = 1000.0f,
|
||||
// float MinOutputNits = 0.001f, float MaxCLL = 2000.0f,
|
||||
// float MaxFALL = 500.0f);
|
||||
|
||||
//// Window handle
|
||||
// HWND m_hwnd;
|
||||
//
|
||||
//// Direct3D resources
|
||||
// nvrhi::RefCountPtr<ID3D12Device> m_d3d_device;
|
||||
// nvrhi::RefCountPtr<ID3D12CommandQueue> m_graphics_queue;
|
||||
// nvrhi::RefCountPtr<ID3D12CommandQueue> m_aux_graphics_queue;
|
||||
// nvrhi::RefCountPtr<ID3D12CommandQueue> m_compute_queue;
|
||||
// nvrhi::RefCountPtr<ID3D12CommandQueue> m_copy_queue;
|
||||
// nvrhi::RefCountPtr<IDXGIFactory2> m_dxgi_factory;
|
||||
// nvrhi::RefCountPtr<IDXGIAdapter> m_dxgi_adapter;
|
||||
// nvrhi::RefCountPtr<IDXGISwapChain4> m_swapchain;
|
||||
// DXGI_SWAP_CHAIN_DESC1 m_swapchain_desc;
|
||||
// DXGI_SWAP_CHAIN_FULLSCREEN_DESC m_fullscreen_desc;
|
||||
// DXGI_OUTPUT_DESC1 m_output_desc;
|
||||
|
||||
// bool m_TearingSupported = false;
|
||||
//
|
||||
// std::vector<nvrhi::RefCountPtr<ID3D12Resource>> m_SwapChainBuffers;
|
||||
// std::vector<nvrhi::TextureHandle> m_RhiSwapChainBuffers;
|
||||
// nvrhi::RefCountPtr<ID3D12Fence> m_FrameFence;
|
||||
// std::vector<HANDLE> m_FrameFenceEvents;
|
||||
|
||||
// UINT64 m_FrameCount = 1;
|
||||
|
||||
// RHI resources
|
||||
|
||||
// Utility functions
|
||||
// bool CreateDevice();
|
||||
// bool CreateSwapChain(GLFWwindow *window);
|
||||
// bool CreateRenderTarget();
|
||||
// void ReleaseRenderTarget();
|
||||
virtual void LoadShaderBlobs() override;
|
||||
|
||||
public:
|
||||
bool CreateInstance();
|
||||
bool CreateDevice();
|
||||
bool CreateSwapChain();
|
||||
void ResizeSwapChain();
|
||||
[[nodiscard]] PFN_vkGetDeviceProcAddr GetDeviceProcAddr();
|
||||
|
||||
private:
|
||||
int32_t m_BackBufferWidth;
|
||||
int32_t m_BackBufferHeight;
|
||||
bool m_VsyncEnabled;
|
||||
bool m_EnableNvrhiValidationLayer;
|
||||
bool m_EnableDebugRuntime = false;
|
||||
bool createInstance();
|
||||
bool createWindowSurface();
|
||||
void installDebugCallback();
|
||||
bool pickPhysicalDevice();
|
||||
bool findQueueFamilies(vk::PhysicalDevice physicalDevice);
|
||||
bool createDevice();
|
||||
bool createSwapChain();
|
||||
void destroySwapChain();
|
||||
|
||||
struct VulkanExtensionSet {
|
||||
std::unordered_set<std::string> instance;
|
||||
std::unordered_set<std::string> layers;
|
||||
std::unordered_set<std::string> device;
|
||||
};
|
||||
|
||||
// minimal set of required extensions
|
||||
VulkanExtensionSet enabledExtensions = {
|
||||
// instance
|
||||
{
|
||||
VK_KHR_GET_PHYSICAL_DEVICE_PROPERTIES_2_EXTENSION_NAME,
|
||||
VK_EXT_SWAPCHAIN_COLOR_SPACE_EXTENSION_NAME,
|
||||
},
|
||||
// layers
|
||||
{},
|
||||
// device
|
||||
{
|
||||
VK_KHR_MAINTENANCE1_EXTENSION_NAME,
|
||||
VK_EXT_SAMPLER_FILTER_MINMAX_EXTENSION_NAME,
|
||||
},
|
||||
};
|
||||
|
||||
// optional extensions
|
||||
VulkanExtensionSet optionalExtensions = {
|
||||
// instance
|
||||
{VK_EXT_DEBUG_UTILS_EXTENSION_NAME},
|
||||
// layers
|
||||
{},
|
||||
// device
|
||||
{VK_EXT_DEBUG_MARKER_EXTENSION_NAME,
|
||||
VK_EXT_DESCRIPTOR_INDEXING_EXTENSION_NAME,
|
||||
VK_KHR_BUFFER_DEVICE_ADDRESS_EXTENSION_NAME,
|
||||
VK_NV_MESH_SHADER_EXTENSION_NAME,
|
||||
VK_KHR_FRAGMENT_SHADING_RATE_EXTENSION_NAME,
|
||||
VK_KHR_SYNCHRONIZATION_2_EXTENSION_NAME,
|
||||
VK_KHR_MAINTENANCE_4_EXTENSION_NAME,
|
||||
VK_KHR_SWAPCHAIN_MUTABLE_FORMAT_EXTENSION_NAME},
|
||||
};
|
||||
|
||||
std::string m_RendererString;
|
||||
|
||||
vk::DynamicLoader m_dynamicLoader;
|
||||
|
||||
vk::Instance m_VulkanInstance;
|
||||
vk::DebugReportCallbackEXT m_DebugReportCallback;
|
||||
|
||||
vk::SurfaceKHR m_WindowSurface;
|
||||
|
||||
vk::PhysicalDevice m_VulkanPhysicalDevice;
|
||||
|
||||
vk::Device m_VulkanDevice;
|
||||
vk::Queue m_GraphicsQueue;
|
||||
vk::Queue m_ComputeQueue;
|
||||
vk::Queue m_TransferQueue;
|
||||
vk::Queue m_PresentQueue;
|
||||
|
||||
int m_GraphicsQueueFamily = -1;
|
||||
int m_ComputeQueueFamily = -1;
|
||||
int m_TransferQueueFamily = -1;
|
||||
int m_PresentQueueFamily = -1;
|
||||
|
||||
int m_SwapChainBufferCount;
|
||||
|
||||
vk::SurfaceFormatKHR m_SwapChainFormat;
|
||||
vk::SwapchainKHR m_SwapChain;
|
||||
|
||||
struct SwapChainImage {
|
||||
vk::Image image;
|
||||
nvrhi::TextureHandle rhiHandle;
|
||||
};
|
||||
|
||||
std::vector<SwapChainImage> m_SwapChainImages;
|
||||
uint32_t m_SwapChainIndex = static_cast<uint32_t>(-1);
|
||||
int m_MaxFramesInFlight = 2;
|
||||
|
||||
nvrhi::vulkan::DeviceHandle m_NvrhiDevice;
|
||||
nvrhi::DeviceHandle m_ValidationLayer;
|
||||
|
||||
nvrhi::CommandListHandle m_BarrierCommandList;
|
||||
std::vector<vk::Semaphore> m_PresentSemaphores;
|
||||
uint32_t m_PresentSemaphoreIndex = 0;
|
||||
|
||||
std::queue<nvrhi::EventQueryHandle> m_FramesInFlight;
|
||||
std::vector<nvrhi::EventQueryHandle> m_QueryPool;
|
||||
|
||||
GLFWwindow *m_Window;
|
||||
|
||||
bool m_EnableComputeQueue;
|
||||
bool m_EnableCopyQueue;
|
||||
bool m_SwapChainMutableFormatSupported = false;
|
||||
bool m_BufferDeviceAddressSupported = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
86
manul/renderer/source/nvrendererbackend.cpp
Normal file
86
manul/renderer/source/nvrendererbackend.cpp
Normal file
@@ -0,0 +1,86 @@
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
#include "Logs.h"
|
||||
#include <fmt/format.h>
|
||||
|
||||
void NvRendererMessageCallback::message(nvrhi::MessageSeverity severity,
|
||||
const char *messageText) {
|
||||
switch (severity) {
|
||||
case nvrhi::MessageSeverity::Info:
|
||||
case nvrhi::MessageSeverity::Warning:
|
||||
WriteLog(messageText);
|
||||
break;
|
||||
case nvrhi::MessageSeverity::Error:
|
||||
ErrorLog(messageText);
|
||||
//__debugbreak();
|
||||
break;
|
||||
case nvrhi::MessageSeverity::Fatal:
|
||||
ErrorLog(messageText);
|
||||
//__debugbreak();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NvRendererBackend::Init() {
|
||||
LoadShaderBlobs();
|
||||
for (int i = 0; i < GetBackBufferCount(); ++i) {
|
||||
m_framebuffers.emplace_back(GetDevice()->createFramebuffer(
|
||||
nvrhi::FramebufferDesc().addColorAttachment(
|
||||
nvrhi::FramebufferAttachment().setTexture(GetBackBuffer(i)))));
|
||||
}
|
||||
}
|
||||
|
||||
nvrhi::FramebufferHandle NvRendererBackend::GetCurrentFramebuffer() {
|
||||
return m_framebuffers[GetCurrentBackBufferIndex()];
|
||||
}
|
||||
|
||||
nvrhi::ShaderHandle NvRendererBackend::CreateShader(const std::string &name,
|
||||
nvrhi::ShaderType type) {
|
||||
if (auto blob_found = m_shader_blobs.find(name);
|
||||
blob_found != m_shader_blobs.end()) {
|
||||
const auto &blob = blob_found->second;
|
||||
nvrhi::ShaderDesc shader_desc{};
|
||||
shader_desc.shaderType = type;
|
||||
shader_desc.debugName = name;
|
||||
shader_desc.entryName = blob.m_entrypoint;
|
||||
return GetDevice()->createShader(shader_desc, blob.m_blob.data(),
|
||||
blob.m_blob.size());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
nvrhi::ShaderHandle NvRendererBackend::CreateMaterialShader(
|
||||
const std::string &name, NvRenderer::RenderPassType pass) {
|
||||
if (auto blob_found = m_material_blobs.find(name);
|
||||
blob_found != m_material_blobs.end()) {
|
||||
const auto &blob = blob_found->second[static_cast<size_t>(pass)];
|
||||
WriteLog(name);
|
||||
WriteLog(blob.m_entrypoint);
|
||||
WriteLog(fmt::format("{:d}", static_cast<int>(pass)));
|
||||
if (blob.m_blob.empty()) return nullptr;
|
||||
nvrhi::ShaderDesc shader_desc{};
|
||||
shader_desc.shaderType = nvrhi::ShaderType::Pixel;
|
||||
shader_desc.debugName = name;
|
||||
shader_desc.entryName = blob.m_entrypoint;
|
||||
return GetDevice()->createShader(shader_desc, blob.m_blob.data(),
|
||||
blob.m_blob.size());
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void NvRendererBackend::AddMaterialShaderBlob(std::string_view material,
|
||||
std::string_view pass,
|
||||
std::string blob,
|
||||
const std::string &entrypoint) {
|
||||
const static std::unordered_map<std::string_view, NvRenderer::RenderPassType>
|
||||
material_passes{{"deferred", NvRenderer::RenderPassType::Deferred},
|
||||
{"forward", NvRenderer::RenderPassType::Forward},
|
||||
{"cubemap", NvRenderer::RenderPassType::CubeMap}};
|
||||
m_material_blobs[std::string(material)][static_cast<size_t>(
|
||||
material_passes.at(pass))] = {entrypoint, blob};
|
||||
}
|
||||
|
||||
void NvRendererBackend::AddShaderBlob(std::string_view shader, std::string blob,
|
||||
const std::string &entrypoint) {
|
||||
m_shader_blobs[std::string(shader)] = {entrypoint, blob};
|
||||
}
|
||||
58
manul/renderer/source/nvrendererbackend.h
Normal file
58
manul/renderer/source/nvrendererbackend.h
Normal file
@@ -0,0 +1,58 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
struct ShaderDefine {
|
||||
std::string m_name;
|
||||
std::string m_definition;
|
||||
};
|
||||
|
||||
class NvRendererBackend {
|
||||
protected:
|
||||
friend class NvRenderer;
|
||||
NvRenderer *m_renderer;
|
||||
virtual std::string LoadShaderBlob(const std::string &fileName,
|
||||
const std::string &entryName) = 0;
|
||||
virtual bool BeginFrame() = 0;
|
||||
virtual void Present() = 0;
|
||||
virtual void UpdateWindowSize() = 0;
|
||||
virtual int GetCurrentBackBufferIndex() = 0;
|
||||
virtual int GetBackBufferCount() = 0;
|
||||
virtual nvrhi::TextureHandle GetBackBuffer(int index) = 0;
|
||||
class NvRendererMessageCallback *GetMessageCallback() const {
|
||||
return m_renderer->m_message_callback.get();
|
||||
}
|
||||
void AddMaterialShaderBlob(std::string_view material, std::string_view pass,
|
||||
std::string blob, const std::string &entrypoint);
|
||||
void AddShaderBlob(std::string_view shader, std::string blob,
|
||||
const std::string &entrypoint);
|
||||
virtual void LoadShaderBlobs() {}
|
||||
struct ShaderBlob {
|
||||
std::string m_entrypoint;
|
||||
std::string m_blob;
|
||||
};
|
||||
std::unordered_map<std::string, ShaderBlob> m_shader_blobs;
|
||||
std::unordered_map<
|
||||
std::string,
|
||||
std::array<ShaderBlob, NvRenderer::Constants::NumMaterialPasses()>>
|
||||
m_material_blobs;
|
||||
|
||||
public:
|
||||
void Init();
|
||||
virtual bool IsHDRDisplay() const { return false; }
|
||||
// nvrhi::DeviceHandle m_device;
|
||||
virtual nvrhi::IDevice *GetDevice() { return nullptr; };
|
||||
std::vector<nvrhi::FramebufferHandle> m_framebuffers;
|
||||
nvrhi::FramebufferHandle GetCurrentFramebuffer();
|
||||
nvrhi::ShaderHandle CreateShader(const std::string &name,
|
||||
nvrhi::ShaderType type);
|
||||
nvrhi::ShaderHandle CreateMaterialShader(const std::string &name,
|
||||
NvRenderer::RenderPassType pass);
|
||||
};
|
||||
|
||||
class NvRendererMessageCallback : public nvrhi::IMessageCallback {
|
||||
virtual void message(nvrhi::MessageSeverity severity,
|
||||
const char *messageText) override;
|
||||
};
|
||||
512
manul/renderer/source/nvtexture.cpp
Normal file
512
manul/renderer/source/nvtexture.cpp
Normal file
@@ -0,0 +1,512 @@
|
||||
#include "nvtexture.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
#include <Globals.h>
|
||||
#include <PyInt.h>
|
||||
#include <application.h>
|
||||
#include <dictionary.h>
|
||||
#include <fmt/format.h>
|
||||
#include <utilities.h>
|
||||
|
||||
#include "Logs.h"
|
||||
// #include "Texture.h"
|
||||
#include "nvrendererbackend.h"
|
||||
#include "stbi/stb_image.h"
|
||||
#define STB_IMAGE_RESIZE2_IMPLEMENTATION
|
||||
#include "stbi/stb_image_resize2.h"
|
||||
#undef STB_IMAGE_RESIZE2_IMPLEMENTATION
|
||||
|
||||
uint64_t NvTexture::s_change_counter = 0;
|
||||
|
||||
void NvTexture::Load(int size_bias) {
|
||||
if (m_sz_texture->is_stub()) {
|
||||
m_width = 2;
|
||||
m_height = 2;
|
||||
auto &[pitch, data] = m_data.emplace_back();
|
||||
pitch = m_width * 4;
|
||||
m_format = nvrhi::Format::RGBA8_UNORM;
|
||||
data.resize(pitch * m_height, '\0');
|
||||
return;
|
||||
}
|
||||
std::string buf{};
|
||||
{
|
||||
std::ifstream file(fmt::format("{}{}", m_sz_texture->get_name().data(),
|
||||
m_sz_texture->get_type().data()),
|
||||
std::ios::binary | std::ios::ate);
|
||||
buf.resize(file.tellg(), '\0');
|
||||
file.seekg(0);
|
||||
file.read(buf.data(), buf.size());
|
||||
};
|
||||
stbi_set_flip_vertically_on_load(true);
|
||||
if (LoadDDS(buf, size_bias)) {
|
||||
} else if (int channels; stbi_uc *source = stbi_load_from_memory(
|
||||
reinterpret_cast<stbi_uc const *>(buf.data()),
|
||||
buf.size(), &m_width, &m_height, &channels, 4)) {
|
||||
int mipcount =
|
||||
static_cast<int>(floor(log2(std::max(m_width, m_height)))) + 1;
|
||||
|
||||
m_has_alpha = channels == 4;
|
||||
|
||||
m_format =
|
||||
m_srgb ? nvrhi::Format::SRGBA8_UNORM : nvrhi::Format::RGBA8_UNORM;
|
||||
int width = m_width, prev_width = m_width, height = m_height,
|
||||
prev_height = m_height;
|
||||
for (int i = 0; i < mipcount; ++i) {
|
||||
auto &[pitch, data] = m_data.emplace_back();
|
||||
pitch = width * 4;
|
||||
data.resize(pitch * height, '\0');
|
||||
if (!i) {
|
||||
memcpy(data.data(), source, data.size());
|
||||
} else {
|
||||
stbir_resize(m_data[i - 1].second.data(), prev_width, prev_height,
|
||||
prev_width * 4, data.data(), width, height, width * 4,
|
||||
STBIR_4CHANNEL,
|
||||
m_srgb ? STBIR_TYPE_UINT8_SRGB : STBIR_TYPE_UINT8,
|
||||
STBIR_EDGE_WRAP, STBIR_FILTER_MITCHELL);
|
||||
}
|
||||
prev_width = std::exchange(width, std::max(1, width >> 1));
|
||||
prev_height = std::exchange(height, std::max(1, height >> 1));
|
||||
}
|
||||
|
||||
stbi_image_free(source);
|
||||
} else if (m_sz_texture->get_type() == ".tga") {
|
||||
std::stringstream ss(buf, std::ios::in | std::ios::binary);
|
||||
// Read the header of the TGA, compare it with the known headers for
|
||||
// compressed and uncompressed TGAs
|
||||
unsigned char tgaheader[18];
|
||||
ss.read((char *)tgaheader, sizeof(unsigned char) * 18);
|
||||
|
||||
while (tgaheader[0] > 0) {
|
||||
--tgaheader[0];
|
||||
|
||||
unsigned char temp;
|
||||
ss.read((char *)&temp, sizeof(unsigned char));
|
||||
}
|
||||
|
||||
m_width = tgaheader[13] * 256 + tgaheader[12];
|
||||
m_height = tgaheader[15] * 256 + tgaheader[14];
|
||||
m_format =
|
||||
m_srgb ? nvrhi::Format::SRGBA8_UNORM : nvrhi::Format::RGBA8_UNORM;
|
||||
int const bytesperpixel = tgaheader[16] / 8;
|
||||
|
||||
// check whether width, height an BitsPerPixel are valid
|
||||
if ((m_width <= 0) || (m_height <= 0) ||
|
||||
((bytesperpixel != 1) && (bytesperpixel != 3) &&
|
||||
(bytesperpixel != 4))) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_has_alpha = false;
|
||||
|
||||
auto &[pitch, data] = m_data.emplace_back();
|
||||
pitch = m_width * 4;
|
||||
// allocate the data buffer
|
||||
int const datasize = pitch * m_height;
|
||||
data.resize(datasize);
|
||||
|
||||
// call the appropriate loader-routine
|
||||
if (tgaheader[2] == 2) {
|
||||
// uncompressed TGA
|
||||
// rgb or greyscale image, expand to bgra
|
||||
unsigned char buffer[4] = {255, 255, 255,
|
||||
255}; // alpha channel will be white
|
||||
|
||||
unsigned int *datapointer = (unsigned int *)&data[0];
|
||||
unsigned int *bufferpointer = (unsigned int *)&buffer[0];
|
||||
|
||||
int const pixelcount = m_width * m_height;
|
||||
|
||||
for (int i = 0; i < pixelcount; ++i) {
|
||||
ss.read((char *)&buffer[0], sizeof(unsigned char) * bytesperpixel);
|
||||
if (bytesperpixel == 1) {
|
||||
// expand greyscale data
|
||||
buffer[1] = buffer[0];
|
||||
buffer[2] = buffer[0];
|
||||
}
|
||||
std::swap(buffer[0], buffer[2]);
|
||||
// copy all four values in one operation
|
||||
(*datapointer) = (*bufferpointer);
|
||||
++datapointer;
|
||||
}
|
||||
} else if (tgaheader[2] == 10) {
|
||||
// compressed TGA
|
||||
int currentpixel = 0;
|
||||
|
||||
unsigned char buffer[4] = {255, 255, 255, 255};
|
||||
const int pixelcount = m_width * m_height;
|
||||
|
||||
unsigned int *datapointer = (unsigned int *)&data[0];
|
||||
unsigned int *bufferpointer = (unsigned int *)&buffer[0];
|
||||
|
||||
do {
|
||||
unsigned char chunkheader = 0;
|
||||
|
||||
ss.read((char *)&chunkheader, sizeof(unsigned char));
|
||||
|
||||
if ((chunkheader & 0x80) == 0) {
|
||||
// if the high bit is not set, it means it is the number of RAW color
|
||||
// packets, plus 1
|
||||
for (int i = 0; i <= chunkheader; ++i) {
|
||||
ss.read((char *)&buffer[0], bytesperpixel);
|
||||
m_has_alpha |= bytesperpixel == 4 && buffer[3] != 255;
|
||||
|
||||
if (bytesperpixel == 1) {
|
||||
// expand greyscale data
|
||||
buffer[1] = buffer[0];
|
||||
buffer[2] = buffer[0];
|
||||
}
|
||||
std::swap(buffer[0], buffer[2]);
|
||||
// copy all four values in one operation
|
||||
(*datapointer) = (*bufferpointer);
|
||||
|
||||
++datapointer;
|
||||
++currentpixel;
|
||||
}
|
||||
} else {
|
||||
// rle chunk, the color supplied afterwards is reapeated header + 1
|
||||
// times (not including the highest bit)
|
||||
chunkheader &= ~0x80;
|
||||
// read the current color
|
||||
ss.read((char *)&buffer[0], bytesperpixel);
|
||||
m_has_alpha |= bytesperpixel == 4 && buffer[3] != 255;
|
||||
|
||||
if (bytesperpixel == 1) {
|
||||
// expand greyscale data
|
||||
buffer[1] = buffer[0];
|
||||
buffer[2] = buffer[0];
|
||||
}
|
||||
std::swap(buffer[0], buffer[2]);
|
||||
// copy the color into the image data as many times as dictated
|
||||
for (int i = 0; i <= chunkheader; ++i) {
|
||||
(*datapointer) = (*bufferpointer);
|
||||
++datapointer;
|
||||
++currentpixel;
|
||||
}
|
||||
}
|
||||
|
||||
} while (currentpixel < pixelcount);
|
||||
}
|
||||
}
|
||||
int max_size = Global.iMaxTextureSize >> size_bias;
|
||||
while (m_data.size() > 1) {
|
||||
if (m_width <= max_size && m_height <= max_size) {
|
||||
break;
|
||||
}
|
||||
m_width = std::max(m_width >> 1, 1);
|
||||
m_height = std::max(m_height >> 1, 1);
|
||||
m_data.erase(m_data.begin());
|
||||
}
|
||||
}
|
||||
|
||||
void NvTexture::set_components_hint(int format_hint) {
|
||||
m_srgb = format_hint == GL_SRGB || format_hint == GL_SRGB8 ||
|
||||
format_hint == GL_SRGB_ALPHA || format_hint == GL_SRGB8_ALPHA8;
|
||||
}
|
||||
|
||||
void NvTexture::make_from_memory(size_t width, size_t height,
|
||||
const uint8_t *data) {
|
||||
m_data.clear();
|
||||
m_rhi_texture = nullptr;
|
||||
auto &[pitch, slice] = m_data.emplace_back();
|
||||
m_format = nvrhi::Format::RGBA8_UNORM;
|
||||
pitch = 4 * width;
|
||||
slice.resize(pitch * height);
|
||||
memcpy(slice.data(), data, slice.size());
|
||||
}
|
||||
|
||||
void NvTexture::update_from_memory(size_t width, size_t height,
|
||||
const uint8_t *data) {
|
||||
auto renderer = dynamic_cast<NvRenderer *>(GfxRenderer.get());
|
||||
if (!renderer) return;
|
||||
auto backend = renderer->GetBackend();
|
||||
if (width != m_width || height != m_height ||
|
||||
m_format != nvrhi::Format::RGBA8_UNORM || !m_rhi_texture) {
|
||||
m_data.clear();
|
||||
m_width = width;
|
||||
m_height = height;
|
||||
auto &[pitch, slice] = m_data.emplace_back();
|
||||
m_format = nvrhi::Format::RGBA8_UNORM;
|
||||
pitch = 4 * width;
|
||||
slice.resize(pitch * height);
|
||||
m_rhi_texture = backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName(std::string(m_sz_texture->get_name()))
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setMipLevels(m_data.size())
|
||||
.setFormat(m_format)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
m_last_change = ++s_change_counter;
|
||||
}
|
||||
auto &slice = std::get<1>(m_data.front());
|
||||
memcpy(slice.data(), data, slice.size());
|
||||
nvrhi::CommandListHandle command_list =
|
||||
backend->GetDevice()->createCommandList(
|
||||
nvrhi::CommandListParameters()
|
||||
.setQueueType(nvrhi::CommandQueue::Copy)
|
||||
.setEnableImmediateExecution(false));
|
||||
command_list->open();
|
||||
for (int mip = 0; mip < m_data.size(); ++mip) {
|
||||
const auto &[pitch, data] = m_data[mip];
|
||||
command_list->writeTexture(m_rhi_texture, 0, mip, data.data(), pitch);
|
||||
}
|
||||
command_list->close();
|
||||
backend->GetDevice()->executeCommandList(command_list,
|
||||
nvrhi::CommandQueue::Copy);
|
||||
}
|
||||
|
||||
bool NvTexture::IsLoaded() const { return false; }
|
||||
|
||||
NvTextureManager::NvTextureManager(NvRenderer *renderer)
|
||||
: m_backend(renderer->m_backend.get()) {}
|
||||
|
||||
size_t NvTextureManager::FetchTexture(std::string path, int format_hint,
|
||||
int size_bias, bool unload_on_location) {
|
||||
if (contains(path, '|')) {
|
||||
path.erase(path.find('|')); // po | może być nazwa kolejnej tekstury
|
||||
}
|
||||
|
||||
std::pair<std::string, std::string> locator; // resource name, resource type
|
||||
std::string traits;
|
||||
|
||||
// discern textures generated by a script
|
||||
// TBD: support file: for file resources?
|
||||
auto const isgenerated{path.find("make:") == 0};
|
||||
auto const isinternalsrc{path.find("internal_src:") == 0};
|
||||
// process supplied resource name
|
||||
if (isgenerated || isinternalsrc) {
|
||||
// generated resource
|
||||
// scheme:(user@)path?query
|
||||
|
||||
// remove scheme indicator
|
||||
path.erase(0, path.find(':') + 1);
|
||||
// TODO: extract traits specification from the query
|
||||
// clean up slashes
|
||||
erase_leading_slashes(path);
|
||||
} else {
|
||||
// regular file resource
|
||||
// (filepath/)(#)filename.extension(:traits)
|
||||
|
||||
// extract trait specifications
|
||||
auto const traitpos = path.rfind(':');
|
||||
if (traitpos != std::string::npos) {
|
||||
// po dwukropku mogą być podane dodatkowe informacje niebędące nazwą
|
||||
// tekstury
|
||||
if (path.size() > traitpos + 1) {
|
||||
traits = path.substr(traitpos + 1);
|
||||
}
|
||||
path.erase(traitpos);
|
||||
}
|
||||
// potentially trim file type indicator since we check for multiple types
|
||||
erase_extension(path);
|
||||
// clean up slashes
|
||||
erase_leading_slashes(path);
|
||||
path = ToLower(path);
|
||||
// temporary code for legacy assets -- textures with names beginning with #
|
||||
// are to be sharpened
|
||||
if ((starts_with(path, "#")) || (contains(path, "/#"))) {
|
||||
traits += '#';
|
||||
}
|
||||
}
|
||||
// try to locate requested texture in the databank
|
||||
// TBD, TODO: include trait specification in the resource id in the databank?
|
||||
|
||||
{
|
||||
const std::array<std::string, 3> filenames{
|
||||
Global.asCurrentTexturePath + path, path, szTexturePath + path};
|
||||
for (const auto &filename : filenames) {
|
||||
if (auto found = m_texture_map.find(filename);
|
||||
found != m_texture_map.end())
|
||||
return found->second;
|
||||
}
|
||||
}
|
||||
|
||||
// if the lookup fails...
|
||||
if (isgenerated) {
|
||||
// TODO: verify presence of the generator script
|
||||
locator.first = path;
|
||||
locator.second = "make:";
|
||||
} else if (isinternalsrc) {
|
||||
locator.first = path;
|
||||
locator.second = "internalsrc:";
|
||||
} else {
|
||||
// ...for file resources check if it's on disk
|
||||
locator = texture_manager::find_on_disk(path);
|
||||
if (true == locator.first.empty()) {
|
||||
// there's nothing matching in the databank nor on the disk, report
|
||||
// failure
|
||||
ErrorLog("Bad file: failed to locate texture file \"" + path + "\"",
|
||||
logtype::file);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
auto &new_texture = m_texture_cache.emplace_back();
|
||||
auto index = m_texture_cache.size();
|
||||
m_texture_map.emplace(locator.first, index);
|
||||
|
||||
new_texture = std::make_shared<NvTexture>();
|
||||
|
||||
auto sz_texture = std::make_shared<opengl_texture>();
|
||||
new_texture->m_sz_texture = sz_texture;
|
||||
sz_texture->is_texstub = isgenerated;
|
||||
sz_texture->name = locator.first;
|
||||
sz_texture->type = locator.second;
|
||||
sz_texture->traits = traits;
|
||||
sz_texture->components_hint = format_hint;
|
||||
|
||||
new_texture->set_components_hint(format_hint);
|
||||
|
||||
new_texture->Load(size_bias);
|
||||
WriteLog("Created texture object for \"" + locator.first + "\"",
|
||||
logtype::texture);
|
||||
|
||||
if (unload_on_location) {
|
||||
new_texture->m_gc_slot = m_unloadable_textures.size();
|
||||
auto &gc_slot = m_unloadable_textures.emplace_back();
|
||||
gc_slot.m_index = index - 1;
|
||||
} else {
|
||||
new_texture->m_gc_slot = static_cast<size_t>(-1);
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
bool NvTexture::CreateRhiTexture() {
|
||||
if (m_rhi_texture) return true;
|
||||
m_last_change = ++s_change_counter;
|
||||
auto renderer = dynamic_cast<NvRenderer *>(GfxRenderer.get());
|
||||
if (!renderer) return false;
|
||||
auto backend = renderer->GetBackend();
|
||||
m_rhi_texture = renderer->GetBackend()->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName(std::string(m_sz_texture->get_name()))
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setMipLevels(m_data.size())
|
||||
.setFormat(m_format)
|
||||
.setInitialState(nvrhi::ResourceStates::CopyDest)
|
||||
.setKeepInitialState(true));
|
||||
nvrhi::CommandListHandle command_list =
|
||||
backend->GetDevice()->createCommandList(
|
||||
nvrhi::CommandListParameters()
|
||||
.setQueueType(nvrhi::CommandQueue::Copy)
|
||||
.setEnableImmediateExecution(false));
|
||||
command_list->open();
|
||||
for (int mip = 0; mip < m_data.size(); ++mip) {
|
||||
const auto &[pitch, data] = m_data[mip];
|
||||
command_list->writeTexture(m_rhi_texture, 0, mip, data.data(), pitch);
|
||||
}
|
||||
command_list->close();
|
||||
backend->GetDevice()->executeCommandList(command_list,
|
||||
nvrhi::CommandQueue::Copy);
|
||||
if (m_sz_texture->get_type() == "make:") {
|
||||
auto const components{Split(std::string(m_sz_texture->get_name()), '?')};
|
||||
|
||||
auto dictionary = std::make_shared<dictionary_source>(components.back());
|
||||
|
||||
auto rt = std::make_shared<python_rt>();
|
||||
rt->shared_tex = this;
|
||||
|
||||
if (!Application.request(
|
||||
{ToLower(components.front()), dictionary, rt})) /*__debugbreak()*/
|
||||
;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool NvTextureManager::IsValidHandle(size_t handle) {
|
||||
return handle > 0 && handle <= m_texture_cache.size();
|
||||
}
|
||||
|
||||
NvTexture *NvTextureManager::GetTexture(size_t handle) {
|
||||
if (!handle || handle > m_texture_cache.size()) {
|
||||
return nullptr;
|
||||
}
|
||||
return m_texture_cache[handle - 1].get();
|
||||
}
|
||||
|
||||
nvrhi::ITexture *NvTextureManager::GetRhiTexture(
|
||||
size_t handle, nvrhi::ICommandList *command_list) {
|
||||
if (!IsValidHandle(handle)) {
|
||||
return nullptr;
|
||||
}
|
||||
const auto &texture = m_texture_cache[handle - 1];
|
||||
// if (!texture.m_rhi_texture) {
|
||||
// texture.m_rhi_texture = m_backend->GetDevice()->createTexture(
|
||||
// nvrhi::TextureDesc()
|
||||
// .setDebugName(texture.m_sz_texture.name)
|
||||
// .setWidth(texture.m_width)
|
||||
// .setHeight(texture.m_height)
|
||||
// .setMipLevels(texture.m_mipcount)
|
||||
// .setFormat(texture.m_format)
|
||||
// .setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
// .setKeepInitialState(true));
|
||||
//
|
||||
// for (int mip = 0; mip < texture.m_mipcount; ++mip) {
|
||||
// const auto &[pitch, data] = texture.m_data[mip];
|
||||
// command_list->writeTexture(texture.m_rhi_texture, 0, mip, data.data(),
|
||||
// pitch);
|
||||
// }
|
||||
// }
|
||||
texture->CreateRhiTexture();
|
||||
return texture->m_rhi_texture;
|
||||
}
|
||||
|
||||
TextureTraitFlags NvTextureManager::GetTraits(size_t handle) {
|
||||
if (!IsValidHandle(handle)) {
|
||||
return 0;
|
||||
}
|
||||
return m_texture_cache[handle - 1]->GetTraits();
|
||||
}
|
||||
|
||||
void NvTextureManager::UpdateLastUse(size_t handle,
|
||||
const glm::dvec3 &location) {
|
||||
if (!IsValidHandle(handle)) {
|
||||
return;
|
||||
}
|
||||
const auto &texture = m_texture_cache[handle - 1];
|
||||
if (texture->m_gc_slot < m_unloadable_textures.size()) {
|
||||
m_unloadable_textures[texture->m_gc_slot].m_last_position_requested =
|
||||
location;
|
||||
}
|
||||
}
|
||||
|
||||
nvrhi::SamplerHandle NvTextureManager::GetSamplerForTraits(
|
||||
TextureTraitFlags traits, NvRenderer::RenderPassType pass) {
|
||||
switch (pass) {
|
||||
case NvRenderer::RenderPassType::CubeMap:
|
||||
case NvRenderer::RenderPassType::ShadowMap:
|
||||
traits[MaTextureTraits_Sharpen] = false;
|
||||
traits[MaTextureTraits_NoAnisotropy] = true;
|
||||
traits[MaTextureTraits_NoMipBias] = true;
|
||||
break;
|
||||
}
|
||||
auto &sampler = m_samplers[traits];
|
||||
if (!sampler) {
|
||||
nvrhi::SamplerDesc desc =
|
||||
nvrhi::SamplerDesc()
|
||||
.setAddressU(traits[MaTextureTraits_ClampS]
|
||||
? nvrhi::SamplerAddressMode::Clamp
|
||||
: nvrhi::SamplerAddressMode::Wrap)
|
||||
.setAddressV(traits[MaTextureTraits_ClampT]
|
||||
? nvrhi::SamplerAddressMode::Clamp
|
||||
: nvrhi::SamplerAddressMode::Wrap)
|
||||
.setAllFilters(true)
|
||||
.setMipFilter(false)
|
||||
.setMaxAnisotropy(traits[MaTextureTraits_NoAnisotropy] ? 0.f : 16.f)
|
||||
.setMipBias(traits[MaTextureTraits_NoMipBias] ? 0.f : -1.76f);
|
||||
sampler = m_backend->GetDevice()->createSampler(desc);
|
||||
}
|
||||
return sampler;
|
||||
}
|
||||
|
||||
void NvTextureManager::Cleanup(const glm::dvec3 &location) {
|
||||
for (const auto &slot : m_unloadable_textures) {
|
||||
if (glm::distance2(slot.m_last_position_requested, location) >
|
||||
Global.BaseDrawRange * Global.BaseDrawRange) {
|
||||
m_texture_cache[slot.m_index]->m_rhi_texture = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
102
manul/renderer/source/nvtexture.h
Normal file
102
manul/renderer/source/nvtexture.h
Normal file
@@ -0,0 +1,102 @@
|
||||
#pragma once
|
||||
|
||||
#include <bitset>
|
||||
#include <memory>
|
||||
#include <unordered_map>
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include "interfaces/ITexture.h"
|
||||
#include "nvrenderer/nvrenderer_enums.h"
|
||||
|
||||
enum MaTextureTraits {
|
||||
MaTextureTraits_Sharpen,
|
||||
MaTextureTraits_ClampS,
|
||||
MaTextureTraits_ClampT,
|
||||
|
||||
MaTextureTraits_NoMipBias,
|
||||
MaTextureTraits_NoAnisotropy,
|
||||
|
||||
MaTextureTraits_Num
|
||||
};
|
||||
|
||||
using TextureTraitFlags = std::bitset<MaTextureTraits_Num>;
|
||||
|
||||
struct opengl_texture;
|
||||
|
||||
struct NvTexture : public ITexture {
|
||||
virtual bool create(bool Static = false) override {
|
||||
return CreateRhiTexture();
|
||||
}
|
||||
virtual int get_width() const override { return m_width; }
|
||||
virtual int get_height() const override { return m_height; }
|
||||
virtual size_t get_id() const override {
|
||||
return reinterpret_cast<size_t>(m_rhi_texture.Get());
|
||||
}
|
||||
virtual void release() override {}
|
||||
virtual void make_stub() override {}
|
||||
virtual std::string_view get_traits() const override { return ""; }
|
||||
virtual std::string_view get_name() const override {
|
||||
return m_sz_texture->get_name();
|
||||
}
|
||||
virtual std::string_view get_type() const override {
|
||||
return m_sz_texture->get_type();
|
||||
}
|
||||
virtual bool is_stub() const override { return false; }
|
||||
virtual bool get_has_alpha() const override { return m_has_alpha; }
|
||||
virtual bool get_is_ready() const override { return m_rhi_texture; }
|
||||
virtual void set_components_hint(int format_hint) override;
|
||||
virtual void make_from_memory(size_t width, size_t height,
|
||||
const uint8_t* data) override;
|
||||
virtual void update_from_memory(size_t width, size_t height,
|
||||
const uint8_t* data) override;
|
||||
|
||||
void Load(int size_bias);
|
||||
bool LoadDDS(std::string& data, int size_bias);
|
||||
bool IsLoaded() const;
|
||||
std::shared_ptr<ITexture> m_sz_texture;
|
||||
nvrhi::TextureHandle m_rhi_texture;
|
||||
std::vector<std::pair<int, std::string>> m_data;
|
||||
TextureTraitFlags GetTraits() const { return 0; }
|
||||
int m_width;
|
||||
int m_height;
|
||||
int m_mipcount;
|
||||
int m_slicecount;
|
||||
bool m_srgb;
|
||||
bool m_bc;
|
||||
bool m_has_alpha;
|
||||
nvrhi::Format m_format;
|
||||
size_t m_gc_slot;
|
||||
bool CreateRhiTexture();
|
||||
uint64_t m_last_change;
|
||||
static uint64_t s_change_counter;
|
||||
uint64_t m_own_handle;
|
||||
};
|
||||
|
||||
class NvTextureManager {
|
||||
public:
|
||||
struct TextureGCSlot {
|
||||
size_t m_index;
|
||||
glm::dvec3 m_last_position_requested;
|
||||
};
|
||||
NvTextureManager(class NvRenderer* renderer);
|
||||
size_t FetchTexture(std::string path, int format_hint, int size_bias,
|
||||
bool unload_on_location);
|
||||
void UpdateLastUse(size_t handle, const glm::dvec3& location);
|
||||
bool IsValidHandle(size_t handle);
|
||||
NvTexture* GetTexture(size_t handle);
|
||||
nvrhi::ITexture* GetRhiTexture(size_t handle,
|
||||
nvrhi::ICommandList* command_list = nullptr);
|
||||
TextureTraitFlags GetTraits(size_t handle);
|
||||
nvrhi::SamplerHandle GetSamplerForTraits(TextureTraitFlags traits,
|
||||
RendererEnums::RenderPassType pass);
|
||||
std::vector<TextureGCSlot> m_unloadable_textures;
|
||||
|
||||
void Cleanup(const glm::dvec3& location);
|
||||
|
||||
private:
|
||||
std::unordered_map<TextureTraitFlags, nvrhi::SamplerHandle> m_samplers;
|
||||
class NvRendererBackend* m_backend;
|
||||
std::unordered_map<std::string, size_t> m_texture_map;
|
||||
std::vector<std::shared_ptr<NvTexture>> m_texture_cache;
|
||||
};
|
||||
94
manul/renderer/source/quadtree.cpp
Normal file
94
manul/renderer/source/quadtree.cpp
Normal file
@@ -0,0 +1,94 @@
|
||||
#include "nvrenderer/quadtree.h"
|
||||
|
||||
void QuadTreeBuilder::Node::Insert(uint32_t index, glm::dvec3 min_,
|
||||
glm::dvec3 max_, int level) {
|
||||
if (level > 0) {
|
||||
int child = GetChildIndex(.5 * (min_ + max_));
|
||||
if (!m_children[child]) {
|
||||
m_children[child] = std::make_shared<Node>(GetChildBounds(child));
|
||||
}
|
||||
m_children[child]->Insert(index, min_, max_, level - 1);
|
||||
} else {
|
||||
m_leaves.emplace_back(.5 * (max_ + min_), .5 * (max_ - min_), index);
|
||||
}
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (compMin(m_actual_min) < -1.e10) {
|
||||
__debugbreak();
|
||||
}
|
||||
if (compMax(m_actual_max) > 1.e10) {
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
|
||||
m_actual_min = min(min_, m_actual_min);
|
||||
m_actual_max = max(max_, m_actual_max);
|
||||
|
||||
#ifndef NDEBUG
|
||||
if (compMax(glm::abs(m_actual_min)) > 1.e10) {
|
||||
__debugbreak();
|
||||
}
|
||||
if (compMax(glm::abs(m_actual_max)) > 1.e10) {
|
||||
__debugbreak();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
QuadTreeBuilder::QuadTreeBuilder(double min_x, double min_z, double max_x,
|
||||
double max_z)
|
||||
: m_root(std::make_shared<Node>(min_x, min_z, max_x, max_z)),
|
||||
m_min(min_x, -std::numeric_limits<double>::max(), min_z),
|
||||
m_max(max_x, std::numeric_limits<double>::max(), max_z),
|
||||
m_max_levels(32) {
|
||||
// Ensure outer bounds are square
|
||||
glm::dvec2 origin = .5 * (m_max + m_min).xz;
|
||||
glm::dvec2 extent = .5 * (m_max - m_min).xz;
|
||||
extent = glm::dvec2(glm::compMax(extent));
|
||||
m_min.xz = origin - extent;
|
||||
m_max.xz = origin + extent;
|
||||
// glm::dvec3 scale_v = (m_max - m_min) / 50.;
|
||||
// double scale = glm::min(scale_v.z, scale_v.x);
|
||||
// m_max_levels = glm::max(1, (int)glm::ceil(glm::log2(scale)));
|
||||
}
|
||||
|
||||
void QuadTreeBuilder::Insert(uint32_t index, glm::dvec3 min,
|
||||
glm::dvec3 max) const {
|
||||
glm::dvec3 scale_v = (m_max - m_min) / (max - min);
|
||||
double scale = glm::min(scale_v.z, scale_v.x);
|
||||
int level =
|
||||
glm::clamp((int)glm::floor(glm::log2(scale)), 0, m_max_levels - 1);
|
||||
m_root->Insert(index, min, max, level);
|
||||
}
|
||||
|
||||
void QuadTree::Build(const QuadTreeBuilder& builder) {
|
||||
Add(m_nodes.emplace_back(), *builder.m_root);
|
||||
}
|
||||
|
||||
void QuadTree::Add(Node& node, const QuadTreeBuilder::Node& item) {
|
||||
if (item.m_leaves.empty() && item.NumChildren() == 1) {
|
||||
return Add(node, *item.FirstChild());
|
||||
}
|
||||
node.m_origin = .5 * (item.m_actual_max + item.m_actual_min);
|
||||
node.m_extent = .5 * (item.m_actual_max - item.m_actual_min);
|
||||
node.m_first_leave = m_leaves.size();
|
||||
node.m_leave_count = item.m_leaves.size();
|
||||
m_leaves.insert(m_leaves.end(), item.m_leaves.begin(), item.m_leaves.end());
|
||||
uint32_t first_child = m_nodes.size();
|
||||
uint32_t child_count = 0;
|
||||
for (const auto& child : item.m_children) {
|
||||
if (child) ++child_count;
|
||||
}
|
||||
node.m_first_child = first_child;
|
||||
node.m_child_count = child_count;
|
||||
// node reference invalidated from here
|
||||
for (int i = 0; i < child_count; ++i) {
|
||||
m_nodes.emplace_back();
|
||||
}
|
||||
{
|
||||
int child_index = first_child;
|
||||
for (const auto& child : item.m_children) {
|
||||
if (!child) continue;
|
||||
Add(m_nodes[child_index++], *child);
|
||||
}
|
||||
}
|
||||
}
|
||||
181
manul/renderer/source/resource_registry.cpp
Normal file
181
manul/renderer/source/resource_registry.cpp
Normal file
@@ -0,0 +1,181 @@
|
||||
#include "nvrenderer/resource_registry.h"
|
||||
|
||||
#include "Logs.h"
|
||||
#include "fmt/compile.h"
|
||||
#include "nvtexture.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
MaResourceMappingSet& MaResourceMappingSet::Add(
|
||||
const MaResourceMapping& mapping) {
|
||||
m_mappings.push_back(mapping);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void MaResourceMappingSet::ToBindingLayout(
|
||||
nvrhi::BindingLayoutDesc& desc) const {
|
||||
for (const auto& [slot, size, key, type] : m_mappings) {
|
||||
nvrhi::BindingLayoutItem item{};
|
||||
item.type = type;
|
||||
item.slot = slot;
|
||||
item.size = size;
|
||||
desc.addItem(item);
|
||||
}
|
||||
}
|
||||
|
||||
bool MaResourceMappingSet::ToBindingSet(
|
||||
nvrhi::BindingSetDesc& desc, const MaResourceRegistry* registry,
|
||||
const nvrhi::BindingLayoutDesc* reference_layout) const {
|
||||
bool is_valid = true;
|
||||
for (const auto& [slot, size, key, type] : m_mappings) {
|
||||
MaResourceView resource{};
|
||||
switch (type) {
|
||||
case nvrhi::ResourceType::PushConstants:
|
||||
case nvrhi::ResourceType::None:
|
||||
break;
|
||||
default:
|
||||
resource = registry->GetResource(key, type);
|
||||
}
|
||||
bool item_is_valid = resource.IsValid();
|
||||
bool item_is_present = true;
|
||||
nvrhi::BindingSetItem item{};
|
||||
item.slot = slot;
|
||||
item.type = type;
|
||||
item.resourceHandle = resource.m_resource;
|
||||
item.dimension = nvrhi::TextureDimension::Unknown;
|
||||
item.format = nvrhi::Format::UNKNOWN;
|
||||
switch (type) {
|
||||
case nvrhi::ResourceType::PushConstants:
|
||||
item.range.byteOffset = 0;
|
||||
item.range.byteSize = size;
|
||||
item_is_valid = true;
|
||||
break;
|
||||
case nvrhi::ResourceType::RawBuffer_SRV:
|
||||
case nvrhi::ResourceType::RawBuffer_UAV:
|
||||
case nvrhi::ResourceType::StructuredBuffer_SRV:
|
||||
case nvrhi::ResourceType::StructuredBuffer_UAV:
|
||||
case nvrhi::ResourceType::TypedBuffer_SRV:
|
||||
case nvrhi::ResourceType::TypedBuffer_UAV:
|
||||
case nvrhi::ResourceType::ConstantBuffer:
|
||||
case nvrhi::ResourceType::VolatileConstantBuffer:
|
||||
item.range = nvrhi::EntireBuffer;
|
||||
break;
|
||||
case nvrhi::ResourceType::Texture_SRV:
|
||||
case nvrhi::ResourceType::Texture_UAV:
|
||||
item.subresources = nvrhi::AllSubresources;
|
||||
default:;
|
||||
}
|
||||
if (reference_layout) {
|
||||
item_is_present = false;
|
||||
for (const auto& binding : reference_layout->bindings) {
|
||||
if (binding.type != item.type || binding.slot != item.slot) continue;
|
||||
item_is_present = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (item_is_valid && item_is_present) desc.addItem(item);
|
||||
is_valid &= item_is_valid;
|
||||
}
|
||||
return is_valid;
|
||||
}
|
||||
|
||||
MaResourceView MaResourceRegistry::GetResource(
|
||||
const entt::hashed_string& key,
|
||||
const nvrhi::ResourceType requested_type) const {
|
||||
auto registry = this;
|
||||
while (registry) {
|
||||
if (const auto resource = registry->GetResourceLocal(key, requested_type);
|
||||
resource.IsValid())
|
||||
return resource;
|
||||
registry = registry->m_parent;
|
||||
}
|
||||
std::string what = fmt::format("Unable to locate resource {:s} [{:#x}]",
|
||||
key.data(), key.value());
|
||||
ErrorLog(fmt::format("Unable to locate resource {:s} [{:#x}]", key.data(),
|
||||
key.value()));
|
||||
throw std::runtime_error(what.c_str());
|
||||
return {};
|
||||
}
|
||||
|
||||
MaResourceRegistry::MaResourceRegistry(MaResourceRegistry* parent)
|
||||
: m_parent(parent) {}
|
||||
|
||||
void MaResourceRegistry::InitResourceRegistry() {
|
||||
if (m_parent) {
|
||||
m_texture_manager =
|
||||
std::shared_ptr<NvTextureManager>(m_parent->GetTextureManager());
|
||||
} else {
|
||||
m_texture_manager =
|
||||
std::make_shared<NvTextureManager>(dynamic_cast<NvRenderer*>(this));
|
||||
}
|
||||
}
|
||||
|
||||
void MaResourceRegistry::RegisterResource(const bool global,
|
||||
const entt::hashed_string& key,
|
||||
nvrhi::IResource* resource,
|
||||
const nvrhi::ResourceType type) {
|
||||
auto registry = this;
|
||||
while (global && registry->m_parent) registry = registry->m_parent;
|
||||
registry->m_resource_views[key] = {resource, type};
|
||||
}
|
||||
|
||||
void MaResourceRegistry::RegisterTexture(const entt::hashed_string& key,
|
||||
const size_t handle) {
|
||||
m_streaming_textures[key] = handle;
|
||||
}
|
||||
|
||||
void MaResourceRegistry::RegisterResource(const bool global, const char* key,
|
||||
nvrhi::IResource* resource,
|
||||
const nvrhi::ResourceType type) {
|
||||
RegisterResource(global, static_cast<entt::hashed_string>(key), resource,
|
||||
type);
|
||||
}
|
||||
|
||||
void MaResourceRegistry::RegisterTexture(const char* key, const size_t handle) {
|
||||
RegisterTexture(static_cast<entt::hashed_string>(key), handle);
|
||||
}
|
||||
|
||||
MaResourceView MaResourceRegistry::GetResourceLocal(
|
||||
const entt::hashed_string& key,
|
||||
const nvrhi::ResourceType requested_type) const {
|
||||
// Attempt to fetch streaming texture
|
||||
if (requested_type == nvrhi::ResourceType::Texture_SRV) {
|
||||
if (const auto it = m_streaming_textures.find(key);
|
||||
it != m_streaming_textures.end()) {
|
||||
if (const auto texture_manager = GetTextureManager();
|
||||
texture_manager && texture_manager->IsValidHandle(it->second))
|
||||
return {texture_manager->GetRhiTexture(it->second),
|
||||
nvrhi::ResourceType::Texture_SRV};
|
||||
}
|
||||
}
|
||||
// Attempt to fetch static resource
|
||||
if (const auto it = m_resource_views.find(key);
|
||||
it != m_resource_views.end() && requested_type == it->second.m_type) {
|
||||
return it->second;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
NvTextureManager* MaResourceRegistry::GetTextureManager() const {
|
||||
auto registry = this;
|
||||
while (!registry->m_texture_manager && registry->m_parent)
|
||||
registry = registry->m_parent;
|
||||
return registry->m_texture_manager.get();
|
||||
}
|
||||
|
||||
uint64_t MaResourceRegistry::GetLastStreamingTextureUpdate() const {
|
||||
uint64_t last_update = 1;
|
||||
const auto texture_manager = GetTextureManager();
|
||||
for (const auto& [key, texture] : m_streaming_textures) {
|
||||
if (!texture_manager->IsValidHandle(texture)) continue;
|
||||
last_update = std::max(last_update,
|
||||
texture_manager->GetTexture(texture)->m_last_change);
|
||||
}
|
||||
return last_update;
|
||||
}
|
||||
void MaResourceRegistry::UpdateLastStreamingTextureUse(
|
||||
const glm::dvec3& location) const {
|
||||
const auto texture_manager = GetTextureManager();
|
||||
for (const auto& [key, texture] : m_streaming_textures) {
|
||||
texture_manager->UpdateLastUse(texture, location);
|
||||
}
|
||||
}
|
||||
31
manul/renderer/source/shaders_d3d12.cpp
Normal file
31
manul/renderer/source/shaders_d3d12.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "nvrenderer_d3d12.h"
|
||||
|
||||
#if LIBMANUL_WITH_D3D12
|
||||
|
||||
void NvRendererBackend_D3D12::LoadShaderBlobs() {
|
||||
auto root = YAML::LoadFile("shaders/shaders_dxil.manul");
|
||||
|
||||
for (const auto entry : root["materials"]) {
|
||||
std::string_view material = entry.first.as<std::string_view>();
|
||||
for (const auto shader : entry.second) {
|
||||
auto binary = shader.second["binary"].as<YAML::Binary>();
|
||||
auto entrypoint = shader.second["entrypoint"].as<std::string>();
|
||||
AddMaterialShaderBlob(
|
||||
material, shader.first.as<std::string_view>(),
|
||||
std::string(binary.data(), binary.data() + binary.size()),
|
||||
entrypoint);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto shader : root["utility"]) {
|
||||
auto binary = shader.second["binary"].as<YAML::Binary>();
|
||||
auto entrypoint = shader.second["entrypoint"].as<std::string>();
|
||||
AddShaderBlob(shader.first.as<std::string_view>(),
|
||||
std::string(binary.data(), binary.data() + binary.size()),
|
||||
entrypoint);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
31
manul/renderer/source/shaders_vulkan.cpp
Normal file
31
manul/renderer/source/shaders_vulkan.cpp
Normal file
@@ -0,0 +1,31 @@
|
||||
#include <yaml-cpp/yaml.h>
|
||||
|
||||
#include "nvrenderer_vulkan.h"
|
||||
|
||||
#if LIBMANUL_WITH_VULKAN
|
||||
|
||||
void NvRendererBackend_Vulkan::LoadShaderBlobs() {
|
||||
auto root = YAML::LoadFile("shaders/shaders_spirv.manul");
|
||||
|
||||
for (const auto entry : root["materials"]) {
|
||||
std::string_view material = entry.first.as<std::string_view>();
|
||||
for (const auto shader : entry.second) {
|
||||
auto binary = shader.second["binary"].as<YAML::Binary>();
|
||||
auto entrypoint = shader.second["entrypoint"].as<std::string>();
|
||||
AddMaterialShaderBlob(
|
||||
material, shader.first.as<std::string_view>(),
|
||||
std::string(binary.data(), binary.data() + binary.size()),
|
||||
entrypoint);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto shader : root["utility"]) {
|
||||
auto binary = shader.second["binary"].as<YAML::Binary>();
|
||||
auto entrypoint = shader.second["entrypoint"].as<std::string>();
|
||||
AddShaderBlob(shader.first.as<std::string_view>(),
|
||||
std::string(binary.data(), binary.data() + binary.size()),
|
||||
entrypoint);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
442
manul/renderer/source/sky.cpp
Normal file
442
manul/renderer/source/sky.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
#include "sky.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "nvrendererbackend.h"
|
||||
#include "simulationenvironment.h"
|
||||
#include "simulationtime.h"
|
||||
|
||||
namespace {
|
||||
static const float PI = 3.14159265358979323846f;
|
||||
static const float INV_PI = 0.31830988618379067154f;
|
||||
static const float INV_4PI = 0.25f * INV_PI;
|
||||
static const float PHASE_ISOTROPIC = INV_4PI;
|
||||
static const float RAYLEIGH_PHASE_SCALE = (3.f / 16.f) * INV_PI;
|
||||
static const float g = 0.8f;
|
||||
static const float gg = g * g;
|
||||
|
||||
static const float EARTH_RADIUS = 6371.0e3f; // km
|
||||
static const float ATMOSPHERE_THICKNESS = 100.0e3f; // km
|
||||
static const float ATMOSPHERE_RADIUS = EARTH_RADIUS + ATMOSPHERE_THICKNESS;
|
||||
static const float EXPOSURE = -4.0;
|
||||
|
||||
// Extraterrestial Solar Irradiance Spectra, units W * m^-2 * nm^-1
|
||||
// https://www.nrel.gov/grid/solar-resource/spectra.html
|
||||
static const glm::vec4 sun_spectral_irradiance =
|
||||
glm::vec4(1.679, 1.828, 1.986, 1.307);
|
||||
// Rayleigh scattering coefficient at sea level, units km^-1
|
||||
// "Rayleigh-scattering calculations for the terrestrial atmosphere"
|
||||
// by Anthony Bucholtz (1995).
|
||||
static const glm::vec4 molecular_scattering_coefficient_base =
|
||||
glm::vec4(6.605e-6, 1.067e-5, 1.842e-5, 3.156e-5);
|
||||
// Fog scattering/extinction cross section, units m^2 / molecules
|
||||
// Mie theory results for IOR of 1.333. Particle size is a log normal
|
||||
// distribution of mean diameter=15 and std deviation=0.4
|
||||
static const glm::vec4 fog_scattering_cross_section =
|
||||
glm::vec4(5.015e-10, 4.987e-10, 4.966e-10, 4.949e-10);
|
||||
// Ozone absorption cross section, units m^2 / molecules
|
||||
// "High spectral resolution ozone absorption cross-sections"
|
||||
// by V. Gorshelev et al. (2014).
|
||||
static const glm::vec4 ozone_absorption_cross_section =
|
||||
glm::vec4(3.472e-25, 3.914e-25, 1.349e-25, 11.03e-27);
|
||||
static const glm::mat4x3 M = {
|
||||
137.672389239975, -8.632904716299537, -1.7181567391931372,
|
||||
32.549094028629234, 91.29801417199785, -12.005406444382531,
|
||||
-38.91428392614275, 34.31665471469816, 29.89044807197628,
|
||||
8.572844237945445, -11.103384660054624, 117.47585277566478};
|
||||
} // namespace
|
||||
|
||||
Sky::Sky(NvRenderer* renderer)
|
||||
: m_backend(renderer->GetBackend()), MaResourceRegistry(renderer) {
|
||||
m_transmittance_pass = std::make_shared<SkyTransmittancePass>(this);
|
||||
m_aerial_lut = std::make_shared<SkyAerialLut>(this);
|
||||
}
|
||||
|
||||
void Sky::Init() {
|
||||
InitResourceRegistry();
|
||||
m_sky_constants = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc(sizeof(SkyConstants),
|
||||
"Sky constants", 16)
|
||||
.setInitialState(nvrhi::ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
m_transmittance_pass->Init();
|
||||
m_aerial_lut->Init();
|
||||
RegisterResource(true, "sky_aerial_lut", m_aerial_lut->m_lut,
|
||||
nvrhi::ResourceType::Texture_SRV);
|
||||
}
|
||||
|
||||
void Sky::Render(nvrhi::ICommandList* command_list,
|
||||
const glm::dmat4& projection, const glm::dmat4& view) {
|
||||
UpdateConstants(command_list);
|
||||
m_transmittance_pass->Render(command_list);
|
||||
m_aerial_lut->Render(command_list, projection, view);
|
||||
}
|
||||
|
||||
float Sky::GetOzoneMean() const {
|
||||
float month = glm::saturate(simulation::Time.year_day() / 366.f) * 12.f + .5f;
|
||||
float month_fract = glm::fract(month);
|
||||
int month_l = glm::floor(month);
|
||||
static std::array<float, 12> ozone_means{347.f, 370.f, 381.f, 384.f,
|
||||
372.f, 352.f, 333.f, 317.f,
|
||||
298.f, 285.f, 290.f, 315.f};
|
||||
return glm::lerp(ozone_means[month_l], ozone_means[(month_l + 1) % 12],
|
||||
month_fract);
|
||||
}
|
||||
|
||||
glm::vec4 Sky::GetAerosolAbsorptionCrossSection() const {
|
||||
switch (m_aerosol_preset) {
|
||||
case AerosolPreset::Rural:
|
||||
return {5.0393e-23f, 8.0765e-23f, 1.3823e-22f, 2.3383e-22f};
|
||||
case AerosolPreset::Urban:
|
||||
return {2.8722e-24f, 4.6168e-24f, 7.9706e-24f, 1.3578e-23f};
|
||||
default:
|
||||
return glm::vec4(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec4 Sky::GetAerosolScatteringCrossSection() const {
|
||||
switch (m_aerosol_preset) {
|
||||
case AerosolPreset::Rural:
|
||||
return {2.6004e-22f, 2.4844e-22f, 2.8362e-22f, 2.7494e-22f};
|
||||
case AerosolPreset::Urban:
|
||||
return {1.5908e-22f, 1.7711e-22f, 2.0942e-22f, 2.4033e-22f};
|
||||
default:
|
||||
return glm::vec4(0.f);
|
||||
}
|
||||
}
|
||||
|
||||
float Sky::GetAerosolBaseDensity() const {
|
||||
switch (m_aerosol_preset) {
|
||||
case AerosolPreset::Rural:
|
||||
return 8.544e15f;
|
||||
case AerosolPreset::Urban:
|
||||
return 1.3681e17f;
|
||||
default:
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
float Sky::GetAerosolBackgroundDividedByBaseDensity() const {
|
||||
switch (m_aerosol_preset) {
|
||||
case AerosolPreset::Rural:
|
||||
return 2e3f / GetAerosolBaseDensity();
|
||||
case AerosolPreset::Urban:
|
||||
return 2e3f / GetAerosolBaseDensity();
|
||||
default:
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
float Sky::GetAerosolHeightScale() const {
|
||||
switch (m_aerosol_preset) {
|
||||
case AerosolPreset::Rural:
|
||||
return .73f;
|
||||
case AerosolPreset::Urban:
|
||||
return .73f;
|
||||
default:
|
||||
return 0.f;
|
||||
}
|
||||
}
|
||||
|
||||
float Sky::GetFogDensity() const {
|
||||
return 3e7f * glm::pow(0.99937f, glm::min(3e7f, m_visibility));
|
||||
}
|
||||
|
||||
void Sky::UpdateConstants(nvrhi::ICommandList* command_list) {
|
||||
SkyConstants constants{};
|
||||
constants.g_AerosolAbsorptionCrossSection =
|
||||
GetAerosolAbsorptionCrossSection();
|
||||
constants.g_AerosolScatteringCrossSection =
|
||||
GetAerosolScatteringCrossSection();
|
||||
constants.g_AerosolHeightScale = GetAerosolHeightScale();
|
||||
constants.g_AerosolBaseDensity = GetAerosolBaseDensity();
|
||||
constants.g_AerosolBackgroundDividedByBaseDensity =
|
||||
GetAerosolBackgroundDividedByBaseDensity();
|
||||
constants.g_GroundAlbedo = glm::vec4{m_ground_albedo};
|
||||
constants.g_AerosolTurbidity = m_aerosol_turbidity;
|
||||
constants.g_OzoneMean = GetOzoneMean();
|
||||
constants.g_FogDensity = GetFogDensity();
|
||||
constants.g_FogHeightOffset = m_fog_height_offset;
|
||||
constants.g_FogHeightScale = m_fog_height_scale;
|
||||
command_list->writeBuffer(m_sky_constants, &constants, sizeof(constants));
|
||||
}
|
||||
|
||||
void Sky::OnGui() {
|
||||
if (!m_gui_active) return;
|
||||
if (ImGui::Begin("Sky settings", &m_gui_active,
|
||||
ImGuiWindowFlags_AlwaysAutoResize)) {
|
||||
ImGui::SliderFloat("Visibility", &m_visibility, 10.f, 3e4f);
|
||||
ImGui::SliderFloat("Fog Offset", &m_fog_height_offset, 0.f, 10.f);
|
||||
ImGui::SliderFloat("Fog Height", &m_fog_height_scale, .01f, 10.f);
|
||||
if (ImGui::BeginCombo("Aerosol Type",
|
||||
GetAerosolTypeDesc(m_aerosol_preset))) {
|
||||
for (int i = 0; i < static_cast<int>(AerosolPreset::Num); ++i) {
|
||||
AerosolPreset preset = static_cast<AerosolPreset>(i);
|
||||
if (ImGui::Selectable(GetAerosolTypeDesc(preset),
|
||||
preset == m_aerosol_preset)) {
|
||||
m_aerosol_preset = preset;
|
||||
}
|
||||
}
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
ImGui::SliderFloat("Aerosol Turbidity", &m_aerosol_turbidity, 0., 10.);
|
||||
ImGui::SliderFloat("Ground Albedo", &m_ground_albedo, 0., 10.);
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
void Sky::ShowGui() { m_gui_active = true; }
|
||||
|
||||
const char* Sky::GetAerosolTypeDesc(AerosolPreset preset) {
|
||||
switch (preset) {
|
||||
case AerosolPreset::Rural:
|
||||
return "Rural";
|
||||
case AerosolPreset::Urban:
|
||||
return "Urban";
|
||||
default:
|
||||
return "INVALID";
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec4 Sky::GetMolecularScatteringCoefficient(float h) const {
|
||||
return molecular_scattering_coefficient_base *
|
||||
glm::exp(-0.07771971f * glm::pow(h, 1.16364243f));
|
||||
}
|
||||
|
||||
glm::vec4 Sky::GetMolecularAbsorptionCoefficient(float h) const {
|
||||
h += 1e-4f; // Avoid division by 0
|
||||
float t = glm::log(h) - 3.22261f;
|
||||
float density = 3.78547397e17f * (1.f / h) * glm::exp(-t * t * 5.55555555f);
|
||||
return ozone_absorption_cross_section * GetOzoneMean() * density;
|
||||
}
|
||||
|
||||
glm::vec4 Sky::GetFogScatteringCoefficient(float h) const {
|
||||
if (GetFogDensity() > 0.f) {
|
||||
return fog_scattering_cross_section * GetFogDensity() *
|
||||
glm::min(1.f,
|
||||
glm::exp((-h + m_fog_height_offset) / m_fog_height_scale));
|
||||
} else {
|
||||
return glm::vec4{0.f};
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec3 Sky::CalcSunColor() const {
|
||||
glm::vec4 transmittance =
|
||||
ComputeTransmittance(-Global.DayLight.direction, 32);
|
||||
return simulation::Environment.light_intensity() *
|
||||
LinearSrgbFromSpectralSamples(sun_spectral_irradiance *
|
||||
transmittance) *
|
||||
glm::exp(EXPOSURE);
|
||||
}
|
||||
|
||||
glm::vec3 Sky::LinearSrgbFromSpectralSamples(glm::vec4 L) {
|
||||
glm::vec3 c = M * L;
|
||||
return c.r * glm::vec3(0.4123908f, 0.21263901f, 0.01933082f) +
|
||||
c.g * glm::vec3(0.35758434f, 0.71516868f, 0.11919478f) +
|
||||
c.b * glm::vec3(0.18048079f, 0.07219232f, 0.95053215f);
|
||||
}
|
||||
|
||||
float Sky::RaySphereIntersection(glm::vec3 ro, glm::vec3 rd, float radius) {
|
||||
float b = glm::dot(ro, rd);
|
||||
float c = glm::dot(ro, ro) - radius * radius;
|
||||
if (c > 0.f && b > 0.f) return -1.f;
|
||||
float d = b * b - c;
|
||||
if (d < 0.f) return -1.f;
|
||||
if (d > b * b) return (-b + glm::sqrt(d));
|
||||
return (-b - glm::sqrt(d));
|
||||
}
|
||||
|
||||
float Sky::GetAerosolDensity(float h) const {
|
||||
return GetAerosolBaseDensity() * (exp(-h / GetAerosolHeightScale()) +
|
||||
GetAerosolBackgroundDividedByBaseDensity());
|
||||
}
|
||||
|
||||
void Sky::GetAtmosphereCollisionCoefficients(
|
||||
float h, glm::vec4& aerosol_absorption, glm::vec4& aerosol_scattering,
|
||||
glm::vec4& molecular_absorption, glm::vec4& molecular_scattering,
|
||||
glm::vec4& fog_scattering, glm::vec4& extinction) const {
|
||||
h = glm::max(h, 1.e-3f); // In case height is negative
|
||||
h *= 1.e-3f;
|
||||
float aerosol_density = GetAerosolDensity(h);
|
||||
aerosol_absorption = GetAerosolAbsorptionCrossSection() * aerosol_density *
|
||||
m_aerosol_turbidity;
|
||||
aerosol_scattering = GetAerosolScatteringCrossSection() * aerosol_density *
|
||||
m_aerosol_turbidity;
|
||||
molecular_absorption = GetMolecularAbsorptionCoefficient(h);
|
||||
molecular_scattering = GetMolecularScatteringCoefficient(h);
|
||||
fog_scattering = GetFogScatteringCoefficient(h);
|
||||
extinction = aerosol_absorption + aerosol_scattering + molecular_absorption +
|
||||
molecular_scattering + fog_scattering;
|
||||
}
|
||||
|
||||
glm::vec4 Sky::ComputeTransmittance(const glm::vec3& ray_dir, int steps) const {
|
||||
glm::vec3 ray_origin{0.f, EARTH_RADIUS + Global.pCamera.Pos.y, 0.f};
|
||||
glm::vec4 transmittance{1.f};
|
||||
float t_max = std::numeric_limits<float>::max();
|
||||
float atmos_dist =
|
||||
RaySphereIntersection(ray_origin, ray_dir, ATMOSPHERE_RADIUS);
|
||||
|
||||
if (RaySphereIntersection(ray_origin, ray_dir, EARTH_RADIUS) >= 0.0) {
|
||||
return glm::vec4(0.f, 0.f, 0.f, 0.f);
|
||||
}
|
||||
|
||||
t_max = glm::min(t_max, atmos_dist);
|
||||
float dt = t_max / float(steps);
|
||||
|
||||
for (int i = 0; i < steps; ++i) {
|
||||
float t = (float(i) + 0.5) * dt;
|
||||
glm::vec3 x_t = ray_origin + ray_dir * t;
|
||||
|
||||
float distance_to_earth_center = glm::length(x_t);
|
||||
float altitude = distance_to_earth_center - EARTH_RADIUS;
|
||||
|
||||
glm::vec4 aerosol_absorption, aerosol_scattering;
|
||||
glm::vec4 molecular_absorption, molecular_scattering;
|
||||
glm::vec4 fog_scattering;
|
||||
glm::vec4 extinction;
|
||||
GetAtmosphereCollisionCoefficients(
|
||||
altitude, aerosol_absorption, aerosol_scattering, molecular_absorption,
|
||||
molecular_scattering, fog_scattering, extinction);
|
||||
|
||||
glm::vec4 step_transmittance = glm::exp(-dt * extinction);
|
||||
transmittance *= step_transmittance;
|
||||
}
|
||||
return transmittance;
|
||||
}
|
||||
|
||||
void SkyTransmittancePass::Init() {
|
||||
m_pixel_shader =
|
||||
m_backend->CreateShader("sky_transmittance", nvrhi::ShaderType::Pixel);
|
||||
m_output = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setFormat(nvrhi::Format::RGBA8_UNORM)
|
||||
.setWidth(128)
|
||||
.setHeight(128)
|
||||
.setIsRenderTarget(true)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::Pixel, 0,
|
||||
nvrhi::BindingSetDesc().addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(13, m_sky->m_sky_constants)),
|
||||
m_binding_layout, m_binding_set);
|
||||
m_framebuffer = m_backend->GetDevice()->createFramebuffer(
|
||||
nvrhi::FramebufferDesc().addColorAttachment(m_output));
|
||||
FullScreenPass::Init();
|
||||
}
|
||||
|
||||
void SkyTransmittancePass::CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) {
|
||||
FullScreenPass::CreatePipelineDesc(pipeline_desc);
|
||||
pipeline_desc.setPixelShader(m_pixel_shader);
|
||||
pipeline_desc.addBindingLayout(m_binding_layout);
|
||||
}
|
||||
|
||||
void SkyTransmittancePass::Render(nvrhi::ICommandList* command_list) {
|
||||
command_list->beginMarker("Sky transmittance");
|
||||
nvrhi::GraphicsState graphics_state;
|
||||
InitState(graphics_state);
|
||||
graphics_state.addBindingSet(m_binding_set);
|
||||
command_list->setGraphicsState(graphics_state);
|
||||
Draw(command_list);
|
||||
command_list->endMarker();
|
||||
}
|
||||
|
||||
nvrhi::IFramebuffer* SkyTransmittancePass::GetFramebuffer() {
|
||||
return m_framebuffer;
|
||||
}
|
||||
|
||||
void SkyAerialLut::Init() {
|
||||
m_sky_width = 128;
|
||||
m_sky_height = 512;
|
||||
m_lut_width = 64;
|
||||
m_lut_height = 256;
|
||||
m_lut_slices = 32;
|
||||
m_constant_buffer = m_sky->m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateVolatileConstantBufferDesc(
|
||||
sizeof(DispatchConstants), "Sky Aerial LUT Dispatch Constants", 16));
|
||||
m_lut = m_sky->m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDimension(nvrhi::TextureDimension::Texture2DArray)
|
||||
.setWidth(m_lut_width)
|
||||
.setHeight(m_lut_height)
|
||||
.setArraySize(m_lut_slices)
|
||||
.setFormat(nvrhi::Format::RGBA16_FLOAT)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(nvrhi::ResourceStates::Common)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Sky Aerial LUT"));
|
||||
m_sky_texture = m_sky->m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setWidth(m_sky_width)
|
||||
.setHeight(m_sky_height)
|
||||
.setFormat(nvrhi::Format::RGBA16_FLOAT)
|
||||
.setIsUAV(true)
|
||||
.setInitialState(nvrhi::ResourceStates::Common)
|
||||
.setKeepInitialState(true)
|
||||
.setDebugName("Sky Texture"));
|
||||
auto shader_lut = m_sky->m_backend->CreateShader("sky_aerial_lut",
|
||||
nvrhi::ShaderType::Compute);
|
||||
auto shader_sky =
|
||||
m_sky->m_backend->CreateShader("sky", nvrhi::ShaderType::Compute);
|
||||
auto sampler = m_sky->m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(nvrhi::SamplerAddressMode::ClampToEdge)
|
||||
.setAllFilters(true));
|
||||
nvrhi::BindingLayoutHandle binding_layout_lut;
|
||||
nvrhi::BindingLayoutHandle binding_layout_sky;
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_sky->m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer))
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(13, m_sky->m_sky_constants))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(0, m_lut))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
13, m_sky->m_transmittance_pass->m_output))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(13, sampler)),
|
||||
binding_layout_lut, m_bindings_lut);
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_sky->m_backend->GetDevice(), nvrhi::ShaderType::Compute, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::ConstantBuffer(0, m_constant_buffer))
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(13, m_sky->m_sky_constants))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(1, m_sky_texture))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
13, m_sky->m_transmittance_pass->m_output))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(13, sampler)),
|
||||
binding_layout_sky, m_bindings_sky);
|
||||
m_pso_lut = m_sky->m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.addBindingLayout(binding_layout_lut)
|
||||
.setComputeShader(shader_lut));
|
||||
m_pso_sky = m_sky->m_backend->GetDevice()->createComputePipeline(
|
||||
nvrhi::ComputePipelineDesc()
|
||||
.addBindingLayout(binding_layout_sky)
|
||||
.setComputeShader(shader_sky));
|
||||
}
|
||||
|
||||
void SkyAerialLut::Render(nvrhi::ICommandList* command_list,
|
||||
const glm::dmat4& projection,
|
||||
const glm::dmat4& view) {
|
||||
{
|
||||
DispatchConstants constants{};
|
||||
constants.g_InverseView = static_cast<glm::mat3>(glm::inverse(view));
|
||||
constants.g_InverseProjection = glm::inverse(projection);
|
||||
constants.g_SunDir = -Global.DayLight.direction;
|
||||
constants.g_Altitude = Global.pCamera.Pos.y;
|
||||
constants.g_MaxDepth = Global.BaseDrawRange * Global.fDistanceFactor;
|
||||
command_list->writeBuffer(m_constant_buffer, &constants, sizeof(constants));
|
||||
}
|
||||
|
||||
command_list->setComputeState(
|
||||
nvrhi::ComputeState().setPipeline(m_pso_lut).addBindingSet(
|
||||
m_bindings_lut));
|
||||
command_list->dispatch((m_lut_width + 7) / 8, (m_lut_height + 7) / 8, 1);
|
||||
|
||||
command_list->setComputeState(
|
||||
nvrhi::ComputeState().setPipeline(m_pso_sky).addBindingSet(
|
||||
m_bindings_sky));
|
||||
command_list->dispatch((m_sky_width + 7) / 8, (m_sky_height + 7) / 8, 1);
|
||||
}
|
||||
115
manul/renderer/source/sky.h
Normal file
115
manul/renderer/source/sky.h
Normal file
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include "fullscreenpass.h"
|
||||
#include "nvrenderer/resource_registry.h"
|
||||
|
||||
struct Sky : public MaResourceRegistry {
|
||||
Sky(class NvRenderer* renderer);
|
||||
|
||||
void Init();
|
||||
void Render(nvrhi::ICommandList* command_list, const glm::dmat4& projection,
|
||||
const glm::dmat4& view);
|
||||
struct SkyConstants {
|
||||
glm::vec4 g_AerosolAbsorptionCrossSection;
|
||||
glm::vec4 g_AerosolScatteringCrossSection;
|
||||
glm::vec4 g_GroundAlbedo;
|
||||
float g_AerosolHeightScale;
|
||||
float g_AerosolTurbidity;
|
||||
float g_AerosolBaseDensity;
|
||||
float g_AerosolBackgroundDividedByBaseDensity;
|
||||
float g_OzoneMean;
|
||||
float g_FogDensity;
|
||||
float g_FogHeightOffset;
|
||||
float g_FogHeightScale;
|
||||
};
|
||||
nvrhi::BufferHandle m_sky_constants;
|
||||
enum class AerosolPreset {
|
||||
Rural,
|
||||
Urban,
|
||||
Num
|
||||
} m_aerosol_preset = AerosolPreset::Rural;
|
||||
float m_visibility = 1e4f;
|
||||
float m_fog_height_offset = 0.f;
|
||||
float m_fog_height_scale = .1f;
|
||||
float m_aerosol_turbidity = 1.f;
|
||||
float m_ground_albedo = .3f;
|
||||
bool m_gui_active = false;
|
||||
void UpdateConstants(nvrhi::ICommandList* command_list);
|
||||
void OnGui();
|
||||
void ShowGui();
|
||||
static const char* GetAerosolTypeDesc(AerosolPreset preset);
|
||||
class NvRendererBackend* m_backend;
|
||||
std::shared_ptr<struct SkyTransmittancePass> m_transmittance_pass;
|
||||
std::shared_ptr<struct SkyAerialLut> m_aerial_lut;
|
||||
float GetOzoneMean() const;
|
||||
glm::vec4 GetAerosolAbsorptionCrossSection() const;
|
||||
glm::vec4 GetAerosolScatteringCrossSection() const;
|
||||
float GetAerosolBaseDensity() const;
|
||||
float GetAerosolBackgroundDividedByBaseDensity() const;
|
||||
float GetAerosolHeightScale() const;
|
||||
float GetFogDensity() const;
|
||||
glm::vec4 GetMolecularScatteringCoefficient(float h) const;
|
||||
glm::vec4 GetMolecularAbsorptionCoefficient(float h) const;
|
||||
glm::vec4 GetFogScatteringCoefficient(float h) const;
|
||||
glm::vec3 CalcSunColor() const;
|
||||
static glm::vec3 LinearSrgbFromSpectralSamples(glm::vec4 L);
|
||||
static float RaySphereIntersection(glm::vec3 ro, glm::vec3 rd, float radius);
|
||||
float GetAerosolDensity(float h) const;
|
||||
void GetAtmosphereCollisionCoefficients(
|
||||
float h, glm::vec4& aerosol_absorption, glm::vec4& aerosol_scattering,
|
||||
glm::vec4& molecular_absorption, glm::vec4& molecular_scattering,
|
||||
glm::vec4& fog_scattering, glm::vec4& extinction) const;
|
||||
glm::vec4 ComputeTransmittance(const glm::vec3& dir, int steps) const;
|
||||
};
|
||||
|
||||
struct SkyTransmittancePass : public FullScreenPass {
|
||||
SkyTransmittancePass(Sky* sky) : FullScreenPass(sky->m_backend), m_sky(sky) {}
|
||||
|
||||
virtual void Init() override;
|
||||
|
||||
virtual void CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) override;
|
||||
|
||||
virtual void Render(nvrhi::ICommandList* command_list) override;
|
||||
|
||||
virtual nvrhi::IFramebuffer* GetFramebuffer() override;
|
||||
|
||||
nvrhi::BindingLayoutHandle m_binding_layout;
|
||||
nvrhi::BindingSetHandle m_binding_set;
|
||||
nvrhi::ShaderHandle m_pixel_shader;
|
||||
nvrhi::FramebufferHandle m_framebuffer;
|
||||
|
||||
nvrhi::ITexture* m_source;
|
||||
nvrhi::Format m_output_format;
|
||||
|
||||
nvrhi::TextureHandle m_output;
|
||||
|
||||
Sky* m_sky;
|
||||
};
|
||||
|
||||
struct SkyAerialLut {
|
||||
struct DispatchConstants {
|
||||
glm::mat4 g_InverseView; // DO NOT TRANSPOSE
|
||||
glm::mat4 g_InverseProjection;
|
||||
glm::vec3 g_SunDir;
|
||||
float g_Altitude;
|
||||
float g_MaxDepth;
|
||||
};
|
||||
SkyAerialLut(Sky* sky) : m_sky(sky) {}
|
||||
void Init();
|
||||
void Render(nvrhi::ICommandList* command_list, const glm::dmat4& projection,
|
||||
const glm::dmat4& view);
|
||||
nvrhi::TextureHandle m_lut;
|
||||
nvrhi::TextureHandle m_sky_texture;
|
||||
nvrhi::BufferHandle m_constant_buffer;
|
||||
nvrhi::ComputePipelineHandle m_pso_lut;
|
||||
nvrhi::ComputePipelineHandle m_pso_sky;
|
||||
int m_sky_width;
|
||||
int m_sky_height;
|
||||
int m_lut_width;
|
||||
int m_lut_height;
|
||||
int m_lut_slices;
|
||||
nvrhi::BindingSetHandle m_bindings_lut;
|
||||
nvrhi::BindingSetHandle m_bindings_sky;
|
||||
Sky* m_sky;
|
||||
};
|
||||
262
manul/renderer/source/ssao.cpp
Normal file
262
manul/renderer/source/ssao.cpp
Normal file
@@ -0,0 +1,262 @@
|
||||
#include "ssao.h"
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "XeGTAO.h"
|
||||
#include "gbuffer.h"
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
NvSsao::NvSsao(NvRenderer* renderer)
|
||||
: m_backend(renderer->m_backend.get()),
|
||||
m_gbuffer(renderer->m_gbuffer.get()),
|
||||
m_width(0),
|
||||
m_height(0) {}
|
||||
|
||||
void NvSsao::Init() {
|
||||
using namespace nvrhi;
|
||||
m_CSPrefilterDepths16x16 = m_backend->CreateShader(
|
||||
"gtao_CSPrefilterDepths16x16", ShaderType::Compute);
|
||||
m_CSGTAOLow = m_backend->CreateShader("gtao_CSGTAOLow", ShaderType::Compute);
|
||||
m_CSGTAOMedium =
|
||||
m_backend->CreateShader("gtao_CSGTAOMedium", ShaderType::Compute);
|
||||
m_CSGTAOHigh =
|
||||
m_backend->CreateShader("gtao_CSGTAOHigh", ShaderType::Compute);
|
||||
m_CSGTAOUltra =
|
||||
m_backend->CreateShader("gtao_CSGTAOUltra", ShaderType::Compute);
|
||||
m_CSDenoisePass =
|
||||
m_backend->CreateShader("gtao_CSDenoisePass", ShaderType::Compute);
|
||||
m_CSDenoiseLastPass =
|
||||
m_backend->CreateShader("gtao_CSDenoiseLastPass", ShaderType::Compute);
|
||||
|
||||
m_width = m_gbuffer->m_framebuffer->getFramebufferInfo().width;
|
||||
m_height = m_gbuffer->m_framebuffer->getFramebufferInfo().height;
|
||||
|
||||
m_constantBuffer = m_backend->GetDevice()->createBuffer(
|
||||
nvrhi::utils::CreateStaticConstantBufferDesc(
|
||||
sizeof(XeGTAO::GTAOConstants), "XeGTAO Constants")
|
||||
.setInitialState(ResourceStates::ConstantBuffer)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_workingDepths = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName("XeGTAO Working Depths")
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R32_FLOAT)
|
||||
.setMipLevels(XE_GTAO_DEPTH_MIP_LEVELS)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_workingEdges = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName("XeGTAO Working Edges")
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R8_UNORM)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_debugImage = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName("XeGTAO Debug Image")
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R11G11B10_FLOAT)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_workingAOTerm = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName("XeGTAO Working AO Term A")
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R8_UINT)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_workingAOTermPong = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName("XeGTAO Working AO Term B")
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R8_UINT)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
m_outputAO = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setDebugName("XeGTAO Output AO")
|
||||
.setWidth(m_width)
|
||||
.setHeight(m_height)
|
||||
.setIsUAV(true)
|
||||
.setFormat(Format::R8_UNORM)
|
||||
.setIsTypeless(true)
|
||||
.setInitialState(ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
|
||||
SamplerHandle sampler_point = m_SamplerPoint = m_backend->GetDevice()->createSampler(
|
||||
nvrhi::SamplerDesc()
|
||||
.setAllAddressModes(SamplerAddressMode::Clamp)
|
||||
.setAllFilters(false));
|
||||
|
||||
{
|
||||
BindingLayoutHandle blPrefilterDepths;
|
||||
BindingSetDesc bsDescPrefilter =
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::ConstantBuffer(0, m_constantBuffer))
|
||||
.addItem(BindingSetItem::Texture_SRV(0, m_gbuffer->m_gbuffer_depth))
|
||||
.addItem(BindingSetItem::Sampler(0, sampler_point));
|
||||
for (int i = 0; i < XE_GTAO_DEPTH_MIP_LEVELS; ++i) {
|
||||
bsDescPrefilter.addItem(
|
||||
BindingSetItem::Texture_UAV(i, m_workingDepths, Format::UNKNOWN,
|
||||
TextureSubresourceSet(i, 1, 0, 1)));
|
||||
}
|
||||
utils::CreateBindingSetAndLayout(m_backend->GetDevice(),
|
||||
ShaderType::Compute, 0, bsDescPrefilter,
|
||||
blPrefilterDepths, m_BSPrefilterDepths);
|
||||
m_PSOPrefilterDepths = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.setComputeShader(m_CSPrefilterDepths16x16)
|
||||
.addBindingLayout(blPrefilterDepths));
|
||||
}
|
||||
|
||||
{
|
||||
BindingLayoutHandle blGTAO;
|
||||
utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), ShaderType::Compute, 0,
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::ConstantBuffer(0, m_constantBuffer))
|
||||
.addItem(BindingSetItem ::Texture_SRV(0, m_workingDepths))
|
||||
.addItem(
|
||||
BindingSetItem::Texture_SRV(1, m_gbuffer->m_gbuffer_normal))
|
||||
.addItem(BindingSetItem::Texture_UAV(0, m_workingAOTerm))
|
||||
.addItem(BindingSetItem::Texture_UAV(1, m_workingEdges))
|
||||
.addItem(BindingSetItem::Texture_UAV(2, m_debugImage))
|
||||
.addItem(BindingSetItem::Sampler(0, sampler_point)),
|
||||
blGTAO, m_BSGTAO);
|
||||
m_PSOGTAO = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.setComputeShader(m_CSGTAOHigh)
|
||||
.addBindingLayout(blGTAO));
|
||||
}
|
||||
|
||||
{
|
||||
BindingLayoutHandle blDenoise;
|
||||
m_BLDenoise = m_backend->GetDevice()->createBindingLayout(
|
||||
BindingLayoutDesc()
|
||||
.setVisibility(nvrhi::ShaderType::Compute)
|
||||
.addItem(BindingLayoutItem::ConstantBuffer(0))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(0))
|
||||
.addItem(BindingLayoutItem::Texture_SRV(1))
|
||||
.addItem(BindingLayoutItem::Texture_UAV(0))
|
||||
.addItem(BindingLayoutItem::Texture_UAV(1))
|
||||
.addItem(BindingLayoutItem::Texture_UAV(2))
|
||||
.addItem(BindingLayoutItem::Sampler(0)));
|
||||
utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), ShaderType::Compute, 0,
|
||||
BindingSetDesc()
|
||||
.addItem(BindingSetItem::ConstantBuffer(0, m_constantBuffer))
|
||||
.addItem(BindingSetItem::Texture_SRV(1, m_workingEdges))
|
||||
.addItem(BindingSetItem::Texture_UAV(2, m_debugImage))
|
||||
.addItem(BindingSetItem::Sampler(0, sampler_point)),
|
||||
blDenoise, m_BSDenoise);
|
||||
m_PSODenoise = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.setComputeShader(m_CSDenoisePass)
|
||||
//.addBindingLayout(blDenoise)
|
||||
.addBindingLayout(m_BLDenoise));
|
||||
m_PSODenoiseLastPass = m_backend->GetDevice()->createComputePipeline(
|
||||
ComputePipelineDesc()
|
||||
.setComputeShader(m_CSDenoiseLastPass)
|
||||
//.addBindingLayout(blDenoise)
|
||||
.addBindingLayout(m_BLDenoise));
|
||||
}
|
||||
}
|
||||
|
||||
void NvSsao::Render(nvrhi::ICommandList* command_list,
|
||||
const glm::mat4& projection, size_t frame_index) {
|
||||
command_list->beginMarker("XeGTAO");
|
||||
|
||||
XeGTAO::GTAOConstants constants{};
|
||||
XeGTAO::GTAOSettings settings{};
|
||||
settings.QualityLevel = 2;
|
||||
settings.Radius = 10.f;
|
||||
settings.ThinOccluderCompensation = .7f;
|
||||
XeGTAO::GTAOUpdateConstants(constants, m_width, m_height, settings,
|
||||
glm::value_ptr(projection), false, frame_index);
|
||||
command_list->writeBuffer(m_constantBuffer, &constants, sizeof(constants));
|
||||
|
||||
{
|
||||
command_list->beginMarker("Prefilter Depth");
|
||||
nvrhi::ComputeState state;
|
||||
state.setPipeline(m_PSOPrefilterDepths);
|
||||
state.addBindingSet(m_BSPrefilterDepths);
|
||||
|
||||
command_list->setComputeState(state);
|
||||
command_list->dispatch((m_width + 16 - 1) / 16, (m_height + 16 - 1) / 16,
|
||||
1);
|
||||
command_list->endMarker();
|
||||
}
|
||||
|
||||
{
|
||||
command_list->beginMarker("Main Pass");
|
||||
nvrhi::ComputeState state;
|
||||
state.setPipeline(m_PSOGTAO);
|
||||
state.addBindingSet(m_BSGTAO);
|
||||
|
||||
command_list->setComputeState(state);
|
||||
command_list->dispatch(
|
||||
(m_width + XE_GTAO_NUMTHREADS_X - 1) / XE_GTAO_NUMTHREADS_X,
|
||||
(m_height + XE_GTAO_NUMTHREADS_Y - 1) / XE_GTAO_NUMTHREADS_Y, 1);
|
||||
command_list->endMarker();
|
||||
}
|
||||
|
||||
{
|
||||
command_list->beginMarker("Denoise Pass");
|
||||
int num_passes = 4;
|
||||
nvrhi::ITexture* ping = m_workingAOTerm;
|
||||
nvrhi::ITexture* pong = m_workingAOTermPong;
|
||||
for (int i = 0; i < num_passes; ++i) {
|
||||
nvrhi::ComputeState state;
|
||||
bool last_pass = i == num_passes - 1;
|
||||
auto bindingSet = m_backend->GetDevice()->createBindingSet(
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(
|
||||
nvrhi::BindingSetItem::ConstantBuffer(0, m_constantBuffer))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(0, ping))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
1, m_gbuffer->m_gbuffer_normal))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(
|
||||
0, last_pass ? m_outputAO.Get() : pong,
|
||||
nvrhi::Format::R8_UINT))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(1, m_workingEdges))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_UAV(2, m_debugImage))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(0, m_SamplerPoint)),
|
||||
m_BLDenoise);
|
||||
state.setPipeline(last_pass ? m_PSODenoiseLastPass : m_PSODenoise);
|
||||
// state.addBindingSet(m_BSDenoise);
|
||||
state.addBindingSet(bindingSet);
|
||||
|
||||
command_list->setComputeState(state);
|
||||
command_list->dispatch(
|
||||
(m_width + (XE_GTAO_NUMTHREADS_X * 2) - 1) /
|
||||
(XE_GTAO_NUMTHREADS_X * 2),
|
||||
(m_height + XE_GTAO_NUMTHREADS_Y - 1) / XE_GTAO_NUMTHREADS_Y, 1);
|
||||
std::swap(ping, pong);
|
||||
}
|
||||
command_list->endMarker();
|
||||
|
||||
command_list->setTextureState(m_outputAO, nvrhi::AllSubresources,
|
||||
nvrhi::ResourceStates::ShaderResource);
|
||||
}
|
||||
command_list->endMarker();
|
||||
}
|
||||
55
manul/renderer/source/ssao.h
Normal file
55
manul/renderer/source/ssao.h
Normal file
@@ -0,0 +1,55 @@
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
struct NvSsao {
|
||||
NvSsao(class NvRenderer* renderer);
|
||||
void Init();
|
||||
|
||||
class NvRendererBackend* m_backend;
|
||||
struct NvGbuffer* m_gbuffer;
|
||||
|
||||
nvrhi::ShaderHandle m_CSPrefilterDepths16x16;
|
||||
nvrhi::ComputePipelineHandle m_PSOPrefilterDepths;
|
||||
nvrhi::BindingSetHandle m_BSPrefilterDepths;
|
||||
|
||||
nvrhi::SamplerHandle m_SamplerPoint;
|
||||
|
||||
nvrhi::ShaderHandle m_CSGTAOLow;
|
||||
nvrhi::ShaderHandle m_CSGTAOMedium;
|
||||
nvrhi::ShaderHandle m_CSGTAOHigh;
|
||||
nvrhi::ShaderHandle m_CSGTAOUltra;
|
||||
nvrhi::ComputePipelineHandle m_PSOGTAO;
|
||||
nvrhi::BindingSetHandle m_BSGTAO;
|
||||
|
||||
nvrhi::ShaderHandle m_CSDenoisePass;
|
||||
nvrhi::ShaderHandle m_CSDenoiseLastPass;
|
||||
nvrhi::ComputePipelineHandle m_PSODenoise;
|
||||
nvrhi::ComputePipelineHandle m_PSODenoiseLastPass;
|
||||
nvrhi::BindingLayoutHandle m_BLDenoise;
|
||||
nvrhi::BindingSetHandle m_BSDenoise;
|
||||
|
||||
nvrhi::ShaderHandle m_CSGenerateNormals;
|
||||
nvrhi::ComputePipelineHandle m_PSOGenerateNormals;
|
||||
nvrhi::BindingSetHandle m_BSGenerateNormals;
|
||||
|
||||
nvrhi::TextureHandle m_workingDepths;
|
||||
nvrhi::TextureHandle m_workingEdges;
|
||||
nvrhi::TextureHandle m_workingAOTerm;
|
||||
nvrhi::TextureHandle m_workingAOTermPong;
|
||||
nvrhi::TextureHandle m_workingNormals;
|
||||
nvrhi::TextureHandle m_debugImage;
|
||||
nvrhi::TextureHandle m_outputAO;
|
||||
nvrhi::BufferHandle m_constantBuffer;
|
||||
|
||||
|
||||
int m_width;
|
||||
int m_height;
|
||||
|
||||
void Render(nvrhi::ICommandList* command_list, const glm::mat4& projection,
|
||||
size_t frame_index);
|
||||
};
|
||||
7985
manul/renderer/source/stbi/stb_image.h
Normal file
7985
manul/renderer/source/stbi/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
10365
manul/renderer/source/stbi/stb_image_resize2.h
Normal file
10365
manul/renderer/source/stbi/stb_image_resize2.h
Normal file
File diff suppressed because it is too large
Load Diff
9307
manul/renderer/source/tinyexr.h
Normal file
9307
manul/renderer/source/tinyexr.h
Normal file
File diff suppressed because it is too large
Load Diff
68
manul/renderer/source/tonemap.cpp
Normal file
68
manul/renderer/source/tonemap.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
#include "tonemap.h"
|
||||
|
||||
#include <nvrhi/utils.h>
|
||||
|
||||
#include "config.h"
|
||||
#include "nvrendererbackend.h"
|
||||
|
||||
void TonemapPass::Init() {
|
||||
nvrhi::utils::CreateBindingSetAndLayout(
|
||||
m_backend->GetDevice(), nvrhi::ShaderType::Pixel, 0,
|
||||
nvrhi::BindingSetDesc()
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(0, m_source))
|
||||
.addItem(nvrhi::BindingSetItem::Texture_SRV(
|
||||
1, static_cast<nvrhi::ITexture*>(
|
||||
m_renderer
|
||||
->GetResource("noise_2d_ldr",
|
||||
nvrhi::ResourceType::Texture_SRV)
|
||||
.m_resource)))
|
||||
.addItem(nvrhi::BindingSetItem::Sampler(
|
||||
0, m_backend->GetDevice()->createSampler(nvrhi::SamplerDesc())))
|
||||
.addItem(nvrhi::BindingSetItem::PushConstants(0, sizeof(glm::vec4))),
|
||||
m_binding_layout, m_binding_set);
|
||||
m_pixel_shader = m_backend->CreateShader("tonemap", nvrhi::ShaderType::Pixel);
|
||||
m_output = m_backend->GetDevice()->createTexture(
|
||||
nvrhi::TextureDesc()
|
||||
.setFormat(m_output_format)
|
||||
.setWidth(m_source->getDesc().width)
|
||||
.setHeight(m_source->getDesc().height)
|
||||
.setIsRenderTarget(true)
|
||||
.setInitialState(nvrhi::ResourceStates::ShaderResource)
|
||||
.setKeepInitialState(true));
|
||||
m_framebuffer = m_backend->GetDevice()->createFramebuffer(
|
||||
nvrhi::FramebufferDesc().addColorAttachment(m_output));
|
||||
FullScreenPass::Init();
|
||||
}
|
||||
|
||||
void TonemapPass::CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) {
|
||||
FullScreenPass::CreatePipelineDesc(pipeline_desc);
|
||||
pipeline_desc.addBindingLayout(m_binding_layout);
|
||||
pipeline_desc.setPixelShader(m_pixel_shader);
|
||||
}
|
||||
|
||||
void TonemapPass::Render(nvrhi::ICommandList* command_list) {
|
||||
nvrhi::GraphicsState graphics_state;
|
||||
InitState(graphics_state);
|
||||
graphics_state.addBindingSet(m_binding_set);
|
||||
command_list->setGraphicsState(graphics_state);
|
||||
|
||||
auto hdr_config = NvRenderer::Config()->m_display.GetHDRConfig();
|
||||
|
||||
struct TonemapConstants {
|
||||
MaConfig::MaTonemapType m_tonemap_function;
|
||||
float m_scene_exposure;
|
||||
float m_scene_nits;
|
||||
float m_scene_gamma;
|
||||
} tonemap_constants{hdr_config.m_tonemap_function,
|
||||
glm::pow(2.f, hdr_config.m_scene_exposure), hdr_config.m_scene_nits,
|
||||
hdr_config.m_scene_gamma};
|
||||
|
||||
command_list->setPushConstants(&tonemap_constants, sizeof(tonemap_constants));
|
||||
|
||||
Draw(command_list);
|
||||
}
|
||||
|
||||
nvrhi::IFramebuffer* TonemapPass::GetFramebuffer() {
|
||||
return FullScreenPass::GetFramebuffer(); // m_framebuffer;
|
||||
}
|
||||
39
manul/renderer/source/tonemap.h
Normal file
39
manul/renderer/source/tonemap.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <nvrhi/nvrhi.h>
|
||||
|
||||
#include "nvrenderer/nvrenderer.h"
|
||||
|
||||
#include "fullscreenpass.h"
|
||||
|
||||
struct TonemapPass : public FullScreenPass {
|
||||
TonemapPass(class NvRenderer* renderer, nvrhi::ITexture* source,
|
||||
nvrhi::Format output_format = nvrhi::Format::UNKNOWN)
|
||||
: FullScreenPass(renderer->GetBackend()),
|
||||
m_renderer(renderer),
|
||||
m_source(source),
|
||||
m_output_format(output_format == nvrhi::Format::UNKNOWN
|
||||
? source->getDesc().format
|
||||
: output_format) {}
|
||||
|
||||
virtual void Init() override;
|
||||
|
||||
virtual void CreatePipelineDesc(
|
||||
nvrhi::GraphicsPipelineDesc& pipeline_desc) override;
|
||||
|
||||
virtual void Render(nvrhi::ICommandList* command_list) override;
|
||||
|
||||
virtual nvrhi::IFramebuffer* GetFramebuffer() override;
|
||||
|
||||
nvrhi::BindingLayoutHandle m_binding_layout;
|
||||
nvrhi::BindingSetHandle m_binding_set;
|
||||
nvrhi::ShaderHandle m_pixel_shader;
|
||||
nvrhi::FramebufferHandle m_framebuffer;
|
||||
|
||||
nvrhi::ITexture* m_source;
|
||||
nvrhi::Format m_output_format;
|
||||
|
||||
nvrhi::TextureHandle m_output;
|
||||
|
||||
class NvRenderer* m_renderer;
|
||||
};
|
||||
0
manul/renderer/source/topo_utils.cpp
Normal file
0
manul/renderer/source/topo_utils.cpp
Normal file
10
manul/renderer/source/topo_utils.h
Normal file
10
manul/renderer/source/topo_utils.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include <Model3d.h>
|
||||
|
||||
struct MaTopologyUtils {
|
||||
|
||||
void ConvertTopology(gfx::index_array &Indices, gfx::vertex_array &Vertices,
|
||||
int const Typ) const;
|
||||
|
||||
};
|
||||
1101
manul/renderer/source/track_batching.cpp
Normal file
1101
manul/renderer/source/track_batching.cpp
Normal file
File diff suppressed because it is too large
Load Diff
35
manul/renderer/source/vaTAAShared.h
Normal file
35
manul/renderer/source/vaTAAShared.h
Normal file
@@ -0,0 +1,35 @@
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Copyright (C) 2016-2021, Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: MIT
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Author(s): Lukasz, Migas (Lukasz.Migas@intel.com) - TAA code, Filip Strugar (filip.strugar@intel.com) - integration
|
||||
//
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __TAA_SHARED_H__
|
||||
#define __TAA_SHARED_H__
|
||||
|
||||
#include "IntelTAA.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
namespace IntelTAA
|
||||
{
|
||||
#endif // #ifdef __cplusplus
|
||||
|
||||
#define TAA_CONSTANTSBUFFERSLOT 0
|
||||
|
||||
// used in a generic way depending on the shader
|
||||
struct TAAConstants
|
||||
{
|
||||
Matrix4x4 ReprojectionMatrix;
|
||||
FTAAResolve Consts;
|
||||
};
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // close the namespace
|
||||
#endif // #ifdef __cplusplus
|
||||
|
||||
|
||||
#endif // __TAA_SHARED_H__
|
||||
Reference in New Issue
Block a user