123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815 |
- 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
- {
- Occluded,
- NotOccluded,
- 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 maxInstanceCount;
- }
-
- 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,
- colorFormat: 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.GetDebugStats()?.occlusionOverlayEnabled ?? 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 argsBuffer;
- public BufferHandle drawInfoBuffer;
-
- public void UseForOcclusionTest(IBaseRenderGraphBuilder builder)
- {
- instanceBuffer = builder.UseBuffer(instanceBuffer, AccessFlags.ReadWrite);
- instanceInfoBuffer = builder.UseBuffer(instanceInfoBuffer, AccessFlags.Read);
- argsBuffer = builder.UseBuffer(argsBuffer, AccessFlags.ReadWrite);
- drawInfoBuffer = builder.UseBuffer(drawInfoBuffer, AccessFlags.Read);
- }
- }
-
- internal struct IndirectBufferContextStorage : IDisposable
- {
- private const int kAllocatorCount = (int)IndirectAllocator.Count;
- internal const int kExtraDrawAllocationCount = 1; // over-allocate by one for indirect args scratch space GPU-side
- 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_ArgsBuffer;
- private GraphicsBuffer m_DrawInfoBuffer;
- private NativeArray<IndirectDrawInfo> m_DrawInfoStaging;
-
- private int m_ContextAllocCounter;
- private NativeHashMap<int, 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 argsBuffer { get { return m_ArgsBuffer; } }
- public GraphicsBuffer drawInfoBuffer { get { return m_DrawInfoBuffer; } }
-
- public GraphicsBufferHandle visibleInstanceBufferHandle { get { return m_InstanceBuffer.bufferHandle; } }
- public GraphicsBufferHandle indirectArgsBufferHandle { get { return m_ArgsBuffer.bufferHandle; } }
-
- public IndirectBufferContextHandles ImportBuffers(RenderGraph renderGraph)
- {
- return new IndirectBufferContextHandles()
- {
- instanceBuffer = renderGraph.ImportBuffer(m_InstanceBuffer),
- instanceInfoBuffer = renderGraph.ImportBuffer(m_InstanceInfoBuffer),
- argsBuffer = renderGraph.ImportBuffer(m_ArgsBuffer),
- 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<int, 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)
- {
- m_ArgsBuffer = 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_ArgsBuffer.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(int 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(int 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;
- }
- }
- }
|