16
0
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:
WLs50
2025-03-09 15:36:11 +01:00
parent a687f551a2
commit a5f6397eca
1211 changed files with 483542 additions and 58643 deletions

View 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__

View 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__

View 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));
}

View 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;
};

View 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();
}

View 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;
};

View 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);
}

View 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;
};

View 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));
}

View 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;
};

View 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;
}

View 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;
};

View 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;
}

View 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;
};
};

View 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.

File diff suppressed because it is too large Load Diff

View 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;
}

View 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;
};

View 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);
}

View 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();
};

View 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));
}

View 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;
};

View 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);
}
}

View 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);
};

View 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; }

View 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;
};

View 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});
}

View 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;
};

View 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;
}

View 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);
};

View File

@@ -0,0 +1 @@
#include "instancecache.h"

View 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);
}
};

View 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;
}

View 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;
}

View 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;
};

View 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);
}

View 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;
}
};

View 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;
}

View File

@@ -0,0 +1,7 @@
#pragma once
struct NvMaterial {
};

View File

@@ -0,0 +1 @@
#include "nvmaterial.h"

File diff suppressed because it is too large Load Diff

View 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

View 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

View 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();
}

View 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);
};

File diff suppressed because it is too large Load Diff

View 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

View 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};
}

View 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;
};

View 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;
}
}
}

View 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;
};

View 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);
}
}
}

View 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);
}
}

View 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

View 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

View 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
View 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;
};

View 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();
}

View 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);
};

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View 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;
}

View 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;
};

View File

View 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;
};

File diff suppressed because it is too large Load Diff

View 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__