Adaug proiectul Unity

This commit is contained in:
2026-11-01 23:39:55 +02:00
parent cb14d9d37d
commit 863eac8f2c
23463 changed files with 5412601 additions and 0 deletions
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df6b79ad3423a5745916fceb76fdefbf
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,30 @@
#if !UNITY_WEBGL_RENDERER_ONLY
using Unity.Collections;
using Unity.Burst;
namespace UnityEngine.Rendering
{
[BurstCompile]
internal static class InstanceCullerBurst
{
[BurstCompile(DisableSafetyChecks = true, OptimizeFor = OptimizeFor.Performance)]
public static unsafe void SetupCullingJobInput(float lodBias,
float meshLodThreshold,
BatchCullingContext* context,
ReceiverPlanes* receiverPlanes,
ReceiverSphereCuller* receiverSphereCuller,
FrustumPlaneCuller* frustumPlaneCuller,
float* screenRelativeMetric,
float* meshLodConstant)
{
*receiverPlanes = ReceiverPlanes.Create(*context, Allocator.TempJob);
*receiverSphereCuller = ReceiverSphereCuller.Create(*context, Allocator.TempJob);
*frustumPlaneCuller = FrustumPlaneCuller.Create(*context, receiverPlanes->planes.AsArray(), *receiverSphereCuller, Allocator.TempJob);
*screenRelativeMetric = LODRenderingUtils.CalculateScreenRelativeMetricNoBias(context->lodParameters);
*meshLodConstant = LODRenderingUtils.CalculateMeshLodConstant(context->lodParameters, *screenRelativeMetric, meshLodThreshold);
*screenRelativeMetric /= lodBias;
}
}
}
#endif // !UNITY_WEBGL_RENDERER_ONLY
@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 86dce443230a0694d8fedef47e43b707
@@ -0,0 +1,827 @@
#if !UNITY_WEBGL_RENDERER_ONLY
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using UnityEngine.Assertions;
using Unity.Burst;
using Unity.Burst.CompilerServices;
using Unity.Mathematics;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Jobs;
using Unity.Jobs.LowLevel.Unsafe;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering
{
internal struct OccluderDerivedData
{
/// <summary></summary>
public Matrix4x4 viewProjMatrix; // from view-centered world space
/// <summary></summary>
public Vector4 viewOriginWorldSpace;
/// <summary></summary>
public Vector4 radialDirWorldSpace;
/// <summary></summary>
public Vector4 facingDirWorldSpace;
public static OccluderDerivedData FromParameters(in OccluderSubviewUpdate occluderSubviewUpdate)
{
var origin = occluderSubviewUpdate.viewOffsetWorldSpace + (Vector3)occluderSubviewUpdate.invViewMatrix.GetColumn(3); // view origin in world space
var xViewVec = (Vector3)occluderSubviewUpdate.invViewMatrix.GetColumn(0); // positive x axis in world space
var yViewVec = (Vector3)occluderSubviewUpdate.invViewMatrix.GetColumn(1); // positive y axis in world space
var towardsVec = (Vector3)occluderSubviewUpdate.invViewMatrix.GetColumn(2); // positive z axis in world space
var viewMatrixNoTranslation = occluderSubviewUpdate.viewMatrix;
viewMatrixNoTranslation.SetColumn(3, new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
return new OccluderDerivedData
{
viewOriginWorldSpace = origin,
facingDirWorldSpace = towardsVec.normalized,
radialDirWorldSpace = (xViewVec + yViewVec).normalized,
viewProjMatrix = occluderSubviewUpdate.gpuProjMatrix * viewMatrixNoTranslation,
};
}
}
internal struct OccluderHandles
{
public TextureHandle occluderDepthPyramid;
public BufferHandle occlusionDebugOverlay;
public bool IsValid()
{
return occluderDepthPyramid.IsValid();
}
public void UseForOcclusionTest(IBaseRenderGraphBuilder builder)
{
builder.UseTexture(occluderDepthPyramid, AccessFlags.Read);
if (occlusionDebugOverlay.IsValid())
builder.UseBuffer(occlusionDebugOverlay, AccessFlags.ReadWrite);
}
public void UseForOccluderUpdate(IBaseRenderGraphBuilder builder)
{
builder.UseTexture(occluderDepthPyramid, AccessFlags.ReadWrite);
if (occlusionDebugOverlay.IsValid())
builder.UseBuffer(occlusionDebugOverlay, AccessFlags.ReadWrite);
}
}
[GenerateHLSL(needAccessors = false)]
internal enum InstanceOcclusionTestDebugCounter
{
InstancesOccluded,
InstancesNotOccluded,
PrimitivesOccluded,
PrimitivesNotOccluded,
Count,
}
[GenerateHLSL(needAccessors = false)]
internal struct IndirectInstanceInfo
{
public int drawOffsetAndSplitMask; // [31:8]=draw_offset, [7:0]=split_mask
public int instanceIndexAndCrossFade; // DOTS instance index
}
[GenerateHLSL(needAccessors = false)]
internal struct IndirectDrawInfo
{
public uint indexCount;
public uint firstIndex;
public uint baseVertex;
public uint firstInstanceGlobalIndex;
public uint maxInstanceCountAndTopology; // [31:3]=max_instance_count, [2:0]=topology
}
internal struct IndirectBufferAllocInfo
{
public int drawAllocIndex;
public int drawCount;
public int instanceAllocIndex;
public int instanceCount;
public bool IsEmpty()
{
return drawCount == 0;
}
public bool IsWithinLimits(in IndirectBufferLimits limits)
{
return drawAllocIndex + drawCount <= limits.maxDrawCount
&& instanceAllocIndex + instanceCount <= limits.maxInstanceCount;
}
public int GetExtraDrawInfoSlotIndex()
{
return drawAllocIndex + drawCount;
}
}
internal struct IndirectBufferContext
{
public JobHandle cullingJobHandle;
public enum BufferState
{
Pending, // Not synced with culling output yet
Zeroed, // All draws have zero instances
NoOcclusionTest, // Copy the results of CPU frustum/LOD culling
AllInstancesOcclusionTested, // Occlusion test the results of CPU frustum/LOD culling
OccludedInstancesReTested, // Re-test previously occluded instances (against updated occluders)
}
public BufferState bufferState;
public int occluderVersion;
public int subviewMask;
public IndirectBufferContext(JobHandle cullingJobHandle)
{
this.cullingJobHandle = cullingJobHandle;
this.bufferState = BufferState.Pending;
this.occluderVersion = 0;
this.subviewMask = 0;
}
public bool Matches(BufferState bufferState, int occluderVersion, int subviewMask)
{
return this.bufferState == bufferState
&& this.occluderVersion == occluderVersion
&& this.subviewMask == subviewMask;
}
}
internal struct OccluderMipBounds
{
public Vector2Int offset;
public Vector2Int size;
}
internal struct OccluderContext : IDisposable
{
private static class ShaderIDs
{
public static readonly int _SrcDepth = Shader.PropertyToID("_SrcDepth");
public static readonly int _DstDepth = Shader.PropertyToID("_DstDepth");
public static readonly int OccluderDepthPyramidConstants = Shader.PropertyToID("OccluderDepthPyramidConstants");
}
public const int k_FirstDepthMipIndex = 3; // 8x8 tiles
public const int k_MaxOccluderMips = (int)OcclusionCullingCommonConfig.MaxOccluderMips;
public const int k_MaxSilhouettePlanes = (int)OcclusionCullingCommonConfig.MaxOccluderSilhouettePlanes;
public const int k_MaxSubviewsPerView = (int)OcclusionCullingCommonConfig.MaxSubviewsPerView;
public int version;
public Vector2Int depthBufferSize;
public NativeArray<OccluderDerivedData> subviewData;
public int subviewCount { get { return subviewData.Length; } }
public int subviewValidMask;
public bool IsSubviewValid(int subviewIndex)
{
return subviewIndex < subviewCount && (subviewValidMask & (1 << subviewIndex)) != 0;
}
public NativeArray<OccluderMipBounds> occluderMipBounds;
public Vector2Int occluderMipLayoutSize; // total size of 2D layout specified by occluderMipBounds
public Vector2Int occluderDepthPyramidSize; // at least the size of N mip layouts tiled vertically (one per subview)
public RTHandle occluderDepthPyramid;
public int occlusionDebugOverlaySize;
public GraphicsBuffer occlusionDebugOverlay;
public bool debugNeedsClear;
public ComputeBuffer constantBuffer;
public NativeArray<OccluderDepthPyramidConstants> constantBufferData;
public Vector2 depthBufferSizeInOccluderPixels {
get
{
int occluderPixelSize = 1 << k_FirstDepthMipIndex;
return new Vector2(
(float)depthBufferSize.x / (float)occluderPixelSize,
(float)depthBufferSize.y / (float)occluderPixelSize);
}
}
public void Dispose()
{
if (subviewData.IsCreated)
subviewData.Dispose();
if (occluderMipBounds.IsCreated)
occluderMipBounds.Dispose();
if (occluderDepthPyramid != null)
{
occluderDepthPyramid.Release();
occluderDepthPyramid = null;
}
if (occlusionDebugOverlay != null)
{
occlusionDebugOverlay.Release();
occlusionDebugOverlay = null;
}
if (constantBuffer != null)
{
constantBuffer.Release();
constantBuffer = null;
}
if (constantBufferData.IsCreated)
constantBufferData.Dispose();
}
private void UpdateMipBounds()
{
int occluderPixelSize = 1 << k_FirstDepthMipIndex;
Vector2Int topMipSize = (depthBufferSize + (occluderPixelSize - 1) * Vector2Int.one) / occluderPixelSize;
Vector2Int totalSize = Vector2Int.zero;
Vector2Int mipOffset = Vector2Int.zero;
Vector2Int mipSize = topMipSize;
if (!occluderMipBounds.IsCreated)
occluderMipBounds = new NativeArray<OccluderMipBounds>(k_MaxOccluderMips, Allocator.Persistent);
for (int mipIndex = 0; mipIndex < k_MaxOccluderMips; ++mipIndex)
{
occluderMipBounds[mipIndex] = new OccluderMipBounds { offset = mipOffset, size = mipSize };
totalSize.x = Mathf.Max(totalSize.x, mipOffset.x + mipSize.x);
totalSize.y = Mathf.Max(totalSize.y, mipOffset.y + mipSize.y);
if (mipIndex == 0)
{
mipOffset.x = 0;
mipOffset.y += mipSize.y;
}
else
{
mipOffset.x += mipSize.x;
}
mipSize.x = (mipSize.x + 1) / 2;
mipSize.y = (mipSize.y + 1) / 2;
}
occluderMipLayoutSize = totalSize;
}
private void AllocateTexturesIfNecessary(bool debugOverlayEnabled)
{
Vector2Int minDepthPyramidSize = new Vector2Int(occluderMipLayoutSize.x, occluderMipLayoutSize.y * subviewCount);
if (occluderDepthPyramidSize.x < minDepthPyramidSize.x || occluderDepthPyramidSize.y < minDepthPyramidSize.y)
{
if (occluderDepthPyramid != null)
occluderDepthPyramid.Release();
occluderDepthPyramidSize = minDepthPyramidSize;
occluderDepthPyramid = RTHandles.Alloc(
occluderDepthPyramidSize.x, occluderDepthPyramidSize.y,
dimension: TextureDimension.Tex2D,
format: GraphicsFormat.R32_SFloat,
filterMode: FilterMode.Point,
wrapMode: TextureWrapMode.Clamp,
enableRandomWrite: true,
name: "Occluder Depths");
}
int newDebugOverlaySize = debugOverlayEnabled ? (minDepthPyramidSize.x * minDepthPyramidSize.y) : 0;
if (occlusionDebugOverlaySize < newDebugOverlaySize)
{
if (occlusionDebugOverlay != null)
occlusionDebugOverlay.Release();
occlusionDebugOverlaySize = newDebugOverlaySize;
debugNeedsClear = true;
// We use buffer instead of texture, because some platforms don't support atmoic operations for Texture2D<uint>
occlusionDebugOverlay = new GraphicsBuffer(GraphicsBuffer.Target.Structured, GraphicsBuffer.UsageFlags.None,
occlusionDebugOverlaySize + (int)OcclusionCullingCommonConfig.DebugPyramidOffset, sizeof(uint));
}
if (newDebugOverlaySize == 0)
{
if (occlusionDebugOverlay != null)
{
occlusionDebugOverlay.Release();
occlusionDebugOverlay = null;
}
occlusionDebugOverlaySize = newDebugOverlaySize;
}
if (constantBuffer == null)
constantBuffer = new ComputeBuffer(1, UnsafeUtility.SizeOf<OccluderDepthPyramidConstants>(), ComputeBufferType.Constant);
if (!constantBufferData.IsCreated)
constantBufferData = new NativeArray<OccluderDepthPyramidConstants>(1, Allocator.Persistent);
}
internal static void SetKeyword(ComputeCommandBuffer cmd, ComputeShader cs, in LocalKeyword keyword, bool value)
{
if (value)
cmd.EnableKeyword(cs, keyword);
else
cmd.DisableKeyword(cs, keyword);
}
private OccluderDepthPyramidConstants SetupFarDepthPyramidConstants(ReadOnlySpan<OccluderSubviewUpdate> occluderSubviewUpdates, NativeArray<Plane> silhouettePlanes)
{
OccluderDepthPyramidConstants cb = new OccluderDepthPyramidConstants();
// write globals
cb._OccluderMipLayoutSizeX = (uint)occluderMipLayoutSize.x;
cb._OccluderMipLayoutSizeY = (uint)occluderMipLayoutSize.y;
// write per-subview data
int updateCount = occluderSubviewUpdates.Length;
for (int updateIndex = 0; updateIndex < updateCount; ++updateIndex)
{
ref readonly OccluderSubviewUpdate update = ref occluderSubviewUpdates[updateIndex];
int subviewIndex = update.subviewIndex;
subviewData[subviewIndex] = OccluderDerivedData.FromParameters(update);
subviewValidMask |= 1 << update.subviewIndex;
Matrix4x4 viewProjMatrix
= update.gpuProjMatrix
* update.viewMatrix
* Matrix4x4.Translate(-update.viewOffsetWorldSpace);
Matrix4x4 invViewProjMatrix = viewProjMatrix.inverse;
unsafe
{
for (int j = 0; j < 16; ++j)
cb._InvViewProjMatrix[16 * updateIndex + j] = invViewProjMatrix[j];
cb._SrcOffset[4 * updateIndex + 0] = (uint)update.depthOffset.x;
cb._SrcOffset[4 * updateIndex + 1] = (uint)update.depthOffset.y;
cb._SrcOffset[4 * updateIndex + 2] = 0;
cb._SrcOffset[4 * updateIndex + 3] = 0;
}
cb._SrcSliceIndices |= (((uint)update.depthSliceIndex & 0xf) << (4 * updateIndex));
cb._DstSubviewIndices |= ((uint)subviewIndex << (4 * updateIndex));
}
// TODO: transform these planes from world space into NDC space planes
for (int i = 0; i < k_MaxSilhouettePlanes; ++i)
{
Plane plane = new Plane(Vector3.zero, 0.0f);
if (i < silhouettePlanes.Length)
plane = silhouettePlanes[i];
unsafe
{
cb._SilhouettePlanes[4 * i + 0] = plane.normal.x;
cb._SilhouettePlanes[4 * i + 1] = plane.normal.y;
cb._SilhouettePlanes[4 * i + 2] = plane.normal.z;
cb._SilhouettePlanes[4 * i + 3] = plane.distance;
}
}
cb._SilhouettePlaneCount = (uint)silhouettePlanes.Length;
return cb;
}
public void CreateFarDepthPyramid(ComputeCommandBuffer cmd, in OccluderParameters occluderParams, ReadOnlySpan<OccluderSubviewUpdate> occluderSubviewUpdates, in OccluderHandles occluderHandles, NativeArray<Plane> silhouettePlanes, ComputeShader occluderDepthPyramidCS, int occluderDepthDownscaleKernel)
{
OccluderDepthPyramidConstants cb = SetupFarDepthPyramidConstants(occluderSubviewUpdates, silhouettePlanes);
var cs = occluderDepthPyramidCS;
int kernel = occluderDepthDownscaleKernel;
var srcKeyword = new LocalKeyword(cs, "USE_SRC");
var srcIsArrayKeyword = new LocalKeyword(cs, "SRC_IS_ARRAY");
var srcIsMsaaKeyword = new LocalKeyword(cs, "SRC_IS_MSAA");
bool srcIsArray = occluderParams.depthIsArray;
RTHandle depthTexture = (RTHandle)occluderParams.depthTexture;
bool srcIsMsaa = depthTexture?.isMSAAEnabled ?? false;
int mipCount = k_FirstDepthMipIndex + k_MaxOccluderMips;
for (int mipIndexBase = 0; mipIndexBase < mipCount - 1; mipIndexBase += 4)
{
cmd.SetComputeTextureParam(cs, kernel, ShaderIDs._DstDepth, occluderHandles.occluderDepthPyramid);
bool useSrc = (mipIndexBase == 0);
SetKeyword(cmd, cs, srcKeyword, useSrc);
SetKeyword(cmd, cs, srcIsArrayKeyword, useSrc && srcIsArray);
SetKeyword(cmd, cs, srcIsMsaaKeyword, useSrc && srcIsMsaa);
if (useSrc)
cmd.SetComputeTextureParam(cs, kernel, ShaderIDs._SrcDepth, occluderParams.depthTexture);
cb._MipCount = (uint)Math.Min(mipCount - 1 - mipIndexBase, 4);
Vector2Int srcSize = Vector2Int.zero;
for (int i = 0; i < 5; ++i)
{
Vector2Int offset = Vector2Int.zero;
Vector2Int size = Vector2Int.zero;
int mipIndex = mipIndexBase + i;
if (mipIndex == 0)
{
size = occluderParams.depthSize;
}
else
{
int occMipIndex = mipIndex - k_FirstDepthMipIndex;
if (0 <= occMipIndex && occMipIndex < k_MaxOccluderMips)
{
offset = occluderMipBounds[occMipIndex].offset;
size = occluderMipBounds[occMipIndex].size;
}
}
if (i == 0)
srcSize = size;
unsafe
{
cb._MipOffsetAndSize[4 * i + 0] = (uint)offset.x;
cb._MipOffsetAndSize[4 * i + 1] = (uint)offset.y;
cb._MipOffsetAndSize[4 * i + 2] = (uint)size.x;
cb._MipOffsetAndSize[4 * i + 3] = (uint)size.y;
}
}
constantBufferData[0] = cb;
cmd.SetBufferData(constantBuffer, constantBufferData);
cmd.SetComputeConstantBufferParam(cs, ShaderIDs.OccluderDepthPyramidConstants, constantBuffer, 0, constantBuffer.stride);
cmd.DispatchCompute(cs, kernel, (srcSize.x + 15) / 16, (srcSize.y + 15) / 16, occluderSubviewUpdates.Length);
}
}
public OccluderHandles Import(RenderGraph renderGraph)
{
RenderTargetInfo rtInfo = new RenderTargetInfo
{
width = occluderDepthPyramidSize.x,
height = occluderDepthPyramidSize.y,
volumeDepth = 1,
msaaSamples = 1,
format = GraphicsFormat.R32_SFloat,
bindMS = false,
};
OccluderHandles occluderHandles = new OccluderHandles()
{
occluderDepthPyramid = renderGraph.ImportTexture(occluderDepthPyramid, rtInfo)
};
if (occlusionDebugOverlay != null)
occluderHandles.occlusionDebugOverlay = renderGraph.ImportBuffer(occlusionDebugOverlay);
return occluderHandles;
}
public void PrepareOccluders(in OccluderParameters occluderParams)
{
if (subviewCount != occluderParams.subviewCount)
{
if (subviewData.IsCreated)
subviewData.Dispose();
subviewData = new NativeArray<OccluderDerivedData>(occluderParams.subviewCount, Allocator.Persistent);
subviewValidMask = 0;
}
depthBufferSize = occluderParams.depthSize;
// enable debug counters for cameras when the overlay is enabled
bool debugOverlayEnabled = GPUResidentDrawer.debugDisplaySettings?.occlusionTestOverlayEnabled ?? false;
UpdateMipBounds();
AllocateTexturesIfNecessary(debugOverlayEnabled);
}
internal OcclusionCullingDebugOutput GetDebugOutput()
{
var debugOutput = new OcclusionCullingDebugOutput
{
occluderDepthPyramid = occluderDepthPyramid,
occlusionDebugOverlay = occlusionDebugOverlay,
};
debugOutput.cb._DepthSizeInOccluderPixels = depthBufferSizeInOccluderPixels;
debugOutput.cb._OccluderMipLayoutSizeX = (uint)occluderMipLayoutSize.x;
debugOutput.cb._OccluderMipLayoutSizeY = (uint)occluderMipLayoutSize.y;
for (int i = 0; i < occluderMipBounds.Length; ++i)
{
var mipBounds = occluderMipBounds[i];
unsafe
{
debugOutput.cb._OccluderMipBounds[4 * i + 0] = (uint)mipBounds.offset.x;
debugOutput.cb._OccluderMipBounds[4 * i + 1] = (uint)mipBounds.offset.y;
debugOutput.cb._OccluderMipBounds[4 * i + 2] = (uint)mipBounds.size.x;
debugOutput.cb._OccluderMipBounds[4 * i + 3] = (uint)mipBounds.size.y;
}
}
return debugOutput;
}
}
internal enum IndirectAllocator
{
NextInstanceIndex,
NextDrawIndex,
Count // keep last
}
internal struct IndirectBufferLimits
{
public int maxInstanceCount;
public int maxDrawCount;
}
internal struct InstanceOcclusionTestSubviewSettings
{
public int testCount;
public int occluderSubviewIndices;
public int occluderSubviewMask;
public int cullingSplitIndices;
public int cullingSplitMask;
public static InstanceOcclusionTestSubviewSettings FromSpan(ReadOnlySpan<SubviewOcclusionTest> subviewOcclusionTests)
{
InstanceOcclusionTestSubviewSettings settings = new InstanceOcclusionTestSubviewSettings();
for (int testIndex = 0; testIndex < subviewOcclusionTests.Length; ++testIndex)
{
SubviewOcclusionTest subviewTest = subviewOcclusionTests[testIndex];
settings.occluderSubviewIndices |= subviewTest.occluderSubviewIndex << (4 * testIndex);
settings.occluderSubviewMask |= 1 << subviewTest.occluderSubviewIndex;
settings.cullingSplitIndices |= subviewTest.cullingSplitIndex << (4 * testIndex);
settings.cullingSplitMask |= 1 << subviewTest.cullingSplitIndex;
}
settings.testCount = subviewOcclusionTests.Length;
return settings;
}
}
internal struct IndirectBufferContextHandles
{
public BufferHandle instanceBuffer;
public BufferHandle instanceInfoBuffer;
public BufferHandle dispatchArgsBuffer;
public BufferHandle drawArgsBuffer;
public BufferHandle drawInfoBuffer;
public void UseForOcclusionTest(IBaseRenderGraphBuilder builder)
{
instanceBuffer = builder.UseBuffer(instanceBuffer, AccessFlags.ReadWrite);
instanceInfoBuffer = builder.UseBuffer(instanceInfoBuffer, AccessFlags.Read);
dispatchArgsBuffer = builder.UseBuffer(dispatchArgsBuffer, AccessFlags.ReadWrite);
drawArgsBuffer = builder.UseBuffer(drawArgsBuffer, AccessFlags.ReadWrite);
drawInfoBuffer = builder.UseBuffer(drawInfoBuffer, AccessFlags.Read);
}
}
internal struct IndirectBufferContextStorage : IDisposable
{
private const int kAllocatorCount = (int)IndirectAllocator.Count;
internal const int kInstanceInfoGpuOffsetMultiplier = 2; // GPU side allocates storage for extra copy of instance list
private IndirectBufferLimits m_BufferLimits;
private GraphicsBuffer m_InstanceBuffer;
private GraphicsBuffer m_InstanceInfoBuffer;
private NativeArray<IndirectInstanceInfo> m_InstanceInfoStaging;
private GraphicsBuffer m_DispatchArgsBuffer;
private GraphicsBuffer m_DrawArgsBuffer;
private GraphicsBuffer m_DrawInfoBuffer;
private NativeArray<IndirectDrawInfo> m_DrawInfoStaging;
private int m_ContextAllocCounter;
private NativeHashMap<EntityId, int> m_ContextIndexFromViewID;
private NativeList<IndirectBufferContext> m_Contexts;
private NativeArray<IndirectBufferAllocInfo> m_ContextAllocInfo;
private NativeArray<int> m_AllocationCounters;
public GraphicsBuffer instanceBuffer { get { return m_InstanceBuffer; } }
public GraphicsBuffer instanceInfoBuffer { get { return m_InstanceInfoBuffer; } }
public GraphicsBuffer dispatchArgsBuffer { get { return m_DispatchArgsBuffer; } }
public GraphicsBuffer drawArgsBuffer { get { return m_DrawArgsBuffer; } }
public GraphicsBuffer drawInfoBuffer { get { return m_DrawInfoBuffer; } }
public GraphicsBufferHandle visibleInstanceBufferHandle { get { return m_InstanceBuffer.bufferHandle; } }
public GraphicsBufferHandle indirectDrawArgsBufferHandle { get { return m_DrawArgsBuffer.bufferHandle; } }
public IndirectBufferContextHandles ImportBuffers(RenderGraph renderGraph)
{
return new IndirectBufferContextHandles()
{
instanceBuffer = renderGraph.ImportBuffer(m_InstanceBuffer),
instanceInfoBuffer = renderGraph.ImportBuffer(m_InstanceInfoBuffer),
dispatchArgsBuffer = renderGraph.ImportBuffer(m_DispatchArgsBuffer),
drawArgsBuffer = renderGraph.ImportBuffer(m_DrawArgsBuffer),
drawInfoBuffer = renderGraph.ImportBuffer(m_DrawInfoBuffer),
};
}
public NativeArray<IndirectInstanceInfo> instanceInfoGlobalArray { get { return m_InstanceInfoStaging; } }
public NativeArray<IndirectDrawInfo> drawInfoGlobalArray { get { return m_DrawInfoStaging; } }
public NativeArray<int> allocationCounters { get { return m_AllocationCounters; } }
public void Init()
{
int initialDrawCount = 256;
int initialInstanceCount = 64 * initialDrawCount;
int initialContextCount = 8;
AllocateInstanceBuffers(initialInstanceCount);
AllocateDrawBuffers(initialDrawCount);
m_ContextIndexFromViewID = new NativeHashMap<EntityId, int>(initialContextCount, Allocator.Persistent);
m_Contexts = new NativeList<IndirectBufferContext>(initialContextCount, Allocator.Persistent);
m_ContextAllocInfo = new NativeArray<IndirectBufferAllocInfo>(initialContextCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
m_AllocationCounters = new NativeArray<int>(kAllocatorCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
ResetAllocators();
}
void AllocateInstanceBuffers(int maxInstanceCount)
{
m_InstanceBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Raw, maxInstanceCount, sizeof(int));
m_InstanceInfoBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, kInstanceInfoGpuOffsetMultiplier * maxInstanceCount, System.Runtime.InteropServices.Marshal.SizeOf<IndirectInstanceInfo>());
m_InstanceInfoStaging = new NativeArray<IndirectInstanceInfo>(maxInstanceCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
m_BufferLimits.maxInstanceCount = maxInstanceCount;
}
void FreeInstanceBuffers()
{
m_InstanceBuffer.Release();
m_InstanceInfoBuffer.Release();
m_InstanceInfoStaging.Dispose();
m_BufferLimits.maxInstanceCount = 0;
}
void AllocateDrawBuffers(int maxDrawCount)
{
// Compute dispatch arguments are number of thread groups in X,Y and Z dimensions, hence 3 integers for the size.
m_DispatchArgsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured | GraphicsBuffer.Target.IndirectArguments, 3, sizeof(int));
m_DrawArgsBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured | GraphicsBuffer.Target.IndirectArguments, maxDrawCount * (GraphicsBuffer.IndirectDrawIndexedArgs.size / sizeof(int)), sizeof(int));
m_DrawInfoBuffer = new GraphicsBuffer(GraphicsBuffer.Target.Structured, maxDrawCount, System.Runtime.InteropServices.Marshal.SizeOf<IndirectDrawInfo>());
m_DrawInfoStaging = new NativeArray<IndirectDrawInfo>(maxDrawCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
m_BufferLimits.maxDrawCount = maxDrawCount;
}
void FreeDrawBuffers()
{
m_DispatchArgsBuffer.Release();
m_DrawArgsBuffer.Release();
m_DrawInfoBuffer.Release();
m_DrawInfoStaging.Dispose();
m_BufferLimits.maxDrawCount = 0;
}
public void Dispose()
{
SyncContexts();
FreeInstanceBuffers();
FreeDrawBuffers();
m_ContextIndexFromViewID.Dispose();
m_Contexts.Dispose();
m_ContextAllocInfo.Dispose();
m_AllocationCounters.Dispose();
}
private void SyncContexts()
{
for (int contextIndex = 0; contextIndex < m_Contexts.Length; ++contextIndex)
m_Contexts[contextIndex].cullingJobHandle.Complete();
}
private void ResetAllocators()
{
m_ContextAllocCounter = 0;
m_ContextIndexFromViewID.Clear();
m_Contexts.Clear();
m_AllocationCounters.FillArray(0);
}
private void GrowBuffers()
{
if (m_ContextAllocCounter > m_ContextAllocInfo.Length)
{
// allocate 20% more than the high water mark
int newContextCount = (m_ContextAllocCounter * 6) / 5;
m_Contexts.Clear();
m_Contexts.SetCapacity(newContextCount);
m_ContextAllocInfo.Dispose();
m_ContextAllocInfo = new NativeArray<IndirectBufferAllocInfo>(newContextCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
//Debug.Log("Raised indirect context count to " + newContextCount);
}
int instanceAllocCounter = m_AllocationCounters[(int)IndirectAllocator.NextInstanceIndex];
if (instanceAllocCounter > m_BufferLimits.maxInstanceCount)
{
// allocate 20% more than the high water mark
int newInstanceCount = (instanceAllocCounter * 6) / 5;
FreeInstanceBuffers();
AllocateInstanceBuffers(newInstanceCount);
//Debug.Log("Raised indirect instance count to " + newInstanceCount);
}
int drawAllocCounter = m_AllocationCounters[(int)IndirectAllocator.NextDrawIndex];
if (drawAllocCounter > m_BufferLimits.maxDrawCount)
{
// allocate 20% more than the high water mark
int newDrawCount = (drawAllocCounter * 6) / 5;
FreeDrawBuffers();
AllocateDrawBuffers(newDrawCount);
//Debug.Log("Raised indirect draw count to " + newDrawCount);
}
}
public void ClearContextsAndGrowBuffers()
{
SyncContexts();
GrowBuffers();
ResetAllocators();
}
public int TryAllocateContext(EntityId viewID)
{
// Disallow using the same viewID multiple times for a frame, since it is used as a UID to update indirect args
// This will prevent multiple context being created for example if a custom pass is being used
if (m_ContextIndexFromViewID.ContainsKey(viewID))
return -1;
int contextIndex = -1;
m_ContextAllocCounter += 1;
if (m_Contexts.Length < m_ContextAllocInfo.Length)
{
contextIndex = m_Contexts.Length;
m_Contexts.Add(new IndirectBufferContext());
m_ContextIndexFromViewID.Add(viewID, contextIndex);
}
return contextIndex;
}
public int TryGetContextIndex(EntityId viewID)
{
if (!m_ContextIndexFromViewID.TryGetValue(viewID, out var contextIndex))
contextIndex = -1;
return contextIndex;
}
public NativeArray<IndirectBufferAllocInfo> GetAllocInfoSubArray(int contextIndex)
{
int safeIndex = Mathf.Max(contextIndex, 0);
return m_ContextAllocInfo.GetSubArray(safeIndex, 1);
}
public IndirectBufferAllocInfo GetAllocInfo(int contextIndex)
{
IndirectBufferAllocInfo allocInfo = new IndirectBufferAllocInfo();
if (0 <= contextIndex && contextIndex < m_Contexts.Length)
allocInfo = m_ContextAllocInfo[contextIndex];
return allocInfo;
}
public void CopyFromStaging(CommandBuffer cmd, in IndirectBufferAllocInfo allocInfo)
{
if (!allocInfo.IsEmpty())
{
cmd.SetBufferData(
m_DrawInfoBuffer,
m_DrawInfoStaging,
allocInfo.drawAllocIndex,
allocInfo.drawAllocIndex,
allocInfo.drawCount);
cmd.SetBufferData(
m_InstanceInfoBuffer,
m_InstanceInfoStaging,
allocInfo.instanceAllocIndex,
kInstanceInfoGpuOffsetMultiplier * allocInfo.instanceAllocIndex,
allocInfo.instanceCount);
}
}
public IndirectBufferLimits GetLimits(int contextIndex)
{
IndirectBufferLimits limits = new IndirectBufferLimits();
if (contextIndex >= 0)
limits = m_BufferLimits;
return limits;
}
public IndirectBufferContext GetBufferContext(int contextIndex)
{
IndirectBufferContext ctx = new IndirectBufferContext();
if (0 <= contextIndex && contextIndex < m_Contexts.Length)
ctx = m_Contexts[contextIndex];
return ctx;
}
public void SetBufferContext(int contextIndex, IndirectBufferContext ctx)
{
if (0 <= contextIndex && contextIndex < m_Contexts.Length)
m_Contexts[contextIndex] = ctx;
}
}
}
#endif // !UNITY_WEBGL_RENDERER_ONLY
@@ -0,0 +1,36 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef INSTANCEOCCLUSIONCULLER_CS_HLSL
#define INSTANCEOCCLUSIONCULLER_CS_HLSL
//
// UnityEngine.Rendering.InstanceOcclusionTestDebugCounter: static fields
//
#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_INSTANCES_OCCLUDED (0)
#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_INSTANCES_NOT_OCCLUDED (1)
#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_PRIMITIVES_OCCLUDED (2)
#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_PRIMITIVES_NOT_OCCLUDED (3)
#define INSTANCEOCCLUSIONTESTDEBUGCOUNTER_COUNT (4)
// Generated from UnityEngine.Rendering.IndirectDrawInfo
// PackingRules = Exact
struct IndirectDrawInfo
{
uint indexCount;
uint firstIndex;
uint baseVertex;
uint firstInstanceGlobalIndex;
uint maxInstanceCountAndTopology;
};
// Generated from UnityEngine.Rendering.IndirectInstanceInfo
// PackingRules = Exact
struct IndirectInstanceInfo
{
int drawOffsetAndSplitMask;
int instanceIndexAndCrossFade;
};
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a71fe447aa3034341b4a16245852e2f5
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: acfffa7be0fa59d409bb1d0a89b9b13b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,20 @@
#if !UNITY_WEBGL_RENDERER_ONLY
using System;
namespace UnityEngine.Rendering
{
[GenerateHLSL(needAccessors = false, generateCBuffer = true)]
internal unsafe struct InstanceOcclusionCullerShaderVariables
{
public uint _DrawInfoAllocIndex;
public uint _DrawInfoCount;
public uint _InstanceInfoAllocIndex;
public uint _InstanceInfoCount;
public int _BoundingSphereInstanceDataAddress;
public int _DebugCounterIndex;
public int _InstanceMultiplierShift;
public int _InstanceOcclusionCullerPad0;
}
}
#endif // !UNITY_WEBGL_RENDERER_ONLY
@@ -0,0 +1,21 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef INSTANCEOCCLUSIONCULLERSHADERVARIABLES_CS_HLSL
#define INSTANCEOCCLUSIONCULLERSHADERVARIABLES_CS_HLSL
// Generated from UnityEngine.Rendering.InstanceOcclusionCullerShaderVariables
// PackingRules = Exact
CBUFFER_START(InstanceOcclusionCullerShaderVariables)
uint _DrawInfoAllocIndex;
uint _DrawInfoCount;
uint _InstanceInfoAllocIndex;
uint _InstanceInfoCount;
int _BoundingSphereInstanceDataAddress;
int _DebugCounterIndex;
int _InstanceMultiplierShift;
int _InstanceOcclusionCullerPad0;
CBUFFER_END
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 60581e86aa47d834785ca132fc385273
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1895ea87beb6a2944b488685a325ccc9
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,31 @@
#if !UNITY_WEBGL_RENDERER_ONLY
namespace UnityEngine.Rendering
{
[GenerateHLSL(needAccessors = false, generateCBuffer = true)]
internal unsafe struct OccluderDepthPyramidConstants
{
[HLSLArray(OccluderContext.k_MaxSubviewsPerView, typeof(Matrix4x4))]
public fixed float _InvViewProjMatrix[OccluderContext.k_MaxSubviewsPerView * 16];
[HLSLArray(OccluderContext.k_MaxSilhouettePlanes, typeof(Vector4))]
public fixed float _SilhouettePlanes[OccluderContext.k_MaxSilhouettePlanes * 4];
[HLSLArray(OccluderContext.k_MaxSubviewsPerView, typeof(ShaderGenUInt4))]
public fixed uint _SrcOffset[OccluderContext.k_MaxSubviewsPerView * 4];
[HLSLArray(5, typeof(ShaderGenUInt4))]
public fixed uint _MipOffsetAndSize[5 * 4];
public uint _OccluderMipLayoutSizeX;
public uint _OccluderMipLayoutSizeY;
public uint _OccluderDepthPyramidPad0;
public uint _OccluderDepthPyramidPad1;
public uint _SrcSliceIndices; // packed 4 bits each
public uint _DstSubviewIndices; // packed 4 bits each
public uint _MipCount;
public uint _SilhouettePlaneCount;
}
}
#endif // !UNITY_WEBGL_RENDERER_ONLY
@@ -0,0 +1,25 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef OCCLUDERDEPTHPYRAMIDCONSTANTS_CS_HLSL
#define OCCLUDERDEPTHPYRAMIDCONSTANTS_CS_HLSL
// Generated from UnityEngine.Rendering.OccluderDepthPyramidConstants
// PackingRules = Exact
CBUFFER_START(OccluderDepthPyramidConstants)
float4x4 _InvViewProjMatrix[6];
float4 _SilhouettePlanes[6];
uint4 _SrcOffset[6];
uint4 _MipOffsetAndSize[5];
uint _OccluderMipLayoutSizeX;
uint _OccluderMipLayoutSizeY;
uint _OccluderDepthPyramidPad0;
uint _OccluderDepthPyramidPad1;
uint _SrcSliceIndices;
uint _DstSubviewIndices;
uint _MipCount;
uint _SilhouettePlaneCount;
CBUFFER_END
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5cbc804d3cb252947a62ba74b9e72d08
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c681068da611a114aa6b31c7214140f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,623 @@
#if !UNITY_WEBGL_RENDERER_ONLY
using System;
using System.Collections.Generic;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using UnityEngine.Rendering.RenderGraphModule;
namespace UnityEngine.Rendering
{
[GenerateHLSL]
internal enum OcclusionCullingCommonConfig
{
MaxOccluderMips = 8,
MaxOccluderSilhouettePlanes = 6,
MaxSubviewsPerView = 6,
DebugPyramidOffset = 4, // TODO: rename
}
[GenerateHLSL(needAccessors = false)]
internal enum OcclusionTestDebugFlag
{
AlwaysPass = (1 << 0),
CountVisible = (1 << 1),
}
internal struct OcclusionTestComputeShader
{
public ComputeShader cs;
public LocalKeyword occlusionDebugKeyword;
public void Init(ComputeShader cs)
{
this.cs = cs;
this.occlusionDebugKeyword = new LocalKeyword(cs, "OCCLUSION_DEBUG");
}
}
internal struct SilhouettePlaneCache : IDisposable
{
private struct Slot
{
public bool isActive;
public EntityId viewID;
public int planeCount; // planeIndex = slotIndex * kMaxSilhouettePlanes
public int lastUsedFrameIndex;
public Slot(EntityId viewID, int planeCount, int frameIndex)
{
this.isActive = true;
this.viewID = viewID;
this.planeCount = planeCount;
this.lastUsedFrameIndex = frameIndex;
}
}
private const int kMaxSilhouettePlanes = (int)OcclusionCullingCommonConfig.MaxOccluderSilhouettePlanes;
private NativeParallelHashMap<EntityId, int> m_SubViewIDToIndexMap;
private NativeList<int> m_SlotFreeList;
private NativeList<Slot> m_Slots;
private NativeList<Plane> m_PlaneStorage;
public void Init()
{
m_SubViewIDToIndexMap = new NativeParallelHashMap<EntityId, int>(16, Allocator.Persistent);
m_SlotFreeList = new NativeList<int>(16, Allocator.Persistent);
m_Slots = new NativeList<Slot>(16, Allocator.Persistent);
m_PlaneStorage = new NativeList<Plane>(16 * kMaxSilhouettePlanes, Allocator.Persistent);
}
public void Dispose()
{
m_SubViewIDToIndexMap.Dispose();
m_SlotFreeList.Dispose();
m_Slots.Dispose();
m_PlaneStorage.Dispose();
}
public void Update(EntityId viewID, NativeArray<Plane> planes, int frameIndex)
{
int planeCount = Math.Min(planes.Length, kMaxSilhouettePlanes);
if (!m_SubViewIDToIndexMap.TryGetValue(viewID, out int slotIndex))
{
if (m_SlotFreeList.Length > 0)
{
// take a free slot from the free list
slotIndex = m_SlotFreeList[m_SlotFreeList.Length - 1];
m_SlotFreeList.Length = m_SlotFreeList.Length - 1;
}
else
{
// ensure we have capacity for a few more
if (m_Slots.Length == m_Slots.Capacity)
{
int newCapacity = m_Slots.Length + 8;
m_Slots.SetCapacity(newCapacity);
m_PlaneStorage.SetCapacity(newCapacity * kMaxSilhouettePlanes);
}
// use the next slot in storage
slotIndex = m_Slots.Length;
int newSlotCount = slotIndex + 1;
m_Slots.ResizeUninitialized(newSlotCount);
m_PlaneStorage.ResizeUninitialized(newSlotCount * kMaxSilhouettePlanes);
}
// associate with this view ID
m_SubViewIDToIndexMap.Add(viewID, slotIndex);
}
m_Slots[slotIndex] = new Slot(viewID, planeCount, frameIndex);
m_PlaneStorage.AsArray().GetSubArray(slotIndex * kMaxSilhouettePlanes, planeCount).CopyFrom(planes);
}
public void FreeUnusedSlots(int frameIndex, int maximumAge)
{
for (int slotIndex = 0; slotIndex < m_Slots.Length; ++slotIndex)
{
var slot = m_Slots[slotIndex];
if (!slot.isActive)
continue;
if ((frameIndex - slot.lastUsedFrameIndex) > maximumAge)
{
slot.isActive = false;
m_Slots[slotIndex] = slot;
m_SubViewIDToIndexMap.Remove(slot.viewID);
m_SlotFreeList.Add(slotIndex);
}
}
}
public NativeArray<Plane> GetSubArray(EntityId viewID)
{
int planeOffset = 0;
int planeCount = 0;
if (m_SubViewIDToIndexMap.TryGetValue(viewID, out int slotIndex))
{
planeOffset = slotIndex * kMaxSilhouettePlanes;
planeCount = m_Slots[slotIndex].planeCount;
}
return m_PlaneStorage.AsArray().GetSubArray(planeOffset, planeCount);
}
}
internal class OcclusionCullingCommon : IDisposable
{
private struct OccluderContextSlot
{
public bool valid;
public int lastUsedFrameIndex;
public EntityId viewID;
}
private static readonly int s_MaxContextGCFrame = 8; // Allow a few frames for alternate frame shadow updates before cleanup
private Material m_DebugOcclusionTestMaterial;
private Material m_OccluderDebugViewMaterial;
private ComputeShader m_OcclusionDebugCS;
private int m_ClearOcclusionDebugKernel;
private ComputeShader m_OccluderDepthPyramidCS;
private int m_OccluderDepthDownscaleKernel;
private int m_FrameIndex = 0;
private SilhouettePlaneCache m_SilhouettePlaneCache;
private NativeParallelHashMap<EntityId, int> m_ViewIDToIndexMap;
private List<OccluderContext> m_OccluderContextData;
private NativeList<OccluderContextSlot> m_OccluderContextSlots;
private NativeList<int> m_FreeOccluderContexts;
private NativeArray<OcclusionCullingCommonShaderVariables> m_CommonShaderVariables;
private ComputeBuffer m_CommonConstantBuffer;
private NativeArray<OcclusionCullingDebugShaderVariables> m_DebugShaderVariables;
private ComputeBuffer m_DebugConstantBuffer;
private ProfilingSampler m_ProfilingSamplerUpdateOccluders;
private ProfilingSampler m_ProfilingSamplerOcclusionTestOverlay;
private ProfilingSampler m_ProfilingSamplerOccluderOverlay;
private BaseRenderFunc<OcclusionTestOverlaySetupPassData, ComputeGraphContext> m_ComputePassRenderFunc;
private BaseRenderFunc<OcclusionTestOverlayPassData, RasterGraphContext> m_RasterPassRenderFunc;
internal void Initialize(GPUResidentDrawerResources resources)
{
m_DebugOcclusionTestMaterial = CoreUtils.CreateEngineMaterial(resources.debugOcclusionTestPS);
m_OccluderDebugViewMaterial = CoreUtils.CreateEngineMaterial(resources.debugOccluderPS);
m_OcclusionDebugCS = resources.occlusionCullingDebugKernels;
m_ClearOcclusionDebugKernel = m_OcclusionDebugCS.FindKernel("ClearOcclusionDebug");
m_OccluderDepthPyramidCS = resources.occluderDepthPyramidKernels;
m_OccluderDepthDownscaleKernel = m_OccluderDepthPyramidCS.FindKernel("OccluderDepthDownscale");
m_SilhouettePlaneCache.Init();
m_ViewIDToIndexMap = new NativeParallelHashMap<EntityId, int>(64, Allocator.Persistent);
m_OccluderContextData = new List<OccluderContext>();
m_OccluderContextSlots = new NativeList<OccluderContextSlot>(64, Allocator.Persistent);
m_FreeOccluderContexts = new NativeList<int>(64, Allocator.Persistent);
m_ProfilingSamplerUpdateOccluders = new ProfilingSampler("UpdateOccluders");
m_ProfilingSamplerOcclusionTestOverlay = new ProfilingSampler("OcclusionTestOverlay");
m_ProfilingSamplerOccluderOverlay = new ProfilingSampler("OccluderOverlay");
m_CommonShaderVariables = new NativeArray<OcclusionCullingCommonShaderVariables>(1, Allocator.Persistent);
m_CommonConstantBuffer = new ComputeBuffer(1, UnsafeUtility.SizeOf<OcclusionCullingCommonShaderVariables>(), ComputeBufferType.Constant);
m_DebugShaderVariables = new NativeArray<OcclusionCullingDebugShaderVariables>(1, Allocator.Persistent);
m_DebugConstantBuffer = new ComputeBuffer(1, UnsafeUtility.SizeOf<OcclusionCullingDebugShaderVariables>(), ComputeBufferType.Constant);
m_ComputePassRenderFunc = (OcclusionTestOverlaySetupPassData data, ComputeGraphContext ctx) =>
{
m_DebugShaderVariables[0] = data.cb;
ctx.cmd.SetBufferData(m_DebugConstantBuffer, m_DebugShaderVariables);
m_DebugOcclusionTestMaterial.SetConstantBuffer(
ShaderIDs.OcclusionCullingDebugShaderVariables,
m_DebugConstantBuffer,
0,
m_DebugConstantBuffer.stride);
};
m_RasterPassRenderFunc = (OcclusionTestOverlayPassData data, RasterGraphContext ctx) =>
{
ctx.cmd.SetGlobalBuffer(ShaderIDs._OcclusionDebugOverlay, data.debugPyramid);
CoreUtils.DrawFullScreen(ctx.cmd, m_DebugOcclusionTestMaterial);
};
}
private static class ShaderIDs
{
public static readonly int OcclusionCullingCommonShaderVariables = Shader.PropertyToID("OcclusionCullingCommonShaderVariables");
public static readonly int _OccluderDepthPyramid = Shader.PropertyToID("_OccluderDepthPyramid");
public static readonly int _OcclusionDebugOverlay = Shader.PropertyToID("_OcclusionDebugOverlay");
public static readonly int OcclusionCullingDebugShaderVariables = Shader.PropertyToID("OcclusionCullingDebugShaderVariables");
}
internal static bool UseOcclusionDebug(in OccluderContext occluderCtx)
{
return occluderCtx.occlusionDebugOverlaySize != 0;
}
internal void PrepareCulling(ComputeCommandBuffer cmd, in OccluderContext occluderCtx, in OcclusionCullingSettings settings, in InstanceOcclusionTestSubviewSettings subviewSettings, in OcclusionTestComputeShader shader, bool useOcclusionDebug)
{
OccluderContext.SetKeyword(cmd, shader.cs, shader.occlusionDebugKeyword, useOcclusionDebug);
var debugDisplaySettings = GPUResidentDrawer.debugDisplaySettings;
m_CommonShaderVariables[0] = new OcclusionCullingCommonShaderVariables(
in occluderCtx,
subviewSettings,
debugDisplaySettings?.occlusionTestOverlayCountVisible ?? false,
debugDisplaySettings?.overrideOcclusionTestToAlwaysPass ?? false);
cmd.SetBufferData(m_CommonConstantBuffer, m_CommonShaderVariables);
cmd.SetComputeConstantBufferParam(shader.cs, ShaderIDs.OcclusionCullingCommonShaderVariables, m_CommonConstantBuffer, 0, m_CommonConstantBuffer.stride);
DispatchDebugClear(cmd, settings.viewInstanceID);
}
internal static void SetDepthPyramid(ComputeCommandBuffer cmd, in OcclusionTestComputeShader shader, int kernel, in OccluderHandles occluderHandles)
{
cmd.SetComputeTextureParam(shader.cs, kernel, ShaderIDs._OccluderDepthPyramid, occluderHandles.occluderDepthPyramid);
}
internal static void SetDebugPyramid(ComputeCommandBuffer cmd, in OcclusionTestComputeShader shader, int kernel, in OccluderHandles occluderHandles)
{
cmd.SetComputeBufferParam(shader.cs, kernel, ShaderIDs._OcclusionDebugOverlay, occluderHandles.occlusionDebugOverlay);
}
private class OcclusionTestOverlaySetupPassData
{
public OcclusionCullingDebugShaderVariables cb;
}
private class OcclusionTestOverlayPassData
{
public BufferHandle debugPyramid;
}
public void RenderDebugOcclusionTestOverlay(RenderGraph renderGraph, DebugDisplayGPUResidentDrawer debugSettings, EntityId viewID, TextureHandle colorBuffer)
{
if (debugSettings == null)
return;
if (!debugSettings.occlusionTestOverlayEnabled)
return;
OcclusionCullingDebugOutput debugOutput = GetOcclusionTestDebugOutput(viewID);
if (debugOutput.occlusionDebugOverlay == null)
return;
using (var builder = renderGraph.AddComputePass<OcclusionTestOverlaySetupPassData>("OcclusionTestOverlay", out var passData, m_ProfilingSamplerOcclusionTestOverlay))
{
builder.AllowPassCulling(false);
passData.cb = debugOutput.cb;
builder.SetRenderFunc(m_ComputePassRenderFunc);
}
using (var builder = renderGraph.AddRasterRenderPass<OcclusionTestOverlayPassData>("OcclusionTestOverlay", out var passData, m_ProfilingSamplerOcclusionTestOverlay))
{
builder.AllowGlobalStateModification(true);
passData.debugPyramid = renderGraph.ImportBuffer(debugOutput.occlusionDebugOverlay);
builder.SetRenderAttachment(colorBuffer, 0);
builder.UseBuffer(passData.debugPyramid);
builder.SetRenderFunc(m_RasterPassRenderFunc);
}
}
private struct DebugOccluderViewData
{
public int passIndex;
public Rect viewport;
public bool valid;
}
class OccluderOverlayPassData
{
public Material debugMaterial;
public RTHandle occluderTexture;
public Rect viewport;
public int passIndex;
public Vector2 validRange;
}
public void RenderDebugOccluderOverlay(RenderGraph renderGraph, DebugDisplayGPUResidentDrawer debugSettings, Vector2 screenPos, float maxHeight, TextureHandle colorBuffer)
{
if (debugSettings == null)
return;
if (!debugSettings.occluderDebugViewEnable)
return;
if (!debugSettings.GetOccluderViewID(out var camera))
return;
var occluderTexture = GetOcclusionTestDebugOutput(camera).occluderDepthPyramid;
if (occluderTexture == null)
return;
Material debugMaterial = m_OccluderDebugViewMaterial;
int passIndex = debugMaterial.FindPass("DebugOccluder");
Vector2 outputSize = occluderTexture.referenceSize;
float scaleFactor = maxHeight / outputSize.y;
outputSize *= scaleFactor;
Rect viewport = new Rect(screenPos.x, screenPos.y, outputSize.x, outputSize.y);
using (var builder = renderGraph.AddRasterRenderPass<OccluderOverlayPassData>("OccluderOverlay", out var passData, m_ProfilingSamplerOccluderOverlay))
{
builder.AllowGlobalStateModification(true);
builder.SetRenderAttachment(colorBuffer, 0);
passData.debugMaterial = debugMaterial;
passData.occluderTexture = occluderTexture;
passData.viewport = viewport;
passData.passIndex = passIndex;
passData.validRange = debugSettings.occluderDebugViewRange;
builder.SetRenderFunc(
static (OccluderOverlayPassData data, RasterGraphContext ctx) =>
{
var mpb = ctx.renderGraphPool.GetTempMaterialPropertyBlock();
mpb.SetTexture("_OccluderTexture", data.occluderTexture);
mpb.SetVector("_ValidRange", data.validRange);
ctx.cmd.SetViewport(data.viewport);
ctx.cmd.DrawProcedural(Matrix4x4.identity, data.debugMaterial, data.passIndex, MeshTopology.Triangles, 3, 1, mpb);
});
}
}
private void DispatchDebugClear(ComputeCommandBuffer cmd, EntityId viewID)
{
if (!m_ViewIDToIndexMap.TryGetValue(viewID, out var contextIndex))
return;
OccluderContext occluderCtx = m_OccluderContextData[contextIndex];
if (UseOcclusionDebug(in occluderCtx) && occluderCtx.debugNeedsClear)
{
var cs = m_OcclusionDebugCS;
int kernel = m_ClearOcclusionDebugKernel;
cmd.SetComputeConstantBufferParam(cs, ShaderIDs.OcclusionCullingCommonShaderVariables, m_CommonConstantBuffer, 0, m_CommonConstantBuffer.stride);
cmd.SetComputeBufferParam(cs, kernel, ShaderIDs._OcclusionDebugOverlay, occluderCtx.occlusionDebugOverlay);
Vector2Int mip0Size = occluderCtx.occluderMipBounds[0].size;
cmd.DispatchCompute(cs, kernel, (mip0Size.x + 7) / 8, (mip0Size.y + 7) / 8, occluderCtx.subviewCount);
// mark as cleared in the dictionary
occluderCtx.debugNeedsClear = false;
m_OccluderContextData[contextIndex] = occluderCtx;
}
}
private OccluderHandles PrepareOccluders(RenderGraph renderGraph, in OccluderParameters occluderParams)
{
OccluderHandles occluderHandles = new OccluderHandles();
if (occluderParams.depthTexture.IsValid())
{
if (!m_ViewIDToIndexMap.TryGetValue(occluderParams.viewInstanceID, out var contextIndex))
contextIndex = NewContext(occluderParams.viewInstanceID);
OccluderContext ctx = m_OccluderContextData[contextIndex];
ctx.PrepareOccluders(occluderParams);
occluderHandles = ctx.Import(renderGraph);
m_OccluderContextData[contextIndex] = ctx;
}
else
{
DeleteContext(occluderParams.viewInstanceID);
}
return occluderHandles;
}
private void CreateFarDepthPyramid(ComputeCommandBuffer cmd, in OccluderParameters occluderParams, ReadOnlySpan<OccluderSubviewUpdate> occluderSubviewUpdates, in OccluderHandles occluderHandles)
{
if (!m_ViewIDToIndexMap.TryGetValue(occluderParams.viewInstanceID, out var contextIndex))
return;
var silhouettePlanes = m_SilhouettePlaneCache.GetSubArray(occluderParams.viewInstanceID);
OccluderContext ctx = m_OccluderContextData[contextIndex];
ctx.CreateFarDepthPyramid(cmd, occluderParams, occluderSubviewUpdates, occluderHandles, silhouettePlanes, m_OccluderDepthPyramidCS, m_OccluderDepthDownscaleKernel);
ctx.version++;
m_OccluderContextData[contextIndex] = ctx;
var slot = m_OccluderContextSlots[contextIndex];
slot.lastUsedFrameIndex = m_FrameIndex;
m_OccluderContextSlots[contextIndex] = slot;
}
private class UpdateOccludersPassData
{
public OccluderParameters occluderParams;
public List<OccluderSubviewUpdate> occluderSubviewUpdates;
public OccluderHandles occluderHandles;
public GPUResidentContext grdContext;
}
public bool UpdateInstanceOccluders(RenderGraph renderGraph, GPUResidentContext grdContext, in OccluderParameters occluderParams, ReadOnlySpan<OccluderSubviewUpdate> occluderSubviewUpdates)
{
var occluderHandles = PrepareOccluders(renderGraph, occluderParams);
if (!occluderHandles.occluderDepthPyramid.IsValid())
return false;
using (var builder = renderGraph.AddComputePass<UpdateOccludersPassData>("Update Occluders", out var passData, m_ProfilingSamplerUpdateOccluders))
{
builder.AllowGlobalStateModification(true);
passData.grdContext = grdContext;
passData.occluderParams = occluderParams;
if (passData.occluderSubviewUpdates is null)
passData.occluderSubviewUpdates = new List<OccluderSubviewUpdate>();
else
passData.occluderSubviewUpdates.Clear();
for (int i = 0; i < occluderSubviewUpdates.Length; ++i)
passData.occluderSubviewUpdates.Add(occluderSubviewUpdates[i]);
passData.occluderHandles = occluderHandles;
builder.UseTexture(passData.occluderParams.depthTexture);
passData.occluderHandles.UseForOccluderUpdate(builder);
builder.SetRenderFunc(
static (UpdateOccludersPassData data, ComputeGraphContext context) =>
{
Span<OccluderSubviewUpdate> occluderSubviewUpdates = stackalloc OccluderSubviewUpdate[data.occluderSubviewUpdates.Count];
int subviewMask = 0;
for (int i = 0; i < data.occluderSubviewUpdates.Count; ++i)
{
occluderSubviewUpdates[i] = data.occluderSubviewUpdates[i];
subviewMask |= 1 << data.occluderSubviewUpdates[i].subviewIndex;
}
OcclusionCullingCommon occlusionCullingCommon = data.grdContext.occlusionCullingCommon;
occlusionCullingCommon.CreateFarDepthPyramid(context.cmd, in data.occluderParams, occluderSubviewUpdates, in data.occluderHandles);
data.grdContext.culler.InstanceOccludersUpdated(data.occluderParams.viewInstanceID, subviewMask, occlusionCullingCommon);
});
}
return true;
}
internal void UpdateSilhouettePlanes(EntityId viewID, NativeArray<Plane> planes)
{
m_SilhouettePlaneCache.Update(viewID, planes, m_FrameIndex);
}
internal OcclusionCullingDebugOutput GetOcclusionTestDebugOutput(EntityId viewID)
{
if (m_ViewIDToIndexMap.TryGetValue(viewID, out var contextIndex) && m_OccluderContextSlots[contextIndex].valid)
return m_OccluderContextData[contextIndex].GetDebugOutput();
return new OcclusionCullingDebugOutput();
}
public void UpdateOccluderStats(DebugRendererBatcherStats debugStats)
{
debugStats.occluderStats.Clear();
foreach (var pair in m_ViewIDToIndexMap)
{
if (pair.Value < m_OccluderContextSlots.Length && m_OccluderContextSlots[pair.Value].valid)
{
debugStats.occluderStats.Add(new DebugOccluderStats
{
viewID = pair.Key,
subviewCount = m_OccluderContextData[pair.Value].subviewCount,
occluderMipLayoutSize = m_OccluderContextData[pair.Value].occluderMipLayoutSize,
});
}
}
}
internal bool HasOccluderContext(EntityId viewID)
{
return m_ViewIDToIndexMap.ContainsKey(viewID);
}
internal bool GetOccluderContext(EntityId viewID, out OccluderContext occluderContext)
{
if (m_ViewIDToIndexMap.TryGetValue(viewID, out var contextIndex) && m_OccluderContextSlots[contextIndex].valid)
{
occluderContext = m_OccluderContextData[contextIndex];
return true;
}
occluderContext = new OccluderContext();
return false;
}
internal void UpdateFrame()
{
for (int i = 0; i < m_OccluderContextData.Count; ++i)
{
if (!m_OccluderContextSlots[i].valid)
continue;
OccluderContext occluderCtx = m_OccluderContextData[i];
var slot = m_OccluderContextSlots[i];
//Garbage collect unused contexts for a long time:
if ((m_FrameIndex - slot.lastUsedFrameIndex) >= s_MaxContextGCFrame)
{
DeleteContext(slot.viewID);
continue;
}
occluderCtx.debugNeedsClear = true;
m_OccluderContextData[i] = occluderCtx;
}
m_SilhouettePlaneCache.FreeUnusedSlots(m_FrameIndex, s_MaxContextGCFrame);
++m_FrameIndex;
}
private int NewContext(EntityId viewID)
{
int newSlot = -1;
var newCtxSlot = new OccluderContextSlot { valid = true, viewID = viewID, lastUsedFrameIndex = m_FrameIndex };
var newCtx = new OccluderContext() {};
if (m_FreeOccluderContexts.Length > 0)
{
newSlot = m_FreeOccluderContexts[m_FreeOccluderContexts.Length - 1];
m_FreeOccluderContexts.RemoveAt(m_FreeOccluderContexts.Length - 1);
m_OccluderContextData[newSlot] = newCtx;
m_OccluderContextSlots[newSlot] = newCtxSlot;
}
else
{
newSlot = m_OccluderContextData.Count;
m_OccluderContextData.Add(newCtx);
m_OccluderContextSlots.Add(newCtxSlot);
}
m_ViewIDToIndexMap.Add(viewID, newSlot);
return newSlot;
}
private void DeleteContext(EntityId viewID)
{
if (!m_ViewIDToIndexMap.TryGetValue(viewID, out var contextIndex) || !m_OccluderContextSlots[contextIndex].valid)
return;
m_OccluderContextData[contextIndex].Dispose();
m_OccluderContextSlots[contextIndex] = new OccluderContextSlot { valid = false };
m_FreeOccluderContexts.Add(contextIndex);
m_ViewIDToIndexMap.Remove(viewID);
}
public void Dispose()
{
CoreUtils.Destroy(m_DebugOcclusionTestMaterial);
CoreUtils.Destroy(m_OccluderDebugViewMaterial);
for (int i = 0; i < m_OccluderContextData.Count; ++i)
{
if (m_OccluderContextSlots[i].valid)
m_OccluderContextData[i].Dispose();
}
m_SilhouettePlaneCache.Dispose();
m_ViewIDToIndexMap.Dispose();
m_FreeOccluderContexts.Dispose();
m_OccluderContextData.Clear();
m_OccluderContextSlots.Dispose();
m_CommonShaderVariables.Dispose();
m_CommonConstantBuffer.Release();
m_DebugShaderVariables.Dispose();
m_DebugConstantBuffer.Release();
}
}
}
#endif // !UNITY_WEBGL_RENDERER_ONLY
@@ -0,0 +1,22 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef OCCLUSIONCULLINGCOMMON_CS_HLSL
#define OCCLUSIONCULLINGCOMMON_CS_HLSL
//
// UnityEngine.Rendering.OcclusionCullingCommonConfig: static fields
//
#define OCCLUSIONCULLINGCOMMONCONFIG_MAX_OCCLUDER_MIPS (8)
#define OCCLUSIONCULLINGCOMMONCONFIG_MAX_OCCLUDER_SILHOUETTE_PLANES (6)
#define OCCLUSIONCULLINGCOMMONCONFIG_MAX_SUBVIEWS_PER_VIEW (6)
#define OCCLUSIONCULLINGCOMMONCONFIG_DEBUG_PYRAMID_OFFSET (4)
//
// UnityEngine.Rendering.OcclusionTestDebugFlag: static fields
//
#define OCCLUSIONTESTDEBUGFLAG_ALWAYS_PASS (1)
#define OCCLUSIONTESTDEBUGFLAG_COUNT_VISIBLE (2)
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1ed97a1fe4775544caa75b92f1d8e9ae
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ec1ae020bebf201478636c2123e2dde8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,106 @@
#ifndef _OCCLUSION_CULLING_COMMON_H
#define _OCCLUSION_CULLING_COMMON_H
// If using this the shader should add
// #pragma multi_compile _ OCCLUSION_DEBUG
// before including this file
#include "Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Culling/OcclusionCullingCommon.cs.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Culling/OcclusionCullingCommonShaderVariables.cs.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Culling/OcclusionTestCommon.hlsl"
#include "Packages/com.unity.render-pipelines.core/Runtime/GPUDriven/Utilities/GeometryUtilities.hlsl"
#define OCCLUSION_ENABLE_GATHER_TRIM 1
TEXTURE2D(_OccluderDepthPyramid);
SAMPLER(s_linear_clamp_sampler);
#ifdef OCCLUSION_DEBUG
RWStructuredBuffer<uint> _OcclusionDebugOverlay;
uint OcclusionDebugOverlayOffset(uint2 coord)
{
return OCCLUSIONCULLINGCOMMONCONFIG_DEBUG_PYRAMID_OFFSET + coord.x + _OccluderMipLayoutSizeX * coord.y;
}
#endif
bool IsOcclusionVisible(float3 frontCenterPosRWS, float2 centerPosNDC, float2 radialPosNDC, int subviewIndex)
{
bool isVisible = true;
float queryClosestDepth = ComputeNormalizedDeviceCoordinatesWithZ(frontCenterPosRWS, _ViewProjMatrix[subviewIndex]).z;
bool isBehindCamera = dot(frontCenterPosRWS, _FacingDirWorldSpace[subviewIndex].xyz) >= 0.f;
float2 centerCoordInTopMip = centerPosNDC * _DepthSizeInOccluderPixels.xy;
float radiusInPixels = length((radialPosNDC - centerPosNDC) * _DepthSizeInOccluderPixels.xy);
// log2 of the radius in pixels for the gather4 mip level
int mipLevel = 0;
float mipPartUnused = frexp(radiusInPixels, mipLevel);
mipLevel = max(mipLevel + 1, 0);
if (mipLevel < OCCLUSIONCULLINGCOMMONCONFIG_MAX_OCCLUDER_MIPS && !isBehindCamera)
{
// scale our coordinate to this mip
float2 centerCoordInChosenMip = ldexp(centerCoordInTopMip, -mipLevel);
int4 mipBounds = _OccluderMipBounds[mipLevel];
mipBounds.y += subviewIndex * _OccluderMipLayoutSizeY;
if ((_OcclusionTestDebugFlags & OCCLUSIONTESTDEBUGFLAG_ALWAYS_PASS) == 0)
{
// gather4 occluder depths to cover this radius
float2 gatherUv = (float2(mipBounds.xy) + clamp(centerCoordInChosenMip, .5f, float2(mipBounds.zw) - .5f)) * _OccluderDepthPyramidSize.zw;
float4 gatherDepths = GATHER_TEXTURE2D(_OccluderDepthPyramid, s_linear_clamp_sampler, gatherUv);
float occluderDepth = FarthestDepth(gatherDepths);
isVisible = IsVisibleAfterOcclusion(occluderDepth, queryClosestDepth);
}
#ifdef OCCLUSION_DEBUG
// show footprint of gather4 in debug output
bool countForOverlay = ((_OcclusionTestDebugFlags & OCCLUSIONTESTDEBUGFLAG_COUNT_VISIBLE) != 0);
if (!isVisible)
countForOverlay = !countForOverlay;
if (countForOverlay)
{
uint2 debugCoord = mipBounds.xy + uint2(clamp(int2(centerCoordInChosenMip - .5f), 0, mipBounds.zw - 2));
InterlockedAdd(_OcclusionDebugOverlay[OcclusionDebugOverlayOffset(debugCoord + uint2(0, 0))], 1);
InterlockedAdd(_OcclusionDebugOverlay[OcclusionDebugOverlayOffset(debugCoord + uint2(1, 0))], 1);
InterlockedAdd(_OcclusionDebugOverlay[OcclusionDebugOverlayOffset(debugCoord + uint2(0, 1))], 1);
InterlockedAdd(_OcclusionDebugOverlay[OcclusionDebugOverlayOffset(debugCoord + uint2(1, 1))], 1);
// accumulate the total in the first slot
InterlockedAdd(_OcclusionDebugOverlay[0], 1);
}
#endif
}
return isVisible;
}
bool IsOcclusionVisible(BoundingObjectData data, int subviewIndex)
{
return IsOcclusionVisible(data.frontCenterPosRWS, data.centerPosNDC, data.radialPosNDC, subviewIndex);
}
bool IsOcclusionVisible(SphereBound boundingSphere, int subviewIndex)
{
BoundingObjectData data = CalculateBoundingObjectData(
boundingSphere,
_ViewProjMatrix[subviewIndex],
_ViewOriginWorldSpace[subviewIndex],
_RadialDirWorldSpace[subviewIndex],
_FacingDirWorldSpace[subviewIndex]);
return IsOcclusionVisible(data, subviewIndex);
}
bool IsOcclusionVisible(CylinderBound cylinderBound, int subviewIndex)
{
BoundingObjectData data = CalculateBoundingObjectData(
cylinderBound,
_ViewProjMatrix[subviewIndex],
_ViewOriginWorldSpace[subviewIndex],
_RadialDirWorldSpace[subviewIndex],
_FacingDirWorldSpace[subviewIndex]);
return IsOcclusionVisible(data, subviewIndex);
}
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 13f1cda4ab8412041ac157181fa6e421
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,92 @@
#if !UNITY_WEBGL_RENDERER_ONLY
namespace UnityEngine.Rendering
{
// TODO make consistent with InstanceOcclusionCullerShaderVariables
[GenerateHLSL(needAccessors = false, generateCBuffer = true)]
internal unsafe struct OcclusionCullingCommonShaderVariables
{
[HLSLArray(OccluderContext.k_MaxOccluderMips, typeof(ShaderGenUInt4))]
public fixed uint _OccluderMipBounds[OccluderContext.k_MaxOccluderMips * 4];
[HLSLArray(OccluderContext.k_MaxSubviewsPerView, typeof(Matrix4x4))]
public fixed float _ViewProjMatrix[OccluderContext.k_MaxSubviewsPerView * 16]; // from view-centered world space
[HLSLArray(OccluderContext.k_MaxSubviewsPerView, typeof(Vector4))]
public fixed float _ViewOriginWorldSpace[OccluderContext.k_MaxSubviewsPerView * 4];
[HLSLArray(OccluderContext.k_MaxSubviewsPerView, typeof(Vector4))]
public fixed float _FacingDirWorldSpace[OccluderContext.k_MaxSubviewsPerView * 4];
[HLSLArray(OccluderContext.k_MaxSubviewsPerView, typeof(Vector4))]
public fixed float _RadialDirWorldSpace[OccluderContext.k_MaxSubviewsPerView * 4];
public Vector4 _DepthSizeInOccluderPixels;
public Vector4 _OccluderDepthPyramidSize;
public uint _OccluderMipLayoutSizeX;
public uint _OccluderMipLayoutSizeY;
public uint _OcclusionTestDebugFlags;
public uint _OcclusionCullingCommonPad0;
public int _OcclusionTestCount;
public int _OccluderSubviewIndices; // packed 4 bits each
public int _CullingSplitIndices; // packed 4 bits each
public int _CullingSplitMask; // only used for early out
internal OcclusionCullingCommonShaderVariables(
in OccluderContext occluderCtx,
in InstanceOcclusionTestSubviewSettings subviewSettings,
bool occlusionOverlayCountVisible,
bool overrideOcclusionTestToAlwaysPass)
{
for (int i = 0; i < occluderCtx.subviewCount; ++i)
{
if (occluderCtx.IsSubviewValid(i))
{
unsafe
{
for (int j = 0; j < 16; ++j)
_ViewProjMatrix[16 * i + j] = occluderCtx.subviewData[i].viewProjMatrix[j];
for (int j = 0; j < 4; ++j)
{
_ViewOriginWorldSpace[4 * i + j] = occluderCtx.subviewData[i].viewOriginWorldSpace[j];
_FacingDirWorldSpace[4 * i + j] = occluderCtx.subviewData[i].facingDirWorldSpace[j];
_RadialDirWorldSpace[4 * i + j] = occluderCtx.subviewData[i].radialDirWorldSpace[j];
}
}
}
}
_OccluderMipLayoutSizeX = (uint)occluderCtx.occluderMipLayoutSize.x;
_OccluderMipLayoutSizeY = (uint)occluderCtx.occluderMipLayoutSize.y;
_OcclusionTestDebugFlags
= (overrideOcclusionTestToAlwaysPass ? (uint)OcclusionTestDebugFlag.AlwaysPass : 0)
| (occlusionOverlayCountVisible ? (uint)OcclusionTestDebugFlag.CountVisible : 0);
_OcclusionCullingCommonPad0 = 0;
_OcclusionTestCount = subviewSettings.testCount;
_OccluderSubviewIndices = subviewSettings.occluderSubviewIndices;
_CullingSplitIndices = subviewSettings.cullingSplitIndices;
_CullingSplitMask = subviewSettings.cullingSplitMask;
_DepthSizeInOccluderPixels = occluderCtx.depthBufferSizeInOccluderPixels;
Vector2Int textureSize = occluderCtx.occluderDepthPyramidSize;
_OccluderDepthPyramidSize = new Vector4(textureSize.x, textureSize.y, 1.0f / textureSize.x, 1.0f / textureSize.y);
for (int i = 0; i < occluderCtx.occluderMipBounds.Length; ++i)
{
var mipBounds = occluderCtx.occluderMipBounds[i];
unsafe
{
_OccluderMipBounds[4*i + 0] = (uint)mipBounds.offset.x;
_OccluderMipBounds[4*i + 1] = (uint)mipBounds.offset.y;
_OccluderMipBounds[4*i + 2] = (uint)mipBounds.size.x;
_OccluderMipBounds[4*i + 3] = (uint)mipBounds.size.y;
}
}
}
}
}
#endif // !UNITY_WEBGL_RENDERER_ONLY
@@ -0,0 +1,28 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef OCCLUSIONCULLINGCOMMONSHADERVARIABLES_CS_HLSL
#define OCCLUSIONCULLINGCOMMONSHADERVARIABLES_CS_HLSL
// Generated from UnityEngine.Rendering.OcclusionCullingCommonShaderVariables
// PackingRules = Exact
CBUFFER_START(OcclusionCullingCommonShaderVariables)
uint4 _OccluderMipBounds[8];
float4x4 _ViewProjMatrix[6];
float4 _ViewOriginWorldSpace[6];
float4 _FacingDirWorldSpace[6];
float4 _RadialDirWorldSpace[6];
float4 _DepthSizeInOccluderPixels;
float4 _OccluderDepthPyramidSize;
uint _OccluderMipLayoutSizeX;
uint _OccluderMipLayoutSizeY;
uint _OcclusionTestDebugFlags;
uint _OcclusionCullingCommonPad0;
int _OcclusionTestCount;
int _OccluderSubviewIndices;
int _CullingSplitIndices;
int _CullingSplitMask;
CBUFFER_END
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a5ea6c3e82289ce4d8ea0b60a96b1ee2
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e30628ae9a1faa34fb2853ed6354bc90
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,21 @@
#if !UNITY_WEBGL_RENDERER_ONLY
using System;
namespace UnityEngine.Rendering
{
[GenerateHLSL(needAccessors = false, generateCBuffer = true)]
internal unsafe struct OcclusionCullingDebugShaderVariables
{
public Vector4 _DepthSizeInOccluderPixels;
[HLSLArray(OccluderContext.k_MaxOccluderMips, typeof(ShaderGenUInt4))]
public fixed uint _OccluderMipBounds[OccluderContext.k_MaxOccluderMips * 4];
public uint _OccluderMipLayoutSizeX;
public uint _OccluderMipLayoutSizeY;
public uint _OcclusionCullingDebugPad0;
public uint _OcclusionCullingDebugPad1;
}
}
#endif // !UNITY_WEBGL_RENDERER_ONLY
@@ -0,0 +1,19 @@
//
// This file was automatically generated. Please don't edit by hand. Execute Editor command [ Edit > Rendering > Generate Shader Includes ] instead
//
#ifndef OCCLUSIONCULLINGDEBUGSHADERVARIABLES_CS_HLSL
#define OCCLUSIONCULLINGDEBUGSHADERVARIABLES_CS_HLSL
// Generated from UnityEngine.Rendering.OcclusionCullingDebugShaderVariables
// PackingRules = Exact
CBUFFER_START(OcclusionCullingDebugShaderVariables)
float4 _DepthSizeInOccluderPixels;
uint4 _OccluderMipBounds[8];
uint _OccluderMipLayoutSizeX;
uint _OccluderMipLayoutSizeY;
uint _OcclusionCullingDebugPad0;
uint _OcclusionCullingDebugPad1;
CBUFFER_END
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 00f96d87bb315084d89b58bd90c5304a
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5c8137fcac12c3743bd060b069e1962b
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
#ifndef _OCCLUSION_TEST_COMMON_H
#define _OCCLUSION_TEST_COMMON_H
#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl"
float FarthestDepth(float depthA, float depthB)
{
#if UNITY_REVERSED_Z
return min(depthA, depthB);
#else
return max(depthA, depthB);
#endif
}
float FarthestDepth(float4 depths)
{
#if UNITY_REVERSED_Z
return Min3(depths.x, depths.y, min(depths.z, depths.w));
#else
return Max3(depths.x, depths.y, max(depths.z, depths.w));
#endif
}
bool IsVisibleAfterOcclusion(float occluderDepth, float queryClosestDepth)
{
#if UNITY_REVERSED_Z
return queryClosestDepth > occluderDepth;
#else
return queryClosestDepth < occluderDepth;
#endif
}
#endif
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 1024f2cfcd9723443be47989a040394e
ShaderIncludeImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant: