763 lines
41 KiB
C#

//using System;
//using UnityEngine.Rendering;
//using UnityEngine.Experimental.Rendering.RenderGraphModule;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Experimental.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering.HighDefinition
{
public partial class HDRenderPipeline
{
struct LightingBuffers
{
// TODO RENDERGRAPH: Those two buffers aren't really lighting buffers but only used for SSS
// We should probably move them out of here.
public TextureHandle sssBuffer;
public TextureHandle diffuseLightingBuffer;
public TextureHandle ambientOcclusionBuffer;
public TextureHandle ssrLightingBuffer;
public TextureHandle ssgiLightingBuffer;
public TextureHandle contactShadowsBuffer;
public TextureHandle screenspaceShadowBuffer;
}
static LightingBuffers ReadLightingBuffers(in LightingBuffers buffers, RenderGraphBuilder builder)
{
var result = new LightingBuffers();
// We only read those buffers because sssBuffer and diffuseLightingBuffer our just output of the lighting process, not inputs.
result.ambientOcclusionBuffer = builder.ReadTexture(buffers.ambientOcclusionBuffer);
result.ssrLightingBuffer = builder.ReadTexture(buffers.ssrLightingBuffer);
result.ssgiLightingBuffer = builder.ReadTexture(buffers.ssgiLightingBuffer);
result.contactShadowsBuffer = builder.ReadTexture(buffers.contactShadowsBuffer);
result.screenspaceShadowBuffer = builder.ReadTexture(buffers.screenspaceShadowBuffer);
return result;
}
static void BindGlobalLightingBuffers(in LightingBuffers buffers, CommandBuffer cmd)
{
cmd.SetGlobalTexture(HDShaderIDs._AmbientOcclusionTexture, buffers.ambientOcclusionBuffer);
cmd.SetGlobalTexture(HDShaderIDs._SsrLightingTexture, buffers.ssrLightingBuffer);
cmd.SetGlobalTexture(HDShaderIDs._IndirectDiffuseTexture, buffers.ssgiLightingBuffer);
cmd.SetGlobalTexture(HDShaderIDs._ContactShadowTexture, buffers.contactShadowsBuffer);
cmd.SetGlobalTexture(HDShaderIDs._ScreenSpaceShadowsTexture, buffers.screenspaceShadowBuffer);
}
class BuildGPULightListPassData
{
public BuildGPULightListParameters buildGPULightListParameters;
public TextureHandle depthBuffer;
public TextureHandle stencilTexture;
public TextureHandle[] gBuffer = new TextureHandle[RenderGraph.kMaxMRTCount];
public int gBufferCount;
// Buffers filled with the CPU outside of render graph.
public ComputeBufferHandle convexBoundsBuffer;
public ComputeBufferHandle AABBBoundsBuffer;
// Transient buffers that are not used outside of BuildGPULight list so they don't need to go outside the pass.
public ComputeBufferHandle globalLightListAtomic;
public ComputeBufferHandle lightVolumeDataBuffer;
public BuildGPULightListOutput output = new BuildGPULightListOutput();
}
struct BuildGPULightListOutput
{
// Tile
public ComputeBufferHandle lightList;
public ComputeBufferHandle tileList;
public ComputeBufferHandle tileFeatureFlags;
public ComputeBufferHandle dispatchIndirectBuffer;
// Big Tile
public ComputeBufferHandle bigTileLightList;
// Cluster
public ComputeBufferHandle perVoxelOffset;
public ComputeBufferHandle perVoxelLightLists;
public ComputeBufferHandle perTileLogBaseTweak;
}
static BuildGPULightListResources PrepareBuildGPULightListResources(RenderGraphContext context, BuildGPULightListPassData data)
{
var buildLightListResources = new BuildGPULightListResources();
// Depending on frame setting configurations we might not have written to a depth buffer yet.
RTHandle depthBuffer = data.depthBuffer;
if (depthBuffer == null)
{
buildLightListResources.depthBuffer = context.defaultResources.blackTextureXR;
buildLightListResources.stencilTexture = context.defaultResources.blackTextureXR;
}
else
{
buildLightListResources.depthBuffer = data.depthBuffer;
buildLightListResources.stencilTexture = data.stencilTexture;
}
if (data.buildGPULightListParameters.computeMaterialVariants && data.buildGPULightListParameters.enableFeatureVariants)
{
buildLightListResources.gBuffer = context.renderGraphPool.GetTempArray<RTHandle>(data.gBufferCount);
for (int i = 0; i < data.gBufferCount; ++i)
buildLightListResources.gBuffer[i] = data.gBuffer[i];
}
buildLightListResources.lightVolumeDataBuffer = data.lightVolumeDataBuffer;
buildLightListResources.convexBoundsBuffer = data.convexBoundsBuffer;
buildLightListResources.AABBBoundsBuffer = data.AABBBoundsBuffer;
buildLightListResources.globalLightListAtomic = data.globalLightListAtomic;
buildLightListResources.tileFeatureFlags = data.output.tileFeatureFlags;
buildLightListResources.dispatchIndirectBuffer = data.output.dispatchIndirectBuffer;
buildLightListResources.perVoxelOffset = data.output.perVoxelOffset;
buildLightListResources.perTileLogBaseTweak = data.output.perTileLogBaseTweak;
buildLightListResources.tileList = data.output.tileList;
buildLightListResources.bigTileLightList = data.output.bigTileLightList;
buildLightListResources.perVoxelLightLists = data.output.perVoxelLightLists;
buildLightListResources.lightList = data.output.lightList;
return buildLightListResources;
}
BuildGPULightListOutput BuildGPULightList(RenderGraph renderGraph,
HDCamera hdCamera,
TileAndClusterData tileAndClusterData,
int totalLightCount,
ref ShaderVariablesLightList constantBuffer,
TextureHandle depthStencilBuffer,
TextureHandle stencilBufferCopy,
GBufferOutput gBuffer)
{
using (var builder = renderGraph.AddRenderPass<BuildGPULightListPassData>("Build Light List", out var passData, ProfilingSampler.Get(HDProfileId.BuildLightList)))
{
builder.EnableAsyncCompute(hdCamera.frameSettings.BuildLightListRunsAsync());
passData.buildGPULightListParameters = PrepareBuildGPULightListParameters(hdCamera, tileAndClusterData, ref constantBuffer, totalLightCount);
passData.depthBuffer = builder.ReadTexture(depthStencilBuffer);
passData.stencilTexture = builder.ReadTexture(stencilBufferCopy);
if (passData.buildGPULightListParameters.computeMaterialVariants && passData.buildGPULightListParameters.enableFeatureVariants)
{
for (int i = 0; i < gBuffer.gBufferCount; ++i)
passData.gBuffer[i] = builder.ReadTexture(gBuffer.mrt[i]);
passData.gBufferCount = gBuffer.gBufferCount;
}
// Here we use m_MaxViewCount/m_MaxWidthHeight to avoid always allocating buffers of different sizes for each camera.
// This way we'll be reusing them more often.
// Those buffer are filled with the CPU outside of the render graph.
passData.convexBoundsBuffer = builder.ReadComputeBuffer(renderGraph.ImportComputeBuffer(tileAndClusterData.convexBoundsBuffer));
passData.lightVolumeDataBuffer = builder.ReadComputeBuffer(renderGraph.ImportComputeBuffer(tileAndClusterData.lightVolumeDataBuffer));
passData.globalLightListAtomic = builder.CreateTransientComputeBuffer(new ComputeBufferDesc(1, sizeof(uint)) { name = "LightListAtomic" });
passData.AABBBoundsBuffer = builder.CreateTransientComputeBuffer(new ComputeBufferDesc(m_MaxViewCount * 2 * tileAndClusterData.maxLightCount, 4 * sizeof(float)) { name = "AABBBoundBuffer" });
var nrTilesX = (m_MaxCameraWidth + LightDefinitions.s_TileSizeFptl - 1) / LightDefinitions.s_TileSizeFptl;
var nrTilesY = (m_MaxCameraHeight + LightDefinitions.s_TileSizeFptl - 1) / LightDefinitions.s_TileSizeFptl;
var nrTiles = nrTilesX * nrTilesY * m_MaxViewCount;
const int capacityUShortsPerTile = 32;
const int dwordsPerTile = (capacityUShortsPerTile + 1) >> 1; // room for 31 lights and a nrLights value.
if (tileAndClusterData.hasTileBuffers)
{
// note that nrTiles include the viewCount in allocation below
// Tile buffers
passData.output.lightList = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc((int)LightCategory.Count * dwordsPerTile * nrTiles, sizeof(uint)) { name = "LightList" }));
passData.output.tileList = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc(LightDefinitions.s_NumFeatureVariants * nrTiles, sizeof(uint)) { name = "TileList" }));
passData.output.tileFeatureFlags = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc(nrTiles, sizeof(uint)) { name = "TileFeatureFlags" }));
// DispatchIndirect: Buffer with arguments has to have three integer numbers at given argsOffset offset: number of work groups in X dimension, number of work groups in Y dimension, number of work groups in Z dimension.
// DrawProceduralIndirect: Buffer with arguments has to have four integer numbers at given argsOffset offset: vertex count per instance, instance count, start vertex location, and start instance location
// Use use max size of 4 unit for allocation
passData.output.dispatchIndirectBuffer = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc(m_MaxViewCount * LightDefinitions.s_NumFeatureVariants * 4, sizeof(uint), ComputeBufferType.IndirectArguments) { name = "DispatchIndirectBuffer" }));
}
// Big Tile buffer
if (passData.buildGPULightListParameters.runBigTilePrepass)
{
var nrBigTilesX = (m_MaxCameraWidth + 63) / 64;
var nrBigTilesY = (m_MaxCameraHeight + 63) / 64;
var nrBigTiles = nrBigTilesX * nrBigTilesY * m_MaxViewCount;
// TODO: (Nick) In the case of Probe Volumes, this buffer could be trimmed down / tuned more specifically to probe volumes if we added a s_MaxNrBigTileProbeVolumesPlusOne value.
passData.output.bigTileLightList = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc(LightDefinitions.s_MaxNrBigTileLightsPlusOne * nrBigTiles, sizeof(uint)) { name = "BigTiles" }));
}
// Cluster buffers
var nrClustersX = (m_MaxCameraWidth + LightDefinitions.s_TileSizeClustered - 1) / LightDefinitions.s_TileSizeClustered;
var nrClustersY = (m_MaxCameraHeight + LightDefinitions.s_TileSizeClustered - 1) / LightDefinitions.s_TileSizeClustered;
var nrClusterTiles = nrClustersX * nrClustersY * m_MaxViewCount;
passData.output.perVoxelOffset = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc((int)LightCategory.Count * (1 << k_Log2NumClusters) * nrClusterTiles, sizeof(uint)) { name = "PerVoxelOffset" }));
passData.output.perVoxelLightLists = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc(NumLightIndicesPerClusteredTile() * nrClusterTiles, sizeof(uint)) { name = "PerVoxelLightList" }));
if (tileAndClusterData.clusterNeedsDepth)
{
passData.output.perTileLogBaseTweak = builder.WriteComputeBuffer(
renderGraph.CreateComputeBuffer(new ComputeBufferDesc(nrClusterTiles, sizeof(float)) { name = "PerTileLogBaseTweak" }));
}
builder.SetRenderFunc(
(BuildGPULightListPassData data, RenderGraphContext context) =>
{
bool tileFlagsWritten = false;
var buildLightListResources = PrepareBuildGPULightListResources(context, data);
ClearLightLists(data.buildGPULightListParameters, buildLightListResources, context.cmd);
GenerateLightsScreenSpaceAABBs(data.buildGPULightListParameters, buildLightListResources, context.cmd);
BigTilePrepass(data.buildGPULightListParameters, buildLightListResources, context.cmd);
BuildPerTileLightList(data.buildGPULightListParameters, buildLightListResources, ref tileFlagsWritten, context.cmd);
VoxelLightListGeneration(data.buildGPULightListParameters, buildLightListResources, context.cmd);
BuildDispatchIndirectArguments(data.buildGPULightListParameters, buildLightListResources, tileFlagsWritten, context.cmd);
});
return passData.output;
}
}
class PushGlobalCameraParamPassData
{
public HDCamera hdCamera;
public ShaderVariablesGlobal globalCB;
public ShaderVariablesXR xrCB;
}
void PushGlobalCameraParams(RenderGraph renderGraph, HDCamera hdCamera)
{
using (var builder = renderGraph.AddRenderPass<PushGlobalCameraParamPassData>("Push Global Camera Parameters", out var passData))
{
passData.hdCamera = hdCamera;
passData.globalCB = m_ShaderVariablesGlobalCB;
passData.xrCB = m_ShaderVariablesXRCB;
builder.SetRenderFunc(
(PushGlobalCameraParamPassData data, RenderGraphContext context) =>
{
data.hdCamera.UpdateShaderVariablesGlobalCB(ref data.globalCB);
ConstantBuffer.PushGlobal(context.cmd, data.globalCB, HDShaderIDs._ShaderVariablesGlobal);
data.hdCamera.UpdateShaderVariablesXRCB(ref data.xrCB);
ConstantBuffer.PushGlobal(context.cmd, data.xrCB, HDShaderIDs._ShaderVariablesXR);
});
}
}
internal ShadowResult RenderShadows(RenderGraph renderGraph, HDCamera hdCamera, CullingResults cullResults, ref ShadowResult result)
{
m_ShadowManager.RenderShadows(m_RenderGraph, m_ShaderVariablesGlobalCB, hdCamera, cullResults, ref result);
// Need to restore global camera parameters.
PushGlobalCameraParams(renderGraph, hdCamera);
return result;
}
TextureHandle CreateDiffuseLightingBuffer(RenderGraph renderGraph, bool msaa)
{
return renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
{
colorFormat = GraphicsFormat.B10G11R11_UFloatPack32,
enableRandomWrite = !msaa,
bindTextureMS = msaa,
enableMSAA = msaa,
clearBuffer = true,
clearColor = Color.clear,
name = msaa ? "CameraSSSDiffuseLightingMSAA" : "CameraSSSDiffuseLighting"
});
}
class DeferredLightingPassData
{
public DeferredLightingParameters parameters;
public TextureHandle colorBuffer;
public TextureHandle sssDiffuseLightingBuffer;
public TextureHandle depthBuffer;
public TextureHandle depthTexture;
public int gbufferCount;
public int lightLayersTextureIndex;
public int shadowMaskTextureIndex;
public TextureHandle[] gbuffer = new TextureHandle[8];
public ComputeBufferHandle lightListBuffer;
public ComputeBufferHandle tileFeatureFlagsBuffer;
public ComputeBufferHandle tileListBuffer;
public ComputeBufferHandle dispatchIndirectBuffer;
public LightingBuffers lightingBuffers;
}
struct LightingOutput
{
public TextureHandle colorBuffer;
}
LightingOutput RenderDeferredLighting(RenderGraph renderGraph,
HDCamera hdCamera,
TextureHandle colorBuffer,
TextureHandle depthStencilBuffer,
TextureHandle depthPyramidTexture,
in LightingBuffers lightingBuffers,
in GBufferOutput gbuffer,
in ShadowResult shadowResult,
in BuildGPULightListOutput lightLists)
{
if (hdCamera.frameSettings.litShaderMode != LitShaderMode.Deferred ||
!hdCamera.frameSettings.IsEnabled(FrameSettingsField.OpaqueObjects))
return new LightingOutput();
using (var builder = renderGraph.AddRenderPass<DeferredLightingPassData>("Deferred Lighting", out var passData))
{
passData.parameters = PrepareDeferredLightingParameters(hdCamera, m_CurrentDebugDisplaySettings);
passData.colorBuffer = builder.WriteTexture(colorBuffer);
if (passData.parameters.outputSplitLighting)
{
passData.sssDiffuseLightingBuffer = builder.WriteTexture(lightingBuffers.diffuseLightingBuffer);
}
else
{
// TODO RENDERGRAPH: Check how to avoid this kind of pattern.
// Unfortunately, the low level needs this texture to always be bound with UAV enabled, so in order to avoid effectively creating the full resolution texture here,
// we need to create a small dummy texture.
passData.sssDiffuseLightingBuffer = builder.CreateTransientTexture(new TextureDesc(1, 1, true, true) { colorFormat = GraphicsFormat.B10G11R11_UFloatPack32, enableRandomWrite = true });
}
passData.depthBuffer = builder.ReadTexture(depthStencilBuffer);
passData.depthTexture = builder.ReadTexture(depthPyramidTexture);
passData.lightingBuffers = ReadLightingBuffers(lightingBuffers, builder);
passData.lightLayersTextureIndex = gbuffer.lightLayersTextureIndex;
passData.shadowMaskTextureIndex = gbuffer.shadowMaskTextureIndex;
passData.gbufferCount = gbuffer.gBufferCount;
for (int i = 0; i < gbuffer.gBufferCount; ++i)
passData.gbuffer[i] = builder.ReadTexture(gbuffer.mrt[i]);
HDShadowManager.ReadShadowResult(shadowResult, builder);
passData.lightListBuffer = builder.ReadComputeBuffer(lightLists.lightList);
passData.tileFeatureFlagsBuffer = builder.ReadComputeBuffer(lightLists.tileFeatureFlags);
passData.tileListBuffer = builder.ReadComputeBuffer(lightLists.tileList);
passData.dispatchIndirectBuffer = builder.ReadComputeBuffer(lightLists.dispatchIndirectBuffer);
var output = new LightingOutput();
output.colorBuffer = passData.colorBuffer;
builder.SetRenderFunc(
(DeferredLightingPassData data, RenderGraphContext context) =>
{
var resources = new DeferredLightingResources();
resources.colorBuffers = context.renderGraphPool.GetTempArray<RenderTargetIdentifier>(2);
resources.colorBuffers[0] = data.colorBuffer;
resources.colorBuffers[1] = data.sssDiffuseLightingBuffer;
resources.depthStencilBuffer = data.depthBuffer;
resources.depthTexture = data.depthTexture;
resources.lightListBuffer = data.lightListBuffer;
resources.tileFeatureFlagsBuffer = data.tileFeatureFlagsBuffer;
resources.tileListBuffer = data.tileListBuffer;
resources.dispatchIndirectBuffer = data.dispatchIndirectBuffer;
// TODO RENDERGRAPH: try to find a better way to bind this.
// Issue is that some GBuffers have several names (for example normal buffer is both NormalBuffer and GBuffer1)
// So it's not possible to use auto binding via dependency to shaderTagID
// Should probably get rid of auto binding and go explicit all the way (might need to wait for us to remove non rendergraph code path).
for (int i = 0; i < data.gbufferCount; ++i)
context.cmd.SetGlobalTexture(HDShaderIDs._GBufferTexture[i], data.gbuffer[i]);
if (data.lightLayersTextureIndex != -1)
context.cmd.SetGlobalTexture(HDShaderIDs._LightLayersTexture, data.gbuffer[data.lightLayersTextureIndex]);
else
context.cmd.SetGlobalTexture(HDShaderIDs._LightLayersTexture, TextureXR.GetWhiteTexture());
if (data.shadowMaskTextureIndex != -1)
context.cmd.SetGlobalTexture(HDShaderIDs._ShadowMaskTexture, data.gbuffer[data.shadowMaskTextureIndex]);
else
context.cmd.SetGlobalTexture(HDShaderIDs._ShadowMaskTexture, TextureXR.GetWhiteTexture());
// TODO RENDERGRAPH: Remove these SetGlobal and properly send these textures to the deferred passes and bind them directly to compute shaders.
// This can wait that we remove the old code path.
BindGlobalLightingBuffers(data.lightingBuffers, context.cmd);
if (data.parameters.enableTile)
{
bool useCompute = data.parameters.useComputeLightingEvaluation && !k_PreferFragment;
if (useCompute)
RenderComputeDeferredLighting(data.parameters, resources, context.cmd);
else
RenderComputeAsPixelDeferredLighting(data.parameters, resources, context.cmd);
}
else
{
RenderPixelDeferredLighting(data.parameters, resources, context.cmd);
}
});
return output;
}
}
class RenderSSRPassData
{
public RenderSSRParameters parameters;
public TextureHandle depthBuffer;
public TextureHandle depthPyramid;
public TextureHandle normalBuffer;
public TextureHandle motionVectorsBuffer;
public TextureHandle colorPyramid;
public TextureHandle stencilBuffer;
public TextureHandle hitPointsTexture;
public TextureHandle ssrAccum;
public TextureHandle lightingTexture;
public TextureHandle ssrAccumPrev;
public TextureHandle clearCoatMask;
public ComputeBufferHandle coarseStencilBuffer;
public BlueNoise blueNoise;
public HDCamera hdCamera;
//public TextureHandle debugTexture;
}
TextureHandle RenderSSR(RenderGraph renderGraph,
HDCamera hdCamera,
ref PrepassOutput prepassOutput,
TextureHandle clearCoatMask,
TextureHandle rayCountTexture,
Texture skyTexture,
bool transparent)
{
if (!hdCamera.IsSSREnabled(transparent))
return renderGraph.defaultResources.blackTextureXR;
TextureHandle result;
var settings = hdCamera.volumeStack.GetComponent<ScreenSpaceReflection>();
bool usesRaytracedReflections = hdCamera.frameSettings.IsEnabled(FrameSettingsField.RayTracing) && settings.rayTracing.value;
if (usesRaytracedReflections)
{
result = RenderRayTracedReflections(renderGraph, hdCamera,
prepassOutput.depthBuffer, prepassOutput.stencilBuffer, prepassOutput.normalBuffer, prepassOutput.resolvedMotionVectorsBuffer, clearCoatMask, skyTexture, rayCountTexture,
m_ShaderVariablesRayTracingCB, transparent);
}
else
{
if (transparent)
{
// NOTE: Currently we profiled that generating the HTile for SSR and using it is not worth it the optimization.
// However if the generated HTile will be used for something else but SSR, this should be made NOT resolve only and
// re-enabled in the shader.
BuildCoarseStencilAndResolveIfNeeded(renderGraph, hdCamera, resolveOnly: true, ref prepassOutput);
}
using (var builder = renderGraph.AddRenderPass<RenderSSRPassData>("Render SSR", out var passData))
{
builder.EnableAsyncCompute(hdCamera.frameSettings.SSRRunsAsync());
hdCamera.AllocateScreenSpaceAccumulationHistoryBuffer(1.0f);
bool usePBRAlgo = !transparent && settings.usedAlgorithm.value == ScreenSpaceReflectionAlgorithm.PBRAccumulation;
var colorPyramid = renderGraph.ImportTexture(hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ColorBufferMipChain));
passData.parameters = PrepareSSRParameters(hdCamera, m_DepthBufferMipChainInfo, transparent);
passData.depthBuffer = builder.ReadTexture(prepassOutput.depthBuffer);
passData.depthPyramid = builder.ReadTexture(prepassOutput.depthPyramidTexture);
passData.colorPyramid = builder.ReadTexture(colorPyramid);
passData.stencilBuffer = builder.ReadTexture(prepassOutput.stencilBuffer);
passData.clearCoatMask = builder.ReadTexture(clearCoatMask);
passData.coarseStencilBuffer = builder.ReadComputeBuffer(prepassOutput.coarseStencilBuffer);
passData.normalBuffer = builder.ReadTexture(prepassOutput.resolvedNormalBuffer);
passData.motionVectorsBuffer = builder.ReadTexture(prepassOutput.resolvedMotionVectorsBuffer);
passData.hdCamera = hdCamera;
passData.blueNoise = GetBlueNoiseManager();
ScreenSpaceReflection ssrVolumeSettings = hdCamera.volumeStack.GetComponent<ScreenSpaceReflection>();
// In practice, these textures are sparse (mostly black). Therefore, clearing them is fast (due to CMASK),
// and much faster than fully overwriting them from within SSR shaders.
passData.hitPointsTexture = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
{ colorFormat = GraphicsFormat.R16G16_UNorm, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = transparent ? "SSR_Hit_Point_Texture_Trans" : "SSR_Hit_Point_Texture" });
if (usePBRAlgo)
{
TextureHandle ssrAccum = renderGraph.ImportTexture(hdCamera.GetCurrentFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation));
TextureHandle ssrAccumPrev = renderGraph.ImportTexture(hdCamera.GetPreviousFrameRT((int)HDCameraFrameHistoryType.ScreenSpaceReflectionAccumulation));;
passData.ssrAccum = builder.WriteTexture(ssrAccum);
passData.ssrAccumPrev = builder.WriteTexture(ssrAccumPrev);
passData.lightingTexture = builder.CreateTransientTexture(new TextureDesc(Vector2.one, true, true)
{ colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Lighting_Texture" });
}
else
{
passData.lightingTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
{ colorFormat = GraphicsFormat.R16G16B16A16_SFloat, clearBuffer = true, clearColor = Color.clear, enableRandomWrite = true, name = "SSR_Lighting_Texture" }));
}
builder.SetRenderFunc(
(RenderSSRPassData data, RenderGraphContext context) =>
{
RenderSSR(data.parameters,
data.hdCamera,
data.blueNoise,
data.depthBuffer,
data.depthPyramid,
data.normalBuffer,
data.motionVectorsBuffer,
data.hitPointsTexture,
data.stencilBuffer,
data.clearCoatMask,
data.colorPyramid,
data.ssrAccum,
data.lightingTexture,
data.ssrAccumPrev,
data.coarseStencilBuffer,
context.cmd, context.renderContext);
});
if (usePBRAlgo)
{
result = passData.ssrAccum;
PushFullScreenDebugTexture(renderGraph, passData.ssrAccum, FullScreenDebugMode.ScreenSpaceReflectionsAccum);
PushFullScreenDebugTexture(renderGraph, passData.ssrAccumPrev, FullScreenDebugMode.ScreenSpaceReflectionsPrev);
}
else
{
result = passData.lightingTexture;
}
}
if (!hdCamera.colorPyramidHistoryIsValid)
{
hdCamera.colorPyramidHistoryIsValid = true; // For the next frame...
result = renderGraph.defaultResources.blackTextureXR;
}
}
PushFullScreenDebugTexture(renderGraph, result, transparent ? FullScreenDebugMode.TransparentScreenSpaceReflections : FullScreenDebugMode.ScreenSpaceReflections);
return result;
}
class RenderContactShadowPassData
{
public ContactShadowsParameters parameters;
public LightLoopLightData lightLoopLightData;
public TextureHandle depthTexture;
public TextureHandle contactShadowsTexture;
public ComputeBufferHandle lightList;
}
TextureHandle RenderContactShadows(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle depthTexture, in BuildGPULightListOutput lightLists, int firstMipOffsetY)
{
if (!WillRenderContactShadow())
return renderGraph.defaultResources.blackUIntTextureXR;
TextureHandle result;
using (var builder = renderGraph.AddRenderPass<RenderContactShadowPassData>("Contact Shadows", out var passData))
{
builder.EnableAsyncCompute(hdCamera.frameSettings.ContactShadowsRunAsync());
// Avoid garbage when visualizing contact shadows.
bool clearBuffer = m_CurrentDebugDisplaySettings.data.fullScreenDebugMode == FullScreenDebugMode.ContactShadows;
passData.parameters = PrepareContactShadowsParameters(hdCamera, firstMipOffsetY);
passData.lightLoopLightData = m_LightLoopLightData;
passData.lightList = builder.ReadComputeBuffer(lightLists.lightList);
passData.depthTexture = builder.ReadTexture(depthTexture);
passData.contactShadowsTexture = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, true, true)
{ colorFormat = GraphicsFormat.R32_UInt, enableRandomWrite = true, clearBuffer = clearBuffer, clearColor = Color.clear, name = "ContactShadowsBuffer" }));
result = passData.contactShadowsTexture;
builder.SetRenderFunc(
(RenderContactShadowPassData data, RenderGraphContext context) =>
{
RenderContactShadows(data.parameters, data.contactShadowsTexture, data.depthTexture, data.lightLoopLightData, data.lightList, context.cmd);
});
}
PushFullScreenDebugTexture(renderGraph, result, FullScreenDebugMode.ContactShadows);
return result;
}
class VolumeVoxelizationPassData
{
public VolumeVoxelizationParameters parameters;
public TextureHandle densityBuffer;
public ComputeBufferHandle bigTileLightListBuffer;
public ComputeBuffer visibleVolumeBoundsBuffer;
public ComputeBuffer visibleVolumeDataBuffer;
}
TextureHandle VolumeVoxelizationPass(RenderGraph renderGraph,
HDCamera hdCamera,
ComputeBuffer visibleVolumeBoundsBuffer,
ComputeBuffer visibleVolumeDataBuffer,
ComputeBufferHandle bigTileLightList)
{
if (Fog.IsVolumetricFogEnabled(hdCamera))
{
using (var builder = renderGraph.AddRenderPass<VolumeVoxelizationPassData>("Volume Voxelization", out var passData))
{
builder.EnableAsyncCompute(hdCamera.frameSettings.VolumeVoxelizationRunsAsync());
passData.parameters = PrepareVolumeVoxelizationParameters(hdCamera);
passData.visibleVolumeBoundsBuffer = visibleVolumeBoundsBuffer;
passData.visibleVolumeDataBuffer = visibleVolumeDataBuffer;
if (passData.parameters.tiledLighting)
passData.bigTileLightListBuffer = builder.ReadComputeBuffer(bigTileLightList);
float tileSize = 0;
Vector3Int viewportSize = ComputeVolumetricViewportSize(hdCamera, ref tileSize);
passData.densityBuffer = builder.WriteTexture(renderGraph.ImportTexture(m_DensityBuffer));
builder.SetRenderFunc(
(VolumeVoxelizationPassData data, RenderGraphContext ctx) =>
{
VolumeVoxelizationPass(data.parameters,
data.densityBuffer,
data.visibleVolumeBoundsBuffer,
data.visibleVolumeDataBuffer,
data.bigTileLightListBuffer,
ctx.cmd);
});
return passData.densityBuffer;
}
}
return TextureHandle.nullHandle;
}
class GenerateMaxZMaskPassData
{
public GenerateMaxZParameters parameters;
public TextureHandle depthTexture;
public TextureHandle maxZ8xBuffer;
public TextureHandle maxZBuffer;
public TextureHandle dilatedMaxZBuffer;
}
TextureHandle GenerateMaxZPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle depthTexture, HDUtils.PackedMipChainInfo depthMipInfo)
{
if (Fog.IsVolumetricFogEnabled(hdCamera))
{
if (!hdCamera.frameSettings.IsEnabled(FrameSettingsField.OpaqueObjects))
{
return renderGraph.defaultResources.blackTextureXR;
}
using (var builder = renderGraph.AddRenderPass<GenerateMaxZMaskPassData>("Generate Max Z Mask for Volumetric", out var passData))
{
passData.parameters = PrepareGenerateMaxZParameters(hdCamera, depthMipInfo);
passData.depthTexture = builder.ReadTexture(depthTexture);
passData.maxZ8xBuffer = builder.ReadTexture(renderGraph.ImportTexture(m_MaxZMask8x));
passData.maxZ8xBuffer = builder.WriteTexture(passData.maxZ8xBuffer);
passData.maxZBuffer = builder.ReadTexture(renderGraph.ImportTexture(m_MaxZMask));
passData.maxZBuffer = builder.WriteTexture(passData.maxZBuffer);
passData.dilatedMaxZBuffer = builder.ReadTexture(renderGraph.ImportTexture(m_DilatedMaxZMask));
passData.dilatedMaxZBuffer = builder.WriteTexture(passData.dilatedMaxZBuffer);
builder.SetRenderFunc(
(GenerateMaxZMaskPassData data, RenderGraphContext ctx) =>
{
GenerateMaxZ(data.parameters, data.depthTexture, data.maxZ8xBuffer, data.maxZBuffer, data.dilatedMaxZBuffer, ctx.cmd);
});
return passData.dilatedMaxZBuffer;
}
}
return TextureHandle.nullHandle;
}
class VolumetricLightingPassData
{
public VolumetricLightingParameters parameters;
public TextureHandle densityBuffer;
public TextureHandle depthTexture;
public TextureHandle lightingBuffer;
public TextureHandle maxZBuffer;
public TextureHandle historyBuffer;
public TextureHandle feedbackBuffer;
public ComputeBufferHandle bigTileLightListBuffer;
}
TextureHandle VolumetricLightingPass(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle depthTexture, TextureHandle densityBuffer, TextureHandle maxZBuffer, ComputeBufferHandle bigTileLightListBuffer, ShadowResult shadowResult)
{
if (Fog.IsVolumetricFogEnabled(hdCamera))
{
// Evaluate the parameters
var parameters = PrepareVolumetricLightingParameters(hdCamera);
using (var builder = renderGraph.AddRenderPass<VolumetricLightingPassData>("Volumetric Lighting", out var passData))
{
// TODO RENDERGRAPH
//builder.EnableAsyncCompute(hdCamera.frameSettings.VolumetricLightingRunsAsync());
passData.parameters = parameters;
if (passData.parameters.tiledLighting)
passData.bigTileLightListBuffer = builder.ReadComputeBuffer(bigTileLightListBuffer);
passData.densityBuffer = builder.ReadTexture(densityBuffer);
passData.depthTexture = builder.ReadTexture(depthTexture);
passData.maxZBuffer = builder.ReadTexture(maxZBuffer);
float tileSize = 0;
Vector3Int viewportSize = ComputeVolumetricViewportSize(hdCamera, ref tileSize);
// TODO RENDERGRAPH: Auto-scale of 3D RTs is not supported yet so we need to find a better solution for this. Or keep it as is?
passData.lightingBuffer = builder.WriteTexture(renderGraph.ImportTexture(m_LightingBuffer));
if (passData.parameters.enableReprojection)
{
int frameIndex = (int)VolumetricFrameIndex(hdCamera);
var currIdx = (frameIndex + 0) & 1;
var prevIdx = (frameIndex + 1) & 1;
passData.feedbackBuffer = builder.WriteTexture(renderGraph.ImportTexture(hdCamera.volumetricHistoryBuffers[currIdx]));
passData.historyBuffer = builder.ReadTexture(renderGraph.ImportTexture(hdCamera.volumetricHistoryBuffers[prevIdx]));
}
HDShadowManager.ReadShadowResult(shadowResult, builder);
builder.SetRenderFunc(
(VolumetricLightingPassData data, RenderGraphContext ctx) =>
{
VolumetricLightingPass(data.parameters,
data.depthTexture,
data.densityBuffer,
data.lightingBuffer,
data.maxZBuffer,
data.parameters.enableReprojection ? data.historyBuffer : (RTHandle)null,
data.parameters.enableReprojection ? data.feedbackBuffer : (RTHandle)null,
data.bigTileLightListBuffer,
ctx.cmd);
if (data.parameters.filterVolume)
FilterVolumetricLighting(data.parameters, data.lightingBuffer, ctx.cmd);
});
if (parameters.enableReprojection && hdCamera.volumetricValidFrames > 1)
hdCamera.volumetricHistoryIsValid = true; // For the next frame..
else
hdCamera.volumetricValidFrames++;
return passData.lightingBuffer;
}
}
return renderGraph.ImportTexture(HDUtils.clearTexture3DRTH);
}
}
}