diff --git a/com.unity.render-pipelines.core/Runtime/BatchRenderer/DeferredMaterialBRG.cs b/com.unity.render-pipelines.core/Runtime/BatchRenderer/DeferredMaterialBRG.cs new file mode 100644 index 00000000000..34a44db3e06 --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/BatchRenderer/DeferredMaterialBRG.cs @@ -0,0 +1,434 @@ +using System; +using System.Collections.Generic; +using Unity.Burst; +using Unity.Collections; +using Unity.Collections.LowLevel.Unsafe; +using Unity.Jobs; +using Unity.Mathematics; +using UnityEngine; +using UnityEngine.Rendering; + +namespace UnityEngine.Rendering +{ + public class DeferredMaterialBRG + { + BatchRendererGroup m_BatchRendererGroup; + GeometryPool m_GeometryPool; + + Mesh m_TileMesh; + BatchMeshID m_TileMeshID; + bool m_MaterialDrawListDirty; + Dictionary m_MaterialsContainer; + NativeList m_MaterialDrawList; + + BatchSlot[] m_Batches; + NativeList m_BatchHandles; + + //hacks until we can have proper indirect dispatch. + int m_MaxNumberOfTiles; + + public const uint RenderLayerMask = 1u << 31; + public const int MaterialTileSize = 64; + + public Mesh globalGeoMesh => m_GeometryPool.globalMesh; + + private struct BRGMaterialInfo + { + public Material material; + public int refCount; + public BatchMaterialID batchMaterialID; + public uint materialGPUKey; + NativeArray m_BatchUsageBits; + + public void Initialize(int maxBatchCount, Material mat, BatchMaterialID batchMatID, uint gpuKey) + { + m_BatchUsageBits = new NativeArray((maxBatchCount + 63) / 64, Allocator.Persistent); + material = mat; + batchMaterialID = batchMatID; + materialGPUKey = gpuKey; + refCount = 1; + } + + public void Dispose() + { + m_BatchUsageBits.Dispose(); + } + + public bool IsUsedInBatch(int batchIndex) + { + return (m_BatchUsageBits[batchIndex / 64] & (1 << (batchIndex & 0x3f))) != 0; + } + + public void SetBatchUsage(int batchIndex, bool value) + { + int slotIdx = batchIndex / 64; + Int64 v = m_BatchUsageBits[slotIdx]; + v |= (1u << (batchIndex & 0x3f)); + m_BatchUsageBits[slotIdx] = v; + } + } + + private struct BRGMaterialDrawInfo + { + public BatchMaterialID batchMaterialID; + public GeometryPoolBatchHandle batchHandle; + public BatchID BRGBatchID; + public uint materialGPUKey; + } + + private struct BatchSlot + { + public bool valid; + public bool ready; + public GeometryPoolBatchHandle batchHandle; + public GeometryPoolBatchInstanceBuffer instanceBuffer; + public BatchID BRGBatchID; + + public static BatchSlot NewDefault() + { + return new BatchSlot() + { + valid = false, + ready = false, + batchHandle = GeometryPoolBatchHandle.Invalid, + BRGBatchID = BatchID.Null, + instanceBuffer = new GeometryPoolBatchInstanceBuffer() + }; + } + } + + public GeometryPool geometryPool { get { return m_GeometryPool; } } + + //TODO: promote this function to API, as well in SceneBRG + public unsafe static T* Malloc(int count) where T : unmanaged + { + return (T*)UnsafeUtility.Malloc( + UnsafeUtility.SizeOf() * count, + UnsafeUtility.AlignOf(), + Allocator.TempJob); + } + + [BurstCompile] + private unsafe struct DrawCommandProducerJob : IJob + { + public BatchMeshID tileMeshID; + + [ReadOnly] + public NativeList materialDrawInfos; + + public NativeArray drawCommands; + + public void Execute() + { + drawCommands[0].drawRanges[0] = new BatchDrawRange() + { + drawCommandsBegin = 0u, + drawCommandsCount = (uint)materialDrawInfos.Length, + filterSettings = new BatchFilterSettings() + { + renderingLayerMask = DeferredMaterialBRG.RenderLayerMask, + layer = 0x1, + motionMode = MotionVectorGenerationMode.Camera, + shadowCastingMode = ShadowCastingMode.Off, + receiveShadows = false, + staticShadowCaster = false, + allDepthSorted = false + } + }; + + for (int drawIndex = 0; drawIndex < (uint)materialDrawInfos.Length; ++drawIndex) + { + BRGMaterialDrawInfo drawInfo = materialDrawInfos[drawIndex]; + drawCommands[0].drawCommands[drawIndex] = new BatchDrawCommand() + { + visibleOffset = (uint)drawIndex, + visibleCount = 1u, + batchID = drawInfo.BRGBatchID, + materialID = drawInfo.batchMaterialID, + meshID = tileMeshID, + submeshIndex = 0, + splitVisibilityMask = (ushort)0xfful, + flags = BatchDrawCommandFlags.None, + sortingPosition = 0 + }; + + drawCommands[0].visibleInstances[drawIndex] = (int)((uint)(drawInfo.materialGPUKey << 8) | ((uint)drawInfo.batchHandle.index & 0xFF)); + } + } + } + + private JobHandle OnPerformCulling(BatchRendererGroup rendererGroup, BatchCullingContext cullingContext, BatchCullingOutput cullingOutput, IntPtr userContext) + { + //bake draws if they are dirty + UpdateDraws(); + + //Early quit if there is nothing to draw. + if (m_MaterialsContainer.Count == 0 || m_MaterialDrawList.Length == 0) + return new JobHandle(); + + JobHandle jobHandle; + unsafe + { + BatchCullingOutputDrawCommands drawCommands = new BatchCullingOutputDrawCommands(); + drawCommands.drawCommands = Malloc(m_MaterialDrawList.Length); + + drawCommands.visibleInstances = Malloc(m_MaterialDrawList.Length); + drawCommands.drawRanges = Malloc(1); + drawCommands.instanceSortingPositions = null; + drawCommands.drawCommandCount = m_MaterialDrawList.Length; + drawCommands.visibleInstanceCount = m_MaterialDrawList.Length; + drawCommands.drawRangeCount = 1; + drawCommands.instanceSortingPositionFloatCount = 0; + + cullingOutput.drawCommands[0] = drawCommands; + + var drawCmdProducerJob = new DrawCommandProducerJob() + { + tileMeshID = m_TileMeshID, + materialDrawInfos = m_MaterialDrawList, + drawCommands = cullingOutput.drawCommands + }; + + //TODO: this can be nicely paralelized and we can write material info in batches + jobHandle = drawCmdProducerJob.Schedule(); + } + return jobHandle; + } + + public DeferredMaterialBRG() + { + m_MaterialsContainer = new Dictionary(); + m_MaterialDrawListDirty = false; + m_BatchRendererGroup = new BatchRendererGroup(this.OnPerformCulling, IntPtr.Zero); + m_GeometryPool = new GeometryPool(GeometryPoolDesc.NewDefault()); + m_MaterialDrawList = new NativeList(1024, Allocator.Persistent); + + m_Batches = new BatchSlot[m_GeometryPool.maxBatchCount]; + for (int i = 0; i < m_GeometryPool.maxBatchCount; ++i) + m_Batches[i] = BatchSlot.NewDefault(); + + m_BatchHandles = new NativeList(m_GeometryPool.maxBatchCount, Allocator.Persistent); + + int tilesX = ((3 * 3840) + MaterialTileSize - 1) / MaterialTileSize; + int tilesY = ((3 * 2160) + MaterialTileSize - 1) / MaterialTileSize; + m_MaxNumberOfTiles = tilesX * tilesY; + + m_TileMesh = new Mesh(); + m_TileMesh.vertices = new Vector3[m_MaxNumberOfTiles * 4]; + m_TileMesh.vertexBufferTarget = GraphicsBuffer.Target.Raw; + m_TileMesh.indexBufferTarget = GraphicsBuffer.Target.Raw; + m_TileMesh.subMeshCount = 1; + m_TileMesh.SetIndexBufferParams(m_MaxNumberOfTiles * 6, IndexFormat.UInt16); + m_TileMesh.SetSubMesh(0, new SubMeshDescriptor(0, m_MaxNumberOfTiles * 6), MeshUpdateFlags.DontValidateIndices | MeshUpdateFlags.DontNotifyMeshUsers | MeshUpdateFlags.DontRecalculateBounds); + var indices = new int[m_MaxNumberOfTiles * 6]; + for (int tileId = 0; tileId < m_MaxNumberOfTiles; ++tileId) + { + indices[tileId * 6 + 0] = 0 + tileId * 4; + indices[tileId * 6 + 1] = 1 + tileId * 4; + indices[tileId * 6 + 2] = 3 + tileId * 4; + indices[tileId * 6 + 3] = 3 + tileId * 4; + indices[tileId * 6 + 4] = 2 + tileId * 4; + indices[tileId * 6 + 5] = 0 + tileId * 4; + } + m_TileMesh.SetIndices(indices, MeshTopology.Triangles, 0); + m_TileMesh.UploadMeshData(false); + m_TileMeshID = m_BatchRendererGroup.RegisterMesh(m_TileMesh); + } + + public bool CreateBatch(int numberOfInstances, out GeometryPoolBatchHandle outHandle) + { + var batchSlot = BatchSlot.NewDefault(); + outHandle = GeometryPoolBatchHandle.Invalid; + + if (batchSlot.ready) + return false; + + if (!m_GeometryPool.CreateBatch(numberOfInstances, out batchSlot.batchHandle)) + return false; + + batchSlot.instanceBuffer = m_GeometryPool.CreateGeometryPoolBatchInstanceBuffer(batchSlot.batchHandle, isPersistant: true); + batchSlot.valid = true; + + outHandle = batchSlot.batchHandle; + Assertions.Assert.IsTrue(!m_Batches[outHandle.index].valid); + + m_Batches[outHandle.index] = batchSlot; + m_BatchHandles.Add(outHandle); + return true; + } + + public void DestroyBatch(GeometryPoolBatchHandle batchHandle) + { + if (!batchHandle.valid) + return; + + Assertions.Assert.IsTrue(m_Batches[batchHandle.index].valid); + Assertions.Assert.IsTrue(m_Batches[batchHandle.index].batchHandle.index == batchHandle.index); + var batchSlot = m_Batches[batchHandle.index]; + + if (batchSlot.instanceBuffer.valid) + { + foreach (var instanceHandleIdx in batchSlot.instanceBuffer.instanceValues) + UnregisterInstanceAndMaterials(batchHandle, new GeometryPoolHandle { index = instanceHandleIdx }); + batchSlot.instanceBuffer.Dispose(); + } + + if (batchSlot.batchHandle.valid) + m_GeometryPool.DestroyBatch(batchSlot.batchHandle); + + m_Batches[batchHandle.index] = BatchSlot.NewDefault(); + for (int i = 0; i < m_BatchHandles.Length; ++i) + { + if (m_BatchHandles[i].index == batchHandle.index) + { + m_BatchHandles.RemoveAtSwapBack(i); + break; + } + } + } + + public void UnregisterInstanceAndMaterials(GeometryPoolBatchHandle batchHandle, GeometryPoolHandle handle) + { + var entryInfo = m_GeometryPool.GetEntryInfo(handle); + m_MaterialDrawListDirty = true; + if (entryInfo.materialHashes.IsCreated) + { + foreach (var materialHash in entryInfo.materialHashes) + { + if (!m_MaterialsContainer.TryGetValue(materialHash, out var matInfo)) + continue; + + --matInfo.refCount; + matInfo.SetBatchUsage(batchHandle.index, false); + if (matInfo.refCount == 0) + { + m_BatchRendererGroup.UnregisterMaterial(matInfo.batchMaterialID); + matInfo.Dispose(); + m_MaterialsContainer.Remove(materialHash); + } + else + { + m_MaterialsContainer[materialHash] = matInfo; + } + } + } + m_GeometryPool.Unregister(handle); + + } + + public bool RegisterInstance(GeometryPoolBatchHandle batchHandle, int instanceIndex, in GeometryPoolEntryDesc desc, out GeometryPoolHandle geoHandle) + { + geoHandle = GeometryPoolHandle.Invalid; + if (!batchHandle.valid) + return false; + + var batchSlot = m_Batches[batchHandle.index]; + if (!batchSlot.valid || batchSlot.ready) + return false; + + if (!m_GeometryPool.Register(desc, out geoHandle)) + return false; + + if (geoHandle.index >= 0xFFFF) + { + Debug.LogError("Geo handle count for batch exceeding 16 bits."); + m_GeometryPool.Unregister(geoHandle); + return false; + } + + batchSlot.instanceBuffer.instanceValues[instanceIndex] = (short)geoHandle.index; + + foreach (var submeshData in desc.submeshData) + { + if (submeshData.material == null) + continue; + + int materialHashCode = submeshData.material.GetHashCode(); + if (m_MaterialsContainer.TryGetValue(materialHashCode, out var matInfo)) + { + ++matInfo.refCount; + matInfo.SetBatchUsage(batchHandle.index, true); + m_MaterialsContainer[materialHashCode] = matInfo; + } + else + { + BatchMaterialID batchMaterialID = m_BatchRendererGroup.RegisterMaterial(submeshData.material); + GeometryPoolMaterialEntry entry = m_GeometryPool.globalMaterialEntries[submeshData.material.GetHashCode()]; + uint materialGPUKey = entry.materialGPUKey; + var newMatInfo = new BRGMaterialInfo(); + newMatInfo.Initialize(m_GeometryPool.maxBatchCount, entry.material, batchMaterialID, materialGPUKey); + newMatInfo.SetBatchUsage(batchHandle.index, true); + m_MaterialsContainer.Add(materialHashCode, newMatInfo); + + } + } + return true; + } + + public void SubmitBatch(GeometryPoolBatchHandle batchHandle, NativeArray batchMetadata, GraphicsBufferHandle batchBuffer) + { + if (!batchHandle.valid) + return; + + var batchSlot = m_Batches[batchHandle.index]; + if (batchSlot.ready) + return; + + m_GeometryPool.SetBatchInstanceData(batchHandle, batchSlot.instanceBuffer); + m_Batches[batchHandle.index] = batchSlot; + + if (batchSlot.BRGBatchID != BatchID.Null) + m_BatchRendererGroup.RemoveBatch(batchSlot.BRGBatchID); + batchSlot.BRGBatchID = m_BatchRendererGroup.AddBatch(batchMetadata, batchBuffer); + + batchSlot.ready = true; + m_Batches[batchHandle.index] = batchSlot; + m_GeometryPool.SendGpuCommands(); + m_MaterialDrawListDirty = true; + } + + private void UpdateDraws() + { + if (!m_MaterialDrawListDirty) + return; + + m_MaterialDrawList.Clear(); + foreach (var batchHandle in m_BatchHandles) + { + var batchSlot = m_Batches[batchHandle.index]; + foreach (var pair in m_MaterialsContainer) + { + var materialInfo = pair.Value; + if (!materialInfo.IsUsedInBatch(batchHandle.index)) + continue; + + m_MaterialDrawList.Add(new BRGMaterialDrawInfo() + { + batchMaterialID = materialInfo.batchMaterialID, + batchHandle = batchHandle, + materialGPUKey = materialInfo.materialGPUKey, + BRGBatchID = batchSlot.BRGBatchID + }); + } + } + + m_MaterialDrawListDirty = false; + } + + public void Dispose() + { + foreach (var b in m_Batches) + { + if (b.valid) + DestroyBatch(b.batchHandle); + } + + m_Batches = null; + m_BatchHandles.Dispose(); + m_BatchRendererGroup.Dispose(); + m_GeometryPool.Dispose(); + m_MaterialDrawList.Dispose(); + } + } + +} diff --git a/com.unity.render-pipelines.core/Runtime/BatchRenderer/DeferredMaterialBRG.cs.meta b/com.unity.render-pipelines.core/Runtime/BatchRenderer/DeferredMaterialBRG.cs.meta new file mode 100644 index 00000000000..48850294e65 --- /dev/null +++ b/com.unity.render-pipelines.core/Runtime/BatchRenderer/DeferredMaterialBRG.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: 0cf4ecbd94860bc48aaacce1d5a5ef2e +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.core/Runtime/BatchRenderer/RenderBRG.cs b/com.unity.render-pipelines.core/Runtime/BatchRenderer/RenderBRG.cs index c9e43b54c59..d5280e8eb1b 100644 --- a/com.unity.render-pipelines.core/Runtime/BatchRenderer/RenderBRG.cs +++ b/com.unity.render-pipelines.core/Runtime/BatchRenderer/RenderBRG.cs @@ -137,13 +137,6 @@ internal struct BRGInstanceBufferOffsets public int probeOffsetOcclusion; } - struct DeferredMaterialInstance - { - public int instanceIndex; - public int meshHashCode; - public GeometryPoolHandle geoPoolHandle; - } - unsafe class SceneBRG { private BatchRendererGroup m_BatchRendererGroup; @@ -162,12 +155,12 @@ unsafe class SceneBRG private NativeArray m_instanceIndices; private NativeArray m_drawIndices; private BRGInstanceBufferOffsets m_instanceBufferOffsets; - private NativeList m_deferredMaterialInstances; private LightMaps m_Lightmaps; private BRGTransformUpdater m_BRGTransformUpdater = new BRGTransformUpdater(); - private GeometryPool m_GlobalGeoPool = null; + private DeferredMaterialBRG m_DeferredMaterialBRG = null; + GeometryPoolBatchHandle m_DeferredMaterialBatch = GeometryPoolBatchHandle.Invalid; private List m_AddedRenderers; @@ -750,7 +743,7 @@ public JobHandle OnPerformCulling(BatchRendererGroup rendererGroup, BatchCulling return jobHandleOutput; } - private void ProcessUsedMeshAndMaterialDataFromGameObjects( + private bool ProcessUsedMeshAndMaterialDataFromGameObjects( RenderPipelineAsset activePipelineAsset, RenderBRGGetMaterialRenderInfoCallback onGetMaterialInfoCb, int instanceIndex, @@ -788,6 +781,9 @@ private void ProcessUsedMeshAndMaterialDataFromGameObjects( material = matToUse }); + if (!visMaterialInfo.supportsBRGRendering) + return false; + if (visMaterialInfo.supportsVisibility && visMaterialInfo.materialOverride != null) { Assert.IsTrue( @@ -806,32 +802,41 @@ private void ProcessUsedMeshAndMaterialDataFromGameObjects( //Special case, if the renderer qualifies for deferred materials, go for it! //TODO: for now we just handle 1 case, if the entire renderer can be deferred material. - if (overrideMaterial != null && overrideCounts == outMaterials.Count && m_GlobalGeoPool != null) + if (overrideMaterial != null && overrideCounts == outMaterials.Count && m_DeferredMaterialBatch.valid) { - m_GlobalGeoPool.Register(outMesh, out GeometryPoolHandle geoPoolHandle); - if (!geoPoolHandle.valid) - return; + GeometryPoolEntryDesc geoPoolEntryDesc = new GeometryPoolEntryDesc() + { + mesh = outMesh, + submeshData = outSubmeshIndices.Count != 0u ? new GeometryPoolSubmeshData[outSubmeshIndices.Count] : null + }; - if (!m_deferredMaterialInstances.IsCreated) - m_deferredMaterialInstances = new NativeList(1024, Allocator.Persistent); + for (int i = 0; i < outSubmeshIndices.Count; ++i) + { + geoPoolEntryDesc.submeshData[i] = new GeometryPoolSubmeshData() + { + submeshIndex = outSubmeshIndices[i], + material = outMaterials[i] + }; + } - m_deferredMaterialInstances.Add(new DeferredMaterialInstance() + GeometryPoolHandle geoHandle = GeometryPoolHandle.Invalid; + if (!m_DeferredMaterialBRG.RegisterInstance(m_DeferredMaterialBatch, instanceIndex, geoPoolEntryDesc, out geoHandle)) { - instanceIndex = instanceIndex, - meshHashCode = outMesh.GetHashCode(), - geoPoolHandle = geoPoolHandle - }); + Debug.LogError("Could not register instance into deferred material batch: ." + renderer); + return true; + } - deferredMaterialBuffer[deferredMaterialBufferOffset + instanceIndex] = new Vector4((float)geoPoolHandle.index, 0.0f, 0.0f, 0.0f); + deferredMaterialBuffer[deferredMaterialBufferOffset + instanceIndex] = new Vector4((float)geoHandle.index, m_DeferredMaterialBatch.index, 0.0f, 0.0f); //We succeeded! lets override the mesh / submesh index and material. outSubmeshIndices.Clear(); outMaterials.Clear(); outMaterials.Add(overrideMaterial); - outSubmeshIndices.Add(geoPoolHandle.index); - outMesh = m_GlobalGeoPool.globalMesh; - + outSubmeshIndices.Add(geoHandle.index); + outMesh = m_DeferredMaterialBRG.globalGeoMesh; } + + return true; } private void SanityCheckDrawInstanceCounts() @@ -856,7 +861,7 @@ private void SanityCheckDrawInstanceCounts() } // Start is called before the first frame update - public void Initialize(List renderers, GeometryPool geometryPool) + public void Initialize(List renderers, DeferredMaterialBRG deferredMaterialBRG) { m_BatchRendererGroup = new BatchRendererGroup(this.OnPerformCulling, IntPtr.Zero); m_BRGTransformUpdater.Initialize(); @@ -872,7 +877,7 @@ public void Initialize(List renderers, GeometryPool geometryPool) m_drawBatches = new NativeList(Allocator.Persistent); m_drawRanges = new NativeList(Allocator.Persistent); m_AddedRenderers = new List(renderersLength); - m_GlobalGeoPool = geometryPool; + m_DeferredMaterialBRG = deferredMaterialBRG; // Fill the GPU-persistent scene data ComputeBuffer int bigDataBufferVector4Count = @@ -937,6 +942,11 @@ public void Initialize(List renderers, GeometryPool geometryPool) LightProbesQuery lpq = new LightProbesQuery(Allocator.Temp); bool useFirstMeshForAll = false; // Hack to help benchmarking different bottlenecks. TODO: Remove! MeshFilter firstMesh = null; + if (m_DeferredMaterialBRG != null) + { + if (!m_DeferredMaterialBRG.CreateBatch(renderers.Count, out m_DeferredMaterialBatch)) + Debug.LogError("Could not allocate batch for this scene, not enough gpu memory allocated."); + } RenderBRGGetMaterialRenderInfoCallback onGetMaterialInfoCb = RenderBRG.GetActiveMaterialRenderInfoCallback(out RenderPipelineAsset activePipeline); @@ -956,6 +966,15 @@ public void Initialize(List renderers, GeometryPool geometryPool) firstMesh = meshFilter; } + Mesh usedMesh = null; + var usedSubmeshIndices = new List(); + var usedMaterials = new List(); + if (!ProcessUsedMeshAndMaterialDataFromGameObjects( + activePipeline, onGetMaterialInfoCb, i, renderer, meshFilter, rendererMaterialInfos, + deferredMaterialDataOffset, vectorBuffer, + ref usedMesh, usedSubmeshIndices, usedMaterials)) + continue; + m_AddedRenderers.Add(renderer); // Disable the existing Unity MeshRenderer to avoid double rendering! @@ -1001,14 +1020,6 @@ public void Initialize(List renderers, GeometryPool geometryPool) m_BRGTransformUpdater.RegisterTransformObject(i, rendererTransform, meshFilter.sharedMesh, renderer.lightProbeUsage == LightProbeUsage.BlendProbes); - Mesh usedMesh = null; - var usedSubmeshIndices = new List(); - var usedMaterials = new List(); - ProcessUsedMeshAndMaterialDataFromGameObjects( - activePipeline, onGetMaterialInfoCb, i, renderer, meshFilter, rendererMaterialInfos, - deferredMaterialDataOffset, vectorBuffer, - ref usedMesh, usedSubmeshIndices, usedMaterials); - var mesh = m_BatchRendererGroup.RegisterMesh(usedMesh); // Different renderer settings? -> new draw range @@ -1082,9 +1093,6 @@ public void Initialize(List renderers, GeometryPool geometryPool) } } - if (m_GlobalGeoPool != null) - m_GlobalGeoPool.SendGpuCommands(); - m_GPUPersistentInstanceData = new GraphicsBuffer(GraphicsBuffer.Target.Raw, (int)bigDataBufferVector4Count * 16 / 4, 4); m_GPUPersistentInstanceData.SetData(vectorBuffer); @@ -1195,6 +1203,9 @@ public void Initialize(List renderers, GeometryPool geometryPool) // Register batch m_batchID = m_BatchRendererGroup.AddBatch(batchMetadata, m_GPUPersistentInstanceData.bufferHandle); + if (m_DeferredMaterialBatch.valid) + m_DeferredMaterialBRG.SubmitBatch(m_DeferredMaterialBatch, batchMetadata, m_GPUPersistentInstanceData.bufferHandle); + m_initialized = true; } @@ -1235,14 +1246,10 @@ public void Destroy() added.forceRenderingOff = false; } - if (m_deferredMaterialInstances.IsCreated) + if (m_DeferredMaterialBatch.valid) { - foreach (var deferredInstance in m_deferredMaterialInstances) - { - m_GlobalGeoPool.UnregisterByMeshHashCode(deferredInstance.meshHashCode); - } - m_GlobalGeoPool.SendGpuCommands(); - m_deferredMaterialInstances.Dispose(); + m_DeferredMaterialBRG.DestroyBatch(m_DeferredMaterialBatch); + m_DeferredMaterialBatch = GeometryPoolBatchHandle.Invalid; } } } @@ -1250,6 +1257,7 @@ public void Destroy() public struct RenderBRGMaterialRenderInfo { + public bool supportsBRGRendering; public bool supportsVisibility; public Material materialOverride; } @@ -1264,6 +1272,21 @@ public struct RenderBRGGetMaterialRenderInfoArgs public delegate RenderBRGMaterialRenderInfo RenderBRGGetMaterialRenderInfoCallback(RenderBRGGetMaterialRenderInfoArgs arguments); + public struct RenderBRGBindingData + { + public GeometryPool globalGeometryPool; + + public bool valid => globalGeometryPool != null; + + public static RenderBRGBindingData NewDefault() + { + return new RenderBRGBindingData() + { + globalGeometryPool = null + }; + } + } + public class RenderBRG : MonoBehaviour { private static Dictionary s_SrpMatInfoCallbacks = new(); @@ -1293,26 +1316,20 @@ internal static RenderBRGGetMaterialRenderInfoCallback GetActiveMaterialRenderIn public bool EnableTransformUpdate = true; private GeometryPool m_GlobalGeoPool; - public static GeometryPool FindGlobalGeometryPool() - { - RenderBRG[] brgers = Resources.FindObjectsOfTypeAll(); - if (brgers == null) - return null; + private static uint s_DeferredMaterialBRGRef = 0; + private static DeferredMaterialBRG s_DeferredMaterialBRG; - foreach (var brg in brgers) + public static RenderBRGBindingData GetRenderBRGMaterialBindingData() + { + return new RenderBRGBindingData() { - if (brg.m_GlobalGeoPool != null) - return brg.m_GlobalGeoPool; - } - - return null; + globalGeometryPool = s_DeferredMaterialBRG == null ? null : s_DeferredMaterialBRG.geometryPool + }; } private void OnEnable() { - var globalGeoPool = FindGlobalGeometryPool(); - if (EnableDeferredMaterials && globalGeoPool == null && m_GlobalGeoPool == null) - m_GlobalGeoPool = new GeometryPool(GeometryPoolDesc.NewDefault()); + CreateDeferredMaterialBRG(); m_gpuCmdBuffer = new CommandBuffer(); SceneManager.sceneLoaded += OnSceneLoaded; @@ -1356,6 +1373,31 @@ private void OnDisable() foreach (var scene in toNull) m_Scenes[scene] = null; + + DisposeDeferredMaterialBRG(); + } + + private void CreateDeferredMaterialBRG() + { + if (!EnableDeferredMaterials) + return; + if (s_DeferredMaterialBRGRef == 0) + s_DeferredMaterialBRG = new DeferredMaterialBRG(); + ++s_DeferredMaterialBRGRef; + } + + private void DisposeDeferredMaterialBRG() + { + if (s_DeferredMaterialBRG == null) + return; + + --s_DeferredMaterialBRGRef; + + if (s_DeferredMaterialBRGRef > 0) + return; + + s_DeferredMaterialBRG.Dispose(); + s_DeferredMaterialBRG = null; } private static void GetValidChildRenderers(GameObject root, List toAppend) @@ -1390,7 +1432,7 @@ private void OnSceneLoaded(Scene scene, LoadSceneMode mode) Debug.Log("Loading scene: " + scene.name); #endif SceneBRG brg = new SceneBRG(); - brg.Initialize(renderers, RenderBRG.FindGlobalGeometryPool()); + brg.Initialize(renderers, s_DeferredMaterialBRG); m_Scenes[scene] = brg; } @@ -1440,11 +1482,7 @@ private void OnDestroy() m_Scenes.Clear(); - if (m_GlobalGeoPool != null) - { - m_GlobalGeoPool.Dispose(); - m_GlobalGeoPool = null; - } + DisposeDeferredMaterialBRG(); } } } diff --git a/com.unity.render-pipelines.core/Runtime/GeometryPool/GeometryPool.cs b/com.unity.render-pipelines.core/Runtime/GeometryPool/GeometryPool.cs index d95f7b58084..1ff39dfe3f6 100644 --- a/com.unity.render-pipelines.core/Runtime/GeometryPool/GeometryPool.cs +++ b/com.unity.render-pipelines.core/Runtime/GeometryPool/GeometryPool.cs @@ -1,3 +1,4 @@ +using System; using System.Collections.Generic; using Unity.Collections; using UnityEngine.VFX; @@ -18,6 +19,7 @@ public struct GeometryPoolDesc public int indexPoolByteSize; public int subMeshLookupPoolByteSize; public int subMeshEntryPoolByteSize; + public int batchInstancePoolByteSize; public int maxMeshes; public static GeometryPoolDesc NewDefault() @@ -28,16 +30,82 @@ public static GeometryPoolDesc NewDefault() indexPoolByteSize = 16 * 1024 * 1024, //16 mb subMeshLookupPoolByteSize = 3 * 1024 * 1024, // 3mb subMeshEntryPoolByteSize = 2 * 1024 * 1024, // 2mb + batchInstancePoolByteSize = 4 * 1024 * 1024, //4 mb maxMeshes = 4096 }; } } - public struct GeometryPoolHandle + public struct GeometryPoolHandle : IEquatable { public int index; public static GeometryPoolHandle Invalid = new GeometryPoolHandle() { index = -1 }; public bool valid => index != -1; + public bool Equals(GeometryPoolHandle other) => index == other.index; + } + + public struct GeometryPoolBatchHandle : IEquatable + { + public int index; + public static GeometryPoolBatchHandle Invalid = new GeometryPoolBatchHandle() { index = -1 }; + public bool valid => index != -1; + public bool Equals(GeometryPoolBatchHandle other) => index == other.index; + } + + public struct GeometryPoolEntryInfo + { + public bool valid; + public int refCount; + public NativeArray materialHashes; + + public static GeometryPoolEntryInfo NewDefault() + { + return new GeometryPoolEntryInfo() + { + valid = false, + refCount = 0 + }; + } + } + + public struct GeometryPoolSubmeshData + { + public int submeshIndex; + public Material material; + } + + public struct GeometryPoolEntryDesc + { + public Mesh mesh; + public GeometryPoolSubmeshData[] submeshData; + } + + public struct GeometryPoolMaterialEntry + { + public uint materialGPUKey; + public int refCount; + public Material material; + + public static GeometryPoolMaterialEntry NewDefault() + { + return new GeometryPoolMaterialEntry() + { + materialGPUKey = 0, + refCount = 0, + material = null + }; + } + } + + public struct GeometryPoolBatchInstanceBuffer + { + public NativeArray instanceValues; + public bool valid => instanceValues.IsCreated; + public void Dispose() + { + if (valid) + instanceValues.Dispose(); + } } public class GeometryPool @@ -51,7 +119,8 @@ private static class GeoPoolShaderIDs public static readonly int _GeoVertexOffset = Shader.PropertyToID("_GeoVertexOffset"); public static readonly int _GeoIndexOffset = Shader.PropertyToID("_GeoIndexOffset"); public static readonly int _GeoSubMeshLookupOffset = Shader.PropertyToID("_GeoSubMeshLookupOffset"); - public static readonly int _GeoSubMeshEntryOffset = Shader.PropertyToID("_GeoSubMeshEntryOffset"); + public static readonly int _GeoSubMeshEntryOffset_VertexFlags = Shader.PropertyToID("_GeoSubMeshEntryOffset_VertexFlags"); + public static readonly int _InputSubMeshMaterialKey = Shader.PropertyToID("_InputSubMeshMaterialKey"); public static readonly int _InputVBCount = Shader.PropertyToID("_InputVBCount"); public static readonly int _OutputVBSize = Shader.PropertyToID("_OutputVBSize"); public static readonly int _OutputVBOffset = Shader.PropertyToID("_OutputVBOffset"); @@ -76,7 +145,11 @@ private static class GeoPoolShaderIDs public static readonly int _OutputGeoMetadataBuffer = Shader.PropertyToID("_OutputGeoMetadataBuffer"); public static readonly int _GeoPoolGlobalVertexBuffer = Shader.PropertyToID("_GeoPoolGlobalVertexBuffer"); public static readonly int _GeoPoolGlobalIndexBuffer = Shader.PropertyToID("_GeoPoolGlobalIndexBuffer"); + public static readonly int _GeoPoolGlobalSubMeshLookupBuffer = Shader.PropertyToID("_GeoPoolGlobalSubMeshLookupBuffer"); + public static readonly int _GeoPoolGlobalSubMeshEntryBuffer = Shader.PropertyToID("_GeoPoolGlobalSubMeshEntryBuffer"); public static readonly int _GeoPoolGlobalMetadataBuffer = Shader.PropertyToID("_GeoPoolGlobalMetadataBuffer"); + public static readonly int _GeoPoolGlobalBatchTableBuffer = Shader.PropertyToID("_GeoPoolGlobalBatchTableBuffer"); + public static readonly int _GeoPoolGlobalBatchInstanceBuffer = Shader.PropertyToID("_GeoPoolGlobalBatchInstanceBuffer"); public static readonly int _GeoPoolGlobalParams = Shader.PropertyToID("_GeoPoolGlobalParams"); public static readonly int _OutputSubMeshLookupBuffer = Shader.PropertyToID("_OutputSubMeshLookupBuffer"); public static readonly int _OutputSubMeshEntryBuffer = Shader.PropertyToID("_OutputSubMeshEntryBuffer"); @@ -96,8 +169,7 @@ private static class GeoPoolShaderIDs private struct MeshSlot { public int refCount; - public int meshHash; - public GeometryPoolHandle geometryHandle; + public uint meshHash; } private struct GeometrySlot @@ -123,6 +195,8 @@ private struct GeometrySlot public static int GetSubMeshLookupByteSize() => 1; //1 byte. public static int GetSubMeshEntryByteSize() => System.Runtime.InteropServices.Marshal.SizeOf(); public static int GetGeoMetadataByteSize() => System.Runtime.InteropServices.Marshal.SizeOf(); + public static int GetGeoBatchInstancesInfoByteSize() => System.Runtime.InteropServices.Marshal.SizeOf(); + public static int GetGeoBatchInstancesDataByteSize() => GeometryPoolConstants.GeoPoolBatchInstanceDataByteSize; private int GetFormatByteCount(VertexAttributeFormat format) { @@ -154,32 +228,44 @@ private int GetFormatByteCount(VertexAttributeFormat format) public ComputeBuffer globalSubMeshLookupBuffer { get { return m_GlobalSubMeshLookupBuffer; } } public ComputeBuffer globalSubMeshEntryBuffer { get { return m_GlobalSubMeshEntryBuffer; } } public ComputeBuffer globalMetadataBuffer { get { return m_GlobalGeoMetadataBuffer; } } + public ComputeBuffer globalBatchTableBuffer { get { return m_GlobalBatchTableBuffer; } } + public ComputeBuffer globalBatchInstanceBuffer { get { return m_GlobalBatchInstanceBuffer; } } + public Dictionary globalMaterialEntries { get { return m_MaterialEntries; } } public int maxMeshes => m_Desc.maxMeshes; public int indicesCount => m_MaxIndexCounts; public int verticesCount => m_MaxVertCounts; public int subMeshLookupCount => m_MaxSubMeshLookupCounts; public int subMeshEntryCount => m_MaxSubMeshEntryCounts; + public int maxBatchCount => m_MaxBatchCount; + public int maxBatchInstanceCount => m_MaxBatchInstanceCount; private GraphicsBuffer m_GlobalIndexBuffer = null; private ComputeBuffer m_GlobalVertexBuffer = null; private ComputeBuffer m_GlobalSubMeshLookupBuffer = null; private ComputeBuffer m_GlobalSubMeshEntryBuffer = null; private ComputeBuffer m_GlobalGeoMetadataBuffer = null; + private ComputeBuffer m_GlobalBatchTableBuffer = null; + private ComputeBuffer m_GlobalBatchInstanceBuffer = null; private int m_MaxVertCounts; private int m_MaxIndexCounts; private int m_MaxSubMeshLookupCounts; private int m_MaxSubMeshEntryCounts; + private int m_MaxBatchCount; + private int m_MaxBatchInstanceCount; private BlockAllocator m_VertexAllocator; private BlockAllocator m_IndexAllocator; private BlockAllocator m_SubMeshLookupAllocator; private BlockAllocator m_SubMeshEntryAllocator; - private NativeHashMap m_MeshSlots; + private NativeHashMap m_MeshSlots; + private Dictionary> m_MaterialHashes; + private NativeHashMap m_MeshHashToHandle; private NativeList m_GeoSlots; private NativeList m_FreeGeoSlots; + private Dictionary m_MaterialEntries; private List m_InputBufferReferences; @@ -197,6 +283,12 @@ private int GetFormatByteCount(VertexAttributeFormat format) private bool m_MustClearCmdBuffer; private int m_PendingCmds; + private uint m_NextMaterialGPUKey; + + private NativeArray m_BatchTable; + private NativeArray m_BatchTableAllocations; + private BlockAllocator m_BatchInstancesAllocator; + public GeometryPool(in GeometryPoolDesc desc) { LoadShaders(); @@ -227,10 +319,25 @@ public GeometryPool(in GeometryPoolDesc desc) m_GlobalSubMeshEntryBuffer = new ComputeBuffer(m_MaxSubMeshEntryCounts, GetSubMeshEntryByteSize(), ComputeBufferType.Structured); m_GlobalGeoMetadataBuffer = new ComputeBuffer(m_Desc.maxMeshes, GetGeoMetadataByteSize(), ComputeBufferType.Structured); + m_MaxBatchCount = 256; //up to 256 batches, 8 bits per batch index. + m_GlobalBatchTableBuffer = new ComputeBuffer(m_MaxBatchCount, GetGeoBatchInstancesInfoByteSize(), ComputeBufferType.Structured); + m_BatchTable = new NativeArray(m_MaxBatchCount, Allocator.Persistent); + m_BatchTableAllocations = new NativeArray(m_MaxBatchCount, Allocator.Persistent); + for (int i = 0; i < m_MaxBatchCount; ++i) + m_BatchTableAllocations[i] = BlockAllocator.Allocation.Invalid; + + m_MaxBatchInstanceCount = DivUp(m_Desc.batchInstancePoolByteSize, GetGeoBatchInstancesDataByteSize()); + m_BatchInstancesAllocator = new BlockAllocator(); + m_BatchInstancesAllocator.Initialize(m_MaxBatchInstanceCount); + m_GlobalBatchInstanceBuffer = new ComputeBuffer(DivUp(m_MaxBatchInstanceCount * GetGeoBatchInstancesDataByteSize(), 4), 4, ComputeBufferType.Raw); + Assertions.Assert.IsTrue(m_GlobalIndexBuffer != null); Assertions.Assert.IsTrue((m_GlobalIndexBuffer.target & GraphicsBuffer.Target.Raw) != 0); - m_MeshSlots = new NativeHashMap(desc.maxMeshes, Allocator.Persistent); + m_MeshSlots = new NativeHashMap(desc.maxMeshes, Allocator.Persistent); + m_MaterialHashes = new Dictionary>(); + m_MeshHashToHandle = new NativeHashMap(desc.maxMeshes, Allocator.Persistent); + m_GeoSlots = new NativeList(Allocator.Persistent); m_FreeGeoSlots = new NativeList(Allocator.Persistent); @@ -245,6 +352,9 @@ public GeometryPool(in GeometryPoolDesc desc) m_SubMeshEntryAllocator = new BlockAllocator(); m_SubMeshEntryAllocator.Initialize(m_MaxSubMeshEntryCounts); + + m_MaterialEntries = new Dictionary(); + m_NextMaterialGPUKey = 0x1; } public void DisposeInputBuffers() @@ -264,15 +374,28 @@ public void Dispose() m_SubMeshLookupAllocator.Dispose(); m_SubMeshEntryAllocator.Dispose(); + m_BatchTable.Dispose(); + m_BatchTableAllocations.Dispose(); + m_BatchInstancesAllocator.Dispose(); + m_FreeGeoSlots.Dispose(); m_GeoSlots.Dispose(); m_MeshSlots.Dispose(); + foreach (var p in m_MaterialHashes) + { + if (p.Value.IsCreated) + p.Value.Dispose(); + } + m_MaterialHashes = null; + m_MeshHashToHandle.Dispose(); m_GlobalIndexBuffer.Dispose(); m_GlobalVertexBuffer.Release(); m_GlobalSubMeshLookupBuffer.Dispose(); m_GlobalSubMeshEntryBuffer.Dispose(); m_GlobalGeoMetadataBuffer.Dispose(); + m_GlobalBatchTableBuffer.Dispose(); + m_GlobalBatchInstanceBuffer.Dispose(); m_CmdBuffer.Release(); CoreUtils.Destroy(globalMesh); @@ -383,6 +506,23 @@ private bool AllocateGeo(int vertexCount, int indexCount, int subMeshEntries, ou return true; } + public GeometryPoolEntryInfo GetEntryInfo(GeometryPoolHandle handle) + { + if (m_MeshSlots.TryGetValue(handle, out MeshSlot slot)) + { + NativeArray materialHashes; + m_MaterialHashes.TryGetValue(handle, out materialHashes); + return new GeometryPoolEntryInfo() + { + valid = true, + refCount = slot.refCount, + materialHashes = materialHashes + }; + } + + return GeometryPoolEntryInfo.NewDefault(); + } + private void DeallocateGeo(GeometryPoolHandle handle) { if (!handle.valid) @@ -395,7 +535,7 @@ private void DeallocateGeo(GeometryPoolHandle handle) m_GeoSlots[handle.index] = slot; } - private void UpdateGeoGpuState(Mesh mesh, GeometryPoolHandle handle) + private void UpdateGeoGpuState(Mesh mesh, NativeArray materialKeys, GeometryPoolHandle handle) { var geoSlot = m_GeoSlots[handle.index]; CommandBuffer cmdBuffer = AllocateCommandBuffer(); //clear any previous cmd buffers. @@ -431,10 +571,12 @@ private void UpdateGeoGpuState(Mesh mesh, GeometryPoolHandle handle) if (tBuffer != null) Assertions.Assert.IsTrue(tBuffer != null); + + GeoPoolInputFlags vertexFlags = GeoPoolInputFlags.None; AddVertexUpdateCommand( cmdBuffer, posBuffer, uvBuffer, uv1Buffer, nBuffer, tBuffer, posStride, posOffset, uvStride, uvOffset, uv1Stride, uv1Offset, nStride, nOffset, tStride, tOffset, - geoSlot.vertexAlloc, m_GlobalVertexBuffer); + geoSlot.vertexAlloc, out vertexFlags, m_GlobalVertexBuffer); { AddClearSubMeshDataBuffer( @@ -447,6 +589,7 @@ private void UpdateGeoGpuState(Mesh mesh, GeometryPoolHandle handle) int subMeshIndexOffset = 0; for (int subMeshId = 0; subMeshId < mesh.subMeshCount; ++subMeshId) { + uint materialKey = materialKeys.IsCreated && subMeshId < materialKeys.Length ? materialKeys[subMeshId] : 0; SubMeshDescriptor submeshDescriptor = mesh.GetSubMesh(subMeshId); //Update submeshLookup AddSubMeshDataUpdateCommand( @@ -454,6 +597,7 @@ private void UpdateGeoGpuState(Mesh mesh, GeometryPoolHandle handle) subMeshId, subMeshIndexOffset, submeshDescriptor, + materialKey, geoSlot.subMeshLookupAlloc, geoSlot.subMeshEntryAlloc, m_GlobalSubMeshLookupBuffer, @@ -467,26 +611,194 @@ private void UpdateGeoGpuState(Mesh mesh, GeometryPoolHandle handle) //Update metadata buffer AddMetadataUpdateCommand( cmdBuffer, handle.index, - new GeoPoolMetadataEntry() + PackGpuGeoPoolMetadataEntry(geoSlot, vertexFlags), m_GlobalGeoMetadataBuffer); + } + + private GeoPoolMetadataEntry PackGpuGeoPoolMetadataEntry(in GeometrySlot geoSlot, GeoPoolInputFlags vertexFlags) + { + return new GeoPoolMetadataEntry() + { + vertexOffset = geoSlot.vertexAlloc.block.offset, + indexOffset = geoSlot.indexAlloc.block.offset, + subMeshLookupOffset = geoSlot.subMeshLookupAlloc.block.offset, + subMeshEntryOffset_VertexFlags = (int)((geoSlot.subMeshEntryAlloc.block.offset << 16) | ((int)vertexFlags & 0xFFFF)) + }; + } + + private uint FNVHash(uint prevHash, uint dword) + { + //https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + const uint fnvPrime = 0x811C9DC5; + prevHash *= fnvPrime; + prevHash ^= ((dword >> 0) & 0xFF); + prevHash ^= ((dword >> 8) & 0xFF); + prevHash ^= ((dword >> 16) & 0xFF); + prevHash ^= ((dword >> 24) & 0xFF); + return prevHash; + } + + private uint CalculateEntryHash(in GeometryPoolEntryDesc entryDesc) + { + uint meshHashCode = 0; + meshHashCode = FNVHash(meshHashCode, (uint)entryDesc.mesh.GetHashCode()); + if (entryDesc.submeshData != null) + { + foreach (var data in entryDesc.submeshData) + { + meshHashCode = FNVHash(meshHashCode, (uint)data.submeshIndex); + meshHashCode = FNVHash(meshHashCode, (uint)data.material.GetHashCode()); + } + } + return meshHashCode; + } + + public bool CreateBatch(int maxInstanceBatchCount, out GeometryPoolBatchHandle outBatchHandle) + { + outBatchHandle = GeometryPoolBatchHandle.Invalid; + + //align to 4 dwords at minimum + int alignedInstanceBatchCount = DivUp(maxInstanceBatchCount * GetGeoBatchInstancesDataByteSize(), 4) * GeometryPoolConstants.GeoPoolBatchInstancesPerDword; + + //find free batch + for (int bi = 0; bi < m_BatchTable.Length; ++bi) + { + if (!m_BatchTableAllocations[bi].valid) { - vertexOffset = geoSlot.vertexAlloc.block.offset, - indexOffset = geoSlot.indexAlloc.block.offset, - subMeshLookupOffset = geoSlot.subMeshLookupAlloc.block.offset, - subMeshEntryOffset = geoSlot.subMeshEntryAlloc.block.offset - }, - m_GlobalGeoMetadataBuffer); + var allocation = m_BatchInstancesAllocator.Allocate(alignedInstanceBatchCount); + if (!allocation.valid) + return false; + + m_BatchTableAllocations[bi] = allocation; + m_BatchTable[bi] = new GeoPoolBatchTableEntry() + { + offset = allocation.block.offset, + count = allocation.block.count + }; + outBatchHandle = new GeometryPoolBatchHandle() + { + index = bi + }; + + CommandBuffer cmdBuffer = AllocateCommandBuffer(); + cmdBuffer.SetBufferData(m_GlobalBatchTableBuffer, m_BatchTable, bi, bi, 1); + + return true; + } + } + + return false; + } + + public GeometryPoolBatchInstanceBuffer CreateGeometryPoolBatchInstanceBuffer(GeometryPoolBatchHandle batchHandle, bool isPersistant = false) + { + if (!batchHandle.valid) + return new GeometryPoolBatchInstanceBuffer(); + + GeoPoolBatchTableEntry entry = m_BatchTable[batchHandle.index]; + + return new GeometryPoolBatchInstanceBuffer() + { + instanceValues = new NativeArray(entry.count, isPersistant ? Allocator.Persistent : Allocator.Temp) + }; + } + + public void SetBatchInstanceData(GeometryPoolBatchHandle batchHandle, GeometryPoolBatchInstanceBuffer data) + { + if (!batchHandle.valid) + return; + + GeoPoolBatchTableEntry entry = m_BatchTable[batchHandle.index]; + Assertions.Assert.IsTrue(data.instanceValues.Length <= entry.count); + + CommandBuffer cmdBuffer = AllocateCommandBuffer(); + cmdBuffer.SetBufferData(m_GlobalBatchInstanceBuffer, data.instanceValues, 0, entry.offset, data.instanceValues.Length); + } + + public void DestroyBatch(GeometryPoolBatchHandle handle) + { + if (!handle.valid) + return; + + m_BatchInstancesAllocator.FreeAllocation((m_BatchTableAllocations[handle.index])); + m_BatchTableAllocations[handle.index] = BlockAllocator.Allocation.Invalid; } public bool Register(Mesh mesh, out GeometryPoolHandle outHandle) { - int meshHashCode = mesh.GetHashCode(); - Assertions.Assert.IsTrue(meshHashCode != -1); - if (m_MeshSlots.TryGetValue(meshHashCode, out MeshSlot meshSlot)) + return Register(new GeometryPoolEntryDesc() + { + mesh = mesh, + submeshData = null + }, out outHandle); + } + + private static int FindSubmeshEntryInDesc(int submeshIndex, in GeometryPoolEntryDesc entry) + { + if (entry.submeshData == null) + return -1; + + for (int i = 0; i < entry.submeshData.Length; ++i) + { + if (entry.submeshData[i].submeshIndex == submeshIndex) + return i; + } + + return -1; + } + + private uint RegisterMaterial(Material m) + { + int materialHashCode = m.GetHashCode(); + if (m_MaterialEntries.TryGetValue(materialHashCode, out GeometryPoolMaterialEntry entry)) { + ++entry.refCount; + m_MaterialEntries[materialHashCode] = entry; + return entry.materialGPUKey; + } + else + { + uint materialGPUKey = m_NextMaterialGPUKey++; + var materialEntry = new GeometryPoolMaterialEntry() + { + refCount = 1, + materialGPUKey = materialGPUKey, + material = m + }; + + m_MaterialEntries.Add(materialHashCode, materialEntry); + return materialGPUKey; + } + } + + private void UnregisterMaterial(int materialHashCode) + { + GeometryPoolMaterialEntry entry; + if (!m_MaterialEntries.TryGetValue(materialHashCode, out entry)) + return; + + --entry.refCount; + if (entry.refCount == 0) + m_MaterialEntries.Remove(materialHashCode); + else + m_MaterialEntries[materialHashCode] = entry; + } + + public bool Register(in GeometryPoolEntryDesc entryDesc, out GeometryPoolHandle outHandle) + { + if (entryDesc.mesh == null) + { + outHandle = GeometryPoolHandle.Invalid; + return false; + } + + Mesh mesh = entryDesc.mesh; + uint meshHashCode = CalculateEntryHash(entryDesc); + if (m_MeshHashToHandle.TryGetValue(meshHashCode, out outHandle)) + { + MeshSlot meshSlot = m_MeshSlots[outHandle]; Assertions.Assert.IsTrue(meshHashCode == meshSlot.meshHash); ++meshSlot.refCount; - m_MeshSlots[meshSlot.meshHash] = meshSlot; - outHandle = meshSlot.geometryHandle; + m_MeshSlots[outHandle] = meshSlot; return true; } else @@ -504,8 +816,7 @@ public bool Register(Mesh mesh, out GeometryPoolHandle outHandle) if (!AllocateGeo(mesh.vertexCount, indexCount, mesh.subMeshCount, out outHandle)) return false; - newSlot.geometryHandle = outHandle; - if (!m_MeshSlots.TryAdd(meshHashCode, newSlot)) + if (!m_MeshSlots.TryAdd(outHandle, newSlot)) { //revert the allocation. DeallocateGeo(outHandle); @@ -513,40 +824,71 @@ public bool Register(Mesh mesh, out GeometryPoolHandle outHandle) return false; } - UpdateGeoGpuState(mesh, outHandle); + if (!m_MeshHashToHandle.TryAdd(meshHashCode, outHandle)) + { + DeallocateGeo(outHandle); + m_MeshSlots.Remove(outHandle); + outHandle = GeometryPoolHandle.Invalid; + return false; + } + + //register material information + var materialHashes = new NativeArray(mesh.subMeshCount, Allocator.Persistent, NativeArrayOptions.UninitializedMemory); + var materialKeys = new NativeArray(mesh.subMeshCount, Allocator.TempJob, NativeArrayOptions.UninitializedMemory); + if (mesh.subMeshCount > 0) + { + for (int submeshIndex = 0; submeshIndex < materialKeys.Length; ++submeshIndex) + { + int entryIndex = FindSubmeshEntryInDesc(submeshIndex, entryDesc); + int materialHash = 0; + uint materialKey = 0; + + if (entryIndex != -1) + { + Material m = entryDesc.submeshData[entryIndex].material; + materialHash = m.GetHashCode(); + materialKey = RegisterMaterial(m); + } + + materialHashes[submeshIndex] = materialHash; + materialKeys[submeshIndex] = materialKey; + } + } + + m_MaterialHashes.Add(outHandle, materialHashes); + UpdateGeoGpuState(mesh, materialKeys, outHandle); + materialKeys.Dispose(); return true; } } - public void Unregister(Mesh mesh) - { - int meshHashCode = mesh.GetHashCode(); - UnregisterByMeshHashCode(meshHashCode); - } - - public void UnregisterByMeshHashCode(int meshHashCode) + public void Unregister(GeometryPoolHandle handle) { - if (!m_MeshSlots.TryGetValue(meshHashCode, out MeshSlot outSlot)) + if (!m_MeshSlots.TryGetValue(handle, out MeshSlot outSlot)) return; --outSlot.refCount; if (outSlot.refCount == 0) { - m_MeshSlots.Remove(meshHashCode); - DeallocateGeo(outSlot.geometryHandle); + m_MeshHashToHandle.Remove(outSlot.meshHash); + m_MeshSlots.Remove(handle); + + if (m_MaterialHashes.TryGetValue(handle, out var materialHashes)) + { + if (materialHashes.IsCreated) + { + foreach (var hash in materialHashes) + UnregisterMaterial(hash); + materialHashes.Dispose(); + } + + m_MaterialHashes.Remove(handle); + } + DeallocateGeo(handle); } else - m_MeshSlots[meshHashCode] = outSlot; - } - - public GeometryPoolHandle GetHandle(Mesh mesh) - { - int meshHashCode = mesh.GetHashCode(); - if (!m_MeshSlots.TryGetValue(meshHashCode, out MeshSlot outSlot)) - return GeometryPoolHandle.Invalid; - - return outSlot.geometryHandle; + m_MeshSlots[handle] = outSlot; } public void SendGpuCommands() @@ -666,7 +1008,7 @@ private void AddMetadataUpdateCommand( cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._GeoVertexOffset, metadataEntry.vertexOffset); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._GeoIndexOffset, metadataEntry.indexOffset); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._GeoSubMeshLookupOffset, metadataEntry.subMeshLookupOffset); - cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._GeoSubMeshEntryOffset, metadataEntry.subMeshEntryOffset); + cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._GeoSubMeshEntryOffset_VertexFlags, metadataEntry.subMeshEntryOffset_VertexFlags); int kernel = m_KernelMainUpdateMeshMetadata; cmdBuffer.SetComputeBufferParam(m_GeometryPoolKernelsCS, kernel, GeoPoolShaderIDs._OutputGeoMetadataBuffer, outputMetadataBuffer); @@ -694,15 +1036,18 @@ private void AddVertexUpdateCommand( in GraphicsBuffer p, in GraphicsBuffer uv0, in GraphicsBuffer uv1, in GraphicsBuffer n, in GraphicsBuffer t, int posStride, int posOffset, int uv0Stride, int uv0Offset, int uv1Stride, int uv1Offset, int normalStride, int normalOffset, int tangentStride, int tangentOffset, in BlockAllocator.Allocation location, + out GeoPoolInputFlags ouputFlags, ComputeBuffer outputVertexBuffer) { - if (location.block.count == 0) - return; - GeoPoolInputFlags flags = (uv1 != null ? GeoPoolInputFlags.HasUV1 : GeoPoolInputFlags.None) | (t != null ? GeoPoolInputFlags.HasTangent : GeoPoolInputFlags.None); + ouputFlags = flags; + + if (location.block.count == 0) + return; + cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._InputVBCount, location.block.count); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._OutputVBSize, m_MaxVertCounts); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._OutputVBOffset, location.block.offset); @@ -755,6 +1100,7 @@ private void AddSubMeshDataUpdateCommand( int descriptorIndex, int indexOffset, SubMeshDescriptor submeshDescriptor, + uint materialKey, in BlockAllocator.Allocation lookupAllocation, in BlockAllocator.Allocation entryAllocation, ComputeBuffer outputLookupBuffer, @@ -768,6 +1114,7 @@ private void AddSubMeshDataUpdateCommand( cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._InputSubMeshIndexCount, submeshDescriptor.indexCount); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._InputSubMeshBaseVertex, submeshDescriptor.baseVertex); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._InputSubMeshDestIndex, entryAllocation.block.offset + descriptorIndex); + cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._InputSubMeshMaterialKey, (int)materialKey); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._InputSubmeshLookupDestOffset, indexOffset / 3 + lookupAllocation.block.offset); cmdBuffer.SetComputeIntParam(m_GeometryPoolKernelsCS, GeoPoolShaderIDs._InputSubmeshLookupBufferCount, lookupCounts); @@ -786,12 +1133,15 @@ private Vector4 GetPackedGeoPoolParam0() return new Vector4(m_MaxVertCounts, 0.0f, 0.0f, 0.0f); } - public void BindResources(CommandBuffer cmdBuffer, ComputeShader cs, int kernel) + public void BindResourcesCS(CommandBuffer cmdBuffer, ComputeShader cs, int kernel) { cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalVertexBuffer, globalVertexBuffer); cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalIndexBuffer, globalIndexBuffer); + cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalSubMeshLookupBuffer, globalSubMeshLookupBuffer); + cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalSubMeshEntryBuffer, globalSubMeshEntryBuffer); cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalMetadataBuffer, globalMetadataBuffer); - cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalMetadataBuffer, globalMetadataBuffer); + cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalBatchTableBuffer, globalBatchTableBuffer); + cmdBuffer.SetComputeBufferParam(cs, kernel, GeoPoolShaderIDs._GeoPoolGlobalBatchInstanceBuffer, globalBatchInstanceBuffer); cmdBuffer.SetComputeVectorParam(cs, GeoPoolShaderIDs._GeoPoolGlobalParams, GetPackedGeoPoolParam0()); } @@ -799,9 +1149,24 @@ public void BindResources(Material material) { material.SetBuffer(GeoPoolShaderIDs._GeoPoolGlobalVertexBuffer, globalVertexBuffer); material.SetBuffer(GeoPoolShaderIDs._GeoPoolGlobalIndexBuffer, globalIndexBuffer); + material.SetBuffer(GeoPoolShaderIDs._GeoPoolGlobalSubMeshLookupBuffer, globalSubMeshLookupBuffer); + material.SetBuffer(GeoPoolShaderIDs._GeoPoolGlobalSubMeshEntryBuffer, globalSubMeshEntryBuffer); material.SetBuffer(GeoPoolShaderIDs._GeoPoolGlobalMetadataBuffer, globalMetadataBuffer); + material.SetBuffer(GeoPoolShaderIDs._GeoPoolGlobalBatchTableBuffer, globalBatchTableBuffer); + material.SetBuffer(GeoPoolShaderIDs._GeoPoolGlobalBatchInstanceBuffer, globalBatchInstanceBuffer); material.SetVector(GeoPoolShaderIDs._GeoPoolGlobalParams, GetPackedGeoPoolParam0()); } - } + public void BindResourcesGlobal(CommandBuffer cmdBuffer) + { + cmdBuffer.SetGlobalBuffer(GeoPoolShaderIDs._GeoPoolGlobalVertexBuffer, globalVertexBuffer); + cmdBuffer.SetGlobalBuffer(GeoPoolShaderIDs._GeoPoolGlobalIndexBuffer, globalIndexBuffer); + cmdBuffer.SetGlobalBuffer(GeoPoolShaderIDs._GeoPoolGlobalSubMeshLookupBuffer, globalSubMeshLookupBuffer); + cmdBuffer.SetGlobalBuffer(GeoPoolShaderIDs._GeoPoolGlobalSubMeshEntryBuffer, globalSubMeshEntryBuffer); + cmdBuffer.SetGlobalBuffer(GeoPoolShaderIDs._GeoPoolGlobalMetadataBuffer, globalMetadataBuffer); + cmdBuffer.SetGlobalBuffer(GeoPoolShaderIDs._GeoPoolGlobalBatchTableBuffer, globalBatchTableBuffer); + cmdBuffer.SetGlobalBuffer(GeoPoolShaderIDs._GeoPoolGlobalBatchInstanceBuffer, globalBatchInstanceBuffer); + cmdBuffer.SetGlobalVector(GeoPoolShaderIDs._GeoPoolGlobalParams, GetPackedGeoPoolParam0()); + } + } } diff --git a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPool.hlsl b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPool.hlsl index c87a60834c6..a0001fdca5d 100644 --- a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPool.hlsl +++ b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPool.hlsl @@ -5,12 +5,26 @@ ByteAddressBuffer _GeoPoolGlobalVertexBuffer; ByteAddressBuffer _GeoPoolGlobalIndexBuffer; +ByteAddressBuffer _GeoPoolGlobalSubMeshLookupBuffer; +StructuredBuffer _GeoPoolGlobalSubMeshEntryBuffer; StructuredBuffer _GeoPoolGlobalMetadataBuffer; +StructuredBuffer _GeoPoolGlobalBatchTableBuffer; +ByteAddressBuffer _GeoPoolGlobalBatchInstanceBuffer; float4 _GeoPoolGlobalParams; namespace GeometryPool { +int getSubMeshEntryOffset(in GeoPoolMetadataEntry metadata) +{ + return (metadata.subMeshEntryOffset_VertexFlags >> 16); +} + +int getGeoPoolInputFlags(in GeoPoolMetadataEntry metadata) +{ + return (metadata.subMeshEntryOffset_VertexFlags & 0xFFFF); +} + void StoreVertex( int vertexIndex, in GeoPoolVertex vertex, @@ -52,6 +66,8 @@ void LoadVertex( componentOffset = vertexBufferSize * GEO_POOL_UV1BYTE_OFFSET; if ((vertexFlags & GEOPOOLINPUTFLAGS_HAS_UV1) != 0) outputVertex.uv1 = asfloat(vertexBuffer.Load2(componentOffset + vertexIndex * GEO_POOL_UV1BYTE_SIZE)); + else + outputVertex.uv1 = outputVertex.uv; componentOffset = vertexBufferSize * GEO_POOL_NORMAL_BYTE_OFFSET; outputVertex.N = asfloat(vertexBuffer.Load3(componentOffset + vertexIndex * GEO_POOL_NORMAL_BYTE_SIZE)); @@ -61,12 +77,13 @@ void LoadVertex( outputVertex.T = asfloat(vertexBuffer.Load3(componentOffset + vertexIndex * GEO_POOL_TANGENT_BYTE_SIZE)); } -void LoadVertex( +GeoPoolVertex LoadVertex( int vertexIndex, - GeoPoolMetadataEntry metadata, - out GeoPoolVertex outputVertex) + GeoPoolMetadataEntry metadata) { - LoadVertex(metadata.vertexOffset + vertexIndex, (int)_GeoPoolGlobalParams.x, 0xfffff, _GeoPoolGlobalVertexBuffer, outputVertex); + GeoPoolVertex outputVertex; + LoadVertex(metadata.vertexOffset + vertexIndex, (int)_GeoPoolGlobalParams.x, getGeoPoolInputFlags(metadata), _GeoPoolGlobalVertexBuffer, outputVertex); + return outputVertex; } void SubMeshLookupBucketShiftMask(int index, out int bucketId, out int shift, out int mask) @@ -76,7 +93,6 @@ void SubMeshLookupBucketShiftMask(int index, out int bucketId, out int shift, ou mask = 0xff; } - void PackSubMeshLookup(int index, int value, out int bucketId, out uint packedValue) { int shift, mask; @@ -84,6 +100,29 @@ void PackSubMeshLookup(int index, int value, out int bucketId, out uint packedVa packedValue = (uint)(value & mask) << (uint)shift; } +uint GetMaterialKey(GeoPoolMetadataEntry metadata, uint primitiveID, ByteAddressBuffer subMeshLookupBuffer, StructuredBuffer subMeshEntryBuffer) +{ + int primitiveBucket, primitiveShift, primitiveMask; + SubMeshLookupBucketShiftMask(metadata.subMeshLookupOffset + primitiveID, primitiveBucket, primitiveShift, primitiveMask); + int submeshEntryIndex = ((int)subMeshLookupBuffer.Load(primitiveBucket << 2) >> primitiveShift) & primitiveMask; + GeoPoolSubMeshEntry submeshEntry = subMeshEntryBuffer[getSubMeshEntryOffset(metadata) + submeshEntryIndex]; + return submeshEntry.materialKey; +} + +uint GetMaterialKey(GeoPoolMetadataEntry metadata, uint primitiveID) +{ + return GetMaterialKey(metadata, primitiveID, _GeoPoolGlobalSubMeshLookupBuffer, _GeoPoolGlobalSubMeshEntryBuffer); +} + +GeoPoolMetadataEntry GetMetadataEntry(int instanceID, int batchID) +{ + GeoPoolBatchTableEntry tableEntry = _GeoPoolGlobalBatchTableBuffer[batchID]; + uint globalInstanceIndex = tableEntry.offset + instanceID; + uint pair = _GeoPoolGlobalBatchInstanceBuffer.Load((globalInstanceIndex >> 1) << 2); + uint metadataIdx = (globalInstanceIndex & 0x1) ? (pair >> 16) : (pair & 0xFF); + return _GeoPoolGlobalMetadataBuffer[metadataIdx]; +} + } #endif diff --git a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs index 5b3866cf2f8..2af35f88216 100644 --- a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs +++ b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs @@ -11,6 +11,8 @@ public static class GeometryPoolConstants public static int GeoPoolUV1ByteSize = 2 * 4; public static int GeoPoolNormalByteSize = 3 * 4; public static int GeoPoolTangentByteSize = 3 * 4; + public static int GeoPoolBatchInstanceDataByteSize = 2; + public static int GeoPoolBatchInstancesPerDword = 4 / GeoPoolBatchInstanceDataByteSize; public static int GeoPoolPosByteOffset = 0; public static int GeoPoolUV0ByteOffset = GeoPoolPosByteOffset + GeoPoolPosByteSize; @@ -48,6 +50,7 @@ internal struct GeoPoolSubMeshEntry public int baseVertex; public int indexStart; public int indexCount; + public uint materialKey; } [GenerateHLSL] @@ -56,6 +59,13 @@ internal struct GeoPoolMetadataEntry public int vertexOffset; public int indexOffset; public int subMeshLookupOffset; - public int subMeshEntryOffset; + public int subMeshEntryOffset_VertexFlags; //16 bits for submesh entry, 16 bits for vertex flags. + } + + [GenerateHLSL] + internal struct GeoPoolBatchTableEntry + { + public int offset; + public int count; } } diff --git a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs.hlsl b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs.hlsl index aa9562cf822..c913fc87344 100644 --- a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs.hlsl +++ b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolDefs.cs.hlsl @@ -12,6 +12,8 @@ #define GEO_POOL_UV1BYTE_SIZE (8) #define GEO_POOL_NORMAL_BYTE_SIZE (12) #define GEO_POOL_TANGENT_BYTE_SIZE (12) +#define GEO_POOL_BATCH_INSTANCE_DATA_BYTE_SIZE (2) +#define GEO_POOL_BATCH_INSTANCES_PER_DWORD (2) #define GEO_POOL_POS_BYTE_OFFSET (0) #define GEO_POOL_UV0BYTE_OFFSET (12) #define GEO_POOL_UV1BYTE_OFFSET (20) @@ -45,6 +47,7 @@ struct GeoPoolSubMeshEntry int baseVertex; int indexStart; int indexCount; + uint materialKey; }; // Generated from UnityEngine.Rendering.GeoPoolMetadataEntry @@ -54,7 +57,15 @@ struct GeoPoolMetadataEntry int vertexOffset; int indexOffset; int subMeshLookupOffset; - int subMeshEntryOffset; + int subMeshEntryOffset_VertexFlags; +}; + +// Generated from UnityEngine.Rendering.GeoPoolBatchTableEntry +// PackingRules = Exact +struct GeoPoolBatchTableEntry +{ + int offset; + int count; }; // @@ -72,6 +83,10 @@ int GetIndexCount(GeoPoolSubMeshEntry value) { return value.indexCount; } +uint GetMaterialKey(GeoPoolSubMeshEntry value) +{ + return value.materialKey; +} // // Accessors for UnityEngine.Rendering.GeoPoolMetadataEntry // @@ -87,9 +102,20 @@ int GetSubMeshLookupOffset(GeoPoolMetadataEntry value) { return value.subMeshLookupOffset; } -int GetSubMeshEntryOffset(GeoPoolMetadataEntry value) +int GetSubMeshEntryOffset_VertexFlags(GeoPoolMetadataEntry value) +{ + return value.subMeshEntryOffset_VertexFlags; +} +// +// Accessors for UnityEngine.Rendering.GeoPoolBatchTableEntry +// +int GetOffset(GeoPoolBatchTableEntry value) +{ + return value.offset; +} +int GetCount(GeoPoolBatchTableEntry value) { - return value.subMeshEntryOffset; + return value.count; } #endif diff --git a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolKernels.compute b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolKernels.compute index a61ea9c8dcf..e7b66df8a21 100644 --- a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolKernels.compute +++ b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPoolKernels.compute @@ -18,7 +18,7 @@ int _GeoHandle; int _GeoVertexOffset; int _GeoIndexOffset; int _GeoSubMeshLookupOffset; -int _GeoSubMeshEntryOffset; +int _GeoSubMeshEntryOffset_VertexFlags; RWStructuredBuffer _OutputGeoMetadataBuffer; [numthreads(1,1,1)] @@ -28,7 +28,7 @@ void MainUpdateMeshMetadata() entry.vertexOffset = _GeoVertexOffset; entry.indexOffset = _GeoIndexOffset; entry.subMeshLookupOffset = _GeoSubMeshLookupOffset; - entry.subMeshEntryOffset = _GeoSubMeshEntryOffset; + entry.subMeshEntryOffset_VertexFlags = _GeoSubMeshEntryOffset_VertexFlags; _OutputGeoMetadataBuffer[_GeoHandle] = entry; } @@ -133,6 +133,7 @@ int _InputSubMeshIndexStart; int _InputSubMeshIndexCount; int _InputSubMeshBaseVertex; int _InputSubMeshDestIndex; +int _InputSubMeshMaterialKey; int _InputSubmeshLookupDestOffset; int _InputSubmeshLookupBufferCount; @@ -150,6 +151,7 @@ void MainUpdateSubMeshData( entry.indexStart = _InputSubMeshIndexStart; entry.indexCount = _InputSubMeshIndexCount; entry.baseVertex = _InputSubMeshBaseVertex; + entry.materialKey = (uint)_InputSubMeshMaterialKey; _OutputSubMeshEntryBuffer[_InputSubMeshDestIndex] = entry; } diff --git a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/VisibilityBufferCommon.hlsl b/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/VisibilityBufferCommon.hlsl deleted file mode 100644 index b1000f4b9a6..00000000000 --- a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/VisibilityBufferCommon.hlsl +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef VBUFFER_COMMON_HLSL -#define VBUFFER_COMMON_HLSL - -#include "VertexBufferCompaction.cs.hlsl" - -void UnpackVisibilityBuffer(uint packedData, out uint clusterID, out uint triangleID) -{ - triangleID = packedData & 127; - // All the remaining 25 bits can be used for cluster (for a max of 33554431 (2^25 - 1) clusters) - clusterID = (packedData >> 7) & 33554431; -} - -uint PackVisBuffer(uint clusterID, uint triangleID) -{ - uint output = 0; - // Cluster size is 128, hence we need 7 bits at most for triangle ID. - output = triangleID & 127; - // All the remaining 25 bits can be used for cluster (for a max of 33554431 (2^25 - 1) clusters) - output |= (clusterID & 33554431) << 7; - return output; -} - - -#endif diff --git a/com.unity.render-pipelines.core/Tests/Editor/GeometryPoolTests.cs b/com.unity.render-pipelines.core/Tests/Editor/GeometryPoolTests.cs index 7a1776e3dff..19f8b667fa3 100644 --- a/com.unity.render-pipelines.core/Tests/Editor/GeometryPoolTests.cs +++ b/com.unity.render-pipelines.core/Tests/Editor/GeometryPoolTests.cs @@ -14,6 +14,7 @@ class GeometryPoolTests public static Mesh sCube16bit = null; public static Mesh sCapsule16bit = null; public static Mesh sMergedCubeSphere = null; + public static Mesh sMergedSphereCube = null; private static Mesh MergeMeshes(Mesh a, Mesh b) { @@ -81,6 +82,8 @@ internal struct GeometryPoolTestCpuData public NativeArray gpuSubMeshLookupData; public NativeArray gpuSubMeshEntryData; public NativeArray gpuMetadatas; + public NativeArray gpuBatchTable; + public NativeArray gpuBatchInstanceData; public void Load(GeometryPool geometryPool) { @@ -122,6 +125,21 @@ public void Load(GeometryPool geometryPool) metaData.CopyFrom(req.GetData()); }); + var batchTable = new NativeArray(geometryPool.maxBatchCount, Allocator.Persistent); + m_cmdBuffer.RequestAsyncReadback(geometryPool.globalBatchTableBuffer, (AsyncGPUReadbackRequest req) => + { + if (req.done) + batchTable.CopyFrom(req.GetData()); + }); + + + var batchInstances = new NativeArray(geometryPool.maxBatchInstanceCount, Allocator.Persistent); + m_cmdBuffer.RequestAsyncReadback(geometryPool.globalBatchInstanceBuffer, (AsyncGPUReadbackRequest req) => + { + if (req.done) + batchInstances.CopyFrom(req.GetData()); + }); + m_cmdBuffer.WaitAllAsyncReadbackRequests(); Graphics.ExecuteCommandBuffer(m_cmdBuffer); @@ -130,6 +148,8 @@ public void Load(GeometryPool geometryPool) gpuSubMeshLookupData = subMeshLookupData; gpuSubMeshEntryData = subMeshEntryData; gpuMetadatas = metaData; + gpuBatchTable = batchTable; + gpuBatchInstanceData = batchInstances; } public void Dispose() @@ -139,6 +159,8 @@ public void Dispose() gpuMetadatas.Dispose(); gpuSubMeshLookupData.Dispose(); gpuSubMeshEntryData.Dispose(); + gpuBatchTable.Dispose(); + gpuBatchInstanceData.Dispose(); m_cmdBuffer.Dispose(); } } @@ -153,8 +175,17 @@ private static bool EpsilonAreEqual(Vector3 a, Vector3 b) internal static void VerifyMeshInPool( in GeometryPoolTestCpuData geopoolCpuData, in GeometryPoolHandle handle, - Mesh mesh) + in Mesh mesh) + { + VerifyMeshInPool(geopoolCpuData, handle, new GeometryPoolEntryDesc() { mesh = mesh, submeshData = null }); + } + + internal static void VerifyMeshInPool( + in GeometryPoolTestCpuData geopoolCpuData, + in GeometryPoolHandle handle, + in GeometryPoolEntryDesc geoDesc) { + Mesh mesh = geoDesc.mesh; var gpuIndexData = geopoolCpuData.gpuIndexData; var gpuVertexData = geopoolCpuData.gpuVertexData; @@ -216,6 +247,13 @@ internal static void VerifyMeshInPool( } //validate submesh data + var submeshMaterialMap = new Dictionary(); + if (geoDesc.submeshData != null) + { + foreach (var desc in geoDesc.submeshData) + submeshMaterialMap.Add(desc.submeshIndex, desc.material); + } + var gpuSubMeshLookup = geopoolCpuData.gpuSubMeshLookupData; var gpuSubMeshEntry = geopoolCpuData.gpuSubMeshEntryData; var submeshLookupBlock = geopoolCpuData.geoPool.GetSubMeshLookupBlock(handle).block; @@ -237,6 +275,16 @@ internal static void VerifyMeshInPool( Assert.IsTrue(subMeshEntry.baseVertex == descriptor.baseVertex); Assert.IsTrue(subMeshEntry.indexStart == descriptor.indexStart); Assert.IsTrue(subMeshEntry.indexCount == descriptor.indexCount); + + Material subMeshMaterial = null; + submeshMaterialMap.TryGetValue(subMeshIndex, out subMeshMaterial); + + var geoPoolMaterialEntry = GeometryPoolMaterialEntry.NewDefault(); + if (subMeshMaterial != null) + geopoolCpuData.geoPool.globalMaterialEntries.TryGetValue(subMeshMaterial.GetHashCode(), out geoPoolMaterialEntry); + + Assert.IsTrue(subMeshMaterial == geoPoolMaterialEntry.material); + Assert.IsTrue(subMeshEntry.materialKey == geoPoolMaterialEntry.materialGPUKey); } //validate metadata @@ -245,6 +293,20 @@ internal static void VerifyMeshInPool( Assert.AreEqual(metadataEntry.indexOffset, idxBufferBlock.offset); } + internal void VerifyInstanceDataInPool( + in GeometryPoolTestCpuData geopoolCpuData, + GeometryPoolBatchHandle batchHandle, + GeometryPoolBatchInstanceBuffer instanceData) + { + var gpuTableData = geopoolCpuData.gpuBatchTable; + var tableEntry = gpuTableData[batchHandle.index]; + + for (int i = 0; i < tableEntry.count; ++i) + { + Assert.AreEqual(instanceData.instanceValues[i], geopoolCpuData.gpuBatchInstanceData[tableEntry.offset + i]); + } + } + [SetUp] public void SetupGeometryPoolTests() @@ -257,6 +319,7 @@ public void SetupGeometryPoolTests() var newCube = GameObject.CreatePrimitive(PrimitiveType.Cube).GetComponent(); sMergedCubeSphere = MergeMeshes(sCube, sSphere); + sMergedSphereCube = MergeMeshes(sSphere, sCube); } [TearDown] @@ -268,6 +331,7 @@ public void TearDownGeometryPoolTests() sCube16bit = null; sCapsule16bit = null; sMergedCubeSphere = null; + sMergedSphereCube = null; } [Test] @@ -277,17 +341,15 @@ public void TestGeometryPoolAddRemove() bool status; status = geometryPool.Register(sCube, out var handle0); Assert.IsTrue(status); - Assert.AreEqual(handle0.index, geometryPool.GetHandle(sCube).index); status = geometryPool.Register(sSphere, out var handle1); Assert.IsTrue(status); - Assert.AreEqual(handle1.index, geometryPool.GetHandle(sSphere).index); - geometryPool.Unregister(sSphere); - Assert.IsTrue(!geometryPool.GetHandle(sSphere).valid); + geometryPool.Unregister(handle0); + Assert.IsTrue(!geometryPool.GetEntryInfo(handle0).valid); - geometryPool.Unregister(sCube); - Assert.IsTrue(!geometryPool.GetHandle(sCube).valid); + geometryPool.Unregister(handle1); + Assert.IsTrue(!geometryPool.GetEntryInfo(handle1).valid); geometryPool.Dispose(); } @@ -299,27 +361,29 @@ public void TestGeometryPoolRefCount() bool status; - status = geometryPool.Register(sCube, out var handle0); + status = geometryPool.Register(sCube, out var cubeHandle); Assert.IsTrue(status); - status = geometryPool.Register(sCube, out var handle1); + status = geometryPool.Register(sCube, out var cubeHandle1); Assert.IsTrue(status); - status = geometryPool.Register(sSphere, out var handle2); + status = geometryPool.Register(sSphere, out var sphereHandle); Assert.IsTrue(status); - Assert.AreEqual(handle0.index, handle1.index); - Assert.AreNotEqual(handle0.index, handle2.index); + Assert.AreEqual(cubeHandle, cubeHandle1); + Assert.AreNotEqual(cubeHandle1, sphereHandle); - geometryPool.Unregister(sCube); + Assert.IsTrue(geometryPool.GetEntryInfo(cubeHandle).refCount == 2); - Assert.IsTrue(geometryPool.GetHandle(sCube).valid); + geometryPool.Unregister(cubeHandle); - geometryPool.Unregister(sCube); + Assert.IsTrue(geometryPool.GetEntryInfo(cubeHandle).refCount == 1); - Assert.IsTrue(!geometryPool.GetHandle(sCube).valid); + geometryPool.Unregister(cubeHandle1); - status = geometryPool.Register(sCube, out var _); + Assert.IsTrue(!geometryPool.GetEntryInfo(cubeHandle).valid); + + status = geometryPool.Register(sCube, out var newCubeHandle); Assert.IsTrue(status); - Assert.IsTrue(geometryPool.GetHandle(sCube).valid); + Assert.IsTrue(geometryPool.GetEntryInfo(newCubeHandle).valid); geometryPool.Dispose(); } @@ -348,13 +412,13 @@ public void TestGeometryPoolFailedAllocByIndex() status = geometryPool.Register(sCube, out var _); Assert.IsTrue(status); - status = geometryPool.Register(sCapsule, out var _); + status = geometryPool.Register(sCapsule, out var capsuleHandle); Assert.IsTrue(status); status = geometryPool.Register(sSphere, out var _); Assert.IsTrue(!status); - geometryPool.Unregister(sCapsule); + geometryPool.Unregister(capsuleHandle); status = geometryPool.Register(sSphere, out var _); Assert.IsTrue(status); @@ -375,18 +439,18 @@ public void TestGeometryPoolFailedAllocByMaxVertex() var geometryPool = new GeometryPool(gpdesc); bool status; - status = geometryPool.Register(sCube, out var _); + status = geometryPool.Register(sCube, out var cubeHandle); Assert.IsTrue(status); - status = geometryPool.Register(sCapsule, out var _); + status = geometryPool.Register(sCapsule, out var capsuleHandle); Assert.IsTrue(status); - status = geometryPool.Register(sSphere, out var _); + status = geometryPool.Register(sSphere, out var sphereHandle); Assert.IsTrue(!status); - geometryPool.Unregister(sCapsule); + geometryPool.Unregister(capsuleHandle); - status = geometryPool.Register(sSphere, out var _); + status = geometryPool.Register(sSphere, out var sphereHandle1); Assert.IsTrue(status); geometryPool.Dispose(); @@ -401,18 +465,18 @@ public void TestGeometryPoolFailedAllocByMaxMeshes() var geometryPool = new GeometryPool(gpdesc); bool status; - status = geometryPool.Register(sCube, out var _); + status = geometryPool.Register(sCube, out var cubeHandle); Assert.IsTrue(status); - status = geometryPool.Register(sCapsule, out var _); + status = geometryPool.Register(sCapsule, out var capsuleHandle); Assert.IsTrue(status); - status = geometryPool.Register(sSphere, out var _); + status = geometryPool.Register(sSphere, out var sphereHandle); Assert.IsTrue(!status); - geometryPool.Unregister(sCapsule); + geometryPool.Unregister(capsuleHandle); - status = geometryPool.Register(sSphere, out var _); + status = geometryPool.Register(sSphere, out var sphereHandle1); Assert.IsTrue(status); geometryPool.Dispose(); @@ -458,7 +522,7 @@ public void TestGpuUploadAddRemoveToGeometryPool() geometryPool.SendGpuCommands(); - geometryPool.Unregister(sSphere); + geometryPool.Unregister(sphereHandle); status = geometryPool.Register(sCapsule, out var capsuleHandle); Assert.IsTrue(status); @@ -514,7 +578,7 @@ public void TestGpuUploadAddRemoveIndexBuffer16bitGeometryPool() geometryPool.SendGpuCommands(); - geometryPool.Unregister(sSphere); + geometryPool.Unregister(sphereHandle); status = geometryPool.Register(sCapsule16bit, out var capsuleHandle); Assert.IsTrue(status); @@ -550,7 +614,7 @@ public void TestGpuUploadAddRemoveMergedMeshes() geometryPool.SendGpuCommands(); - geometryPool.Unregister(sSphere); + geometryPool.Unregister(sphereHandle); status = geometryPool.Register(sCapsule16bit, out var capsuleHandle); Assert.IsTrue(status); @@ -568,5 +632,149 @@ public void TestGpuUploadAddRemoveMergedMeshes() geometryPool.Dispose(); } + [Test] + public void TestGpuSubmeshMaterials() + { + var geometryPool = new GeometryPool(GeometryPoolDesc.NewDefault()); + + bool status; + + var materialA = new Material(Shader.Find("Standard")); + var materialB = new Material(Shader.Find("Standard")); + var materialC = new Material(Shader.Find("Standard")); + + var mergedCubeSphereDesc = new GeometryPoolEntryDesc() + { + mesh = sMergedCubeSphere, + submeshData = new GeometryPoolSubmeshData[] + { + new GeometryPoolSubmeshData() { submeshIndex = 0, material = materialA }, + new GeometryPoolSubmeshData() { submeshIndex = 1, material = materialB } + } + }; + + status = geometryPool.Register(mergedCubeSphereDesc, out var mergedCubeSphereHandle); + Assert.IsTrue(status); + + var mergedSphereCubeDesc = new GeometryPoolEntryDesc() + { + mesh = sMergedSphereCube, + submeshData = new GeometryPoolSubmeshData[] + { + new GeometryPoolSubmeshData() { submeshIndex = 0, material = materialB }, + new GeometryPoolSubmeshData() { submeshIndex = 1, material = materialC } + } + }; + + status = geometryPool.Register(mergedSphereCubeDesc, out var mergedSphereCubeHandle); + Assert.IsTrue(status); + + status = geometryPool.Register(sCapsule16bit, out var capsuleHandle); + Assert.IsTrue(status); + + geometryPool.SendGpuCommands(); + + GeometryPoolTestCpuData geopoolCpuData = new GeometryPoolTestCpuData(); + geopoolCpuData.Load(geometryPool); + VerifyMeshInPool(geopoolCpuData, mergedSphereCubeHandle, mergedSphereCubeDesc); + VerifyMeshInPool(geopoolCpuData, capsuleHandle, sCapsule16bit); + VerifyMeshInPool(geopoolCpuData, mergedCubeSphereHandle, mergedCubeSphereDesc); + + var matEntry = GeometryPoolMaterialEntry.NewDefault(); + + geometryPool.globalMaterialEntries.TryGetValue(materialB.GetHashCode(), out matEntry); + Assert.IsTrue(matEntry.refCount == 2); + Assert.IsTrue(matEntry.material == materialB); + + matEntry = GeometryPoolMaterialEntry.NewDefault(); + geometryPool.globalMaterialEntries.TryGetValue(materialA.GetHashCode(), out matEntry); + Assert.IsTrue(matEntry.refCount == 1); + Assert.IsTrue(matEntry.material == materialA); + + geometryPool.Unregister(mergedCubeSphereHandle); + + matEntry = GeometryPoolMaterialEntry.NewDefault(); + geometryPool.globalMaterialEntries.TryGetValue(materialB.GetHashCode(), out matEntry); + Assert.IsTrue(matEntry.refCount == 1); + Assert.IsTrue(matEntry.material == materialB); + + matEntry = GeometryPoolMaterialEntry.NewDefault(); + geometryPool.globalMaterialEntries.TryGetValue(materialA.GetHashCode(), out matEntry); + Assert.IsTrue(matEntry.refCount == 0); + Assert.IsTrue(matEntry.material == null); + + geopoolCpuData.Dispose(); + geometryPool.Dispose(); + } + + [Test] + public void TestGpuGeoPoolBatchAddRemove() + { + var geometryPool = new GeometryPool(GeometryPoolDesc.NewDefault()); + var allBatches = new GeometryPoolBatchHandle[geometryPool.maxBatchCount]; + for (int i = 0; i < geometryPool.maxBatchCount; ++i) + { + bool success = geometryPool.CreateBatch(5, out var newBatchHandle); + allBatches[i] = newBatchHandle; + Assert.IsTrue(success); + } + + bool notSuccess = !geometryPool.CreateBatch(5, out var newBatchHandleInvalid); + Assert.IsTrue(notSuccess); + + geometryPool.DestroyBatch(allBatches[8]); + + bool yesSuccess = geometryPool.CreateBatch(5, out var newBatchHandleValid); + Assert.IsTrue(yesSuccess && newBatchHandleValid.valid); + + geometryPool.Dispose(); + } + + [Test] + public void TestGpuGeoPoolBatchInstances() + { + var geometryPool = new GeometryPool(GeometryPoolDesc.NewDefault()); + + bool status; + + status = geometryPool.Register(sSphere, out var sphereHandle); + Assert.IsTrue(status); + + status = geometryPool.Register(sCube16bit, out var cubeHandle); + Assert.IsTrue(status); + + const int batch0Size = 21; + const int batch1Size = 15; + geometryPool.CreateBatch(batch0Size, out var batch0Handle); + var instanceDataBatch0 = geometryPool.CreateGeometryPoolBatchInstanceBuffer(batch0Handle); + { + for (int i = 0; i < batch0Size; ++i) + instanceDataBatch0.instanceValues[i] = (short)((i & 0x1) != 0 ? sphereHandle.index : cubeHandle.index); + geometryPool.SetBatchInstanceData(batch0Handle, instanceDataBatch0); + } + + geometryPool.CreateBatch(batch1Size, out var batch1Handle); + var instanceDataBatch1 = geometryPool.CreateGeometryPoolBatchInstanceBuffer(batch1Handle); + { + for (int i = 0; i < batch1Size; ++i) + instanceDataBatch1.instanceValues[i] = (short)((i & 0x1) != 0 ? cubeHandle.index : sphereHandle.index); + geometryPool.SetBatchInstanceData(batch1Handle, instanceDataBatch1); + } + + geometryPool.SendGpuCommands(); + + GeometryPoolTestCpuData geopoolCpuData = new GeometryPoolTestCpuData(); + geopoolCpuData.Load(geometryPool); + VerifyMeshInPool(geopoolCpuData, cubeHandle, sCube16bit); + VerifyMeshInPool(geopoolCpuData, sphereHandle, sSphere); + + VerifyInstanceDataInPool(geopoolCpuData, batch0Handle, instanceDataBatch0); + VerifyInstanceDataInPool(geopoolCpuData, batch1Handle, instanceDataBatch1); + + instanceDataBatch0.Dispose(); + instanceDataBatch1.Dispose(); + geopoolCpuData.Dispose(); + geometryPool.Dispose(); + } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs index 37adcf9ff83..e0bb672011c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs @@ -133,8 +133,22 @@ public enum FullScreenDebugMode RequestedVirtualTextureTiles, /// Black background to visualize the Lens Flare LensFlareDataDriven, - /// Display the visibility buffer. - VisibilityBuffer, + /// Display the visibility buffer instaces. + VisibilityBufferInstances, + /// Display the visibility buffer primitives. + VisibilityBufferPrimitives, + /// Display the visibility buffer materials. + VisibilityBufferMaterials, + /// Display the visibility buffer batch. + VisibilityBufferBatch, + /// Display the visibility feature tile. + VisibilityFeatureTile, + /// Display the visibility material tile. + VisibilityMaterialsTile, + /// Display the visibility bucket id. + VisibilityBucketID, + /// Display lighting result of visibility buffer. + VisibilityBufferLighting, /// Maximum Full Screen Rendering debug mode value (used internally). MaxRenderingFullScreenDebug, diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl index a788f59301d..812fb09fb28 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.cs.hlsl @@ -39,13 +39,20 @@ #define FULLSCREENDEBUGMODE_VERTEX_DENSITY (29) #define FULLSCREENDEBUGMODE_REQUESTED_VIRTUAL_TEXTURE_TILES (30) #define FULLSCREENDEBUGMODE_LENS_FLARE_DATA_DRIVEN (31) -#define FULLSCREENDEBUGMODE_VISIBILITY_BUFFER (32) -#define FULLSCREENDEBUGMODE_MAX_RENDERING_FULL_SCREEN_DEBUG (33) -#define FULLSCREENDEBUGMODE_MIN_MATERIAL_FULL_SCREEN_DEBUG (34) -#define FULLSCREENDEBUGMODE_VALIDATE_DIFFUSE_COLOR (35) -#define FULLSCREENDEBUGMODE_VALIDATE_SPECULAR_COLOR (36) -#define FULLSCREENDEBUGMODE_MAX_MATERIAL_FULL_SCREEN_DEBUG (37) -#define FULLSCREENDEBUGMODE_WORLD_SPACE_POSITION (38) +#define FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_INSTANCES (32) +#define FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_PRIMITIVES (33) +#define FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_MATERIALS (34) +#define FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_BATCH (35) +#define FULLSCREENDEBUGMODE_VISIBILITY_FEATURE_TILE (36) +#define FULLSCREENDEBUGMODE_VISIBILITY_MATERIALS_TILE (37) +#define FULLSCREENDEBUGMODE_VISIBILITY_BUCKET_ID (38) +#define FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_LIGHTING (39) +#define FULLSCREENDEBUGMODE_MAX_RENDERING_FULL_SCREEN_DEBUG (40) +#define FULLSCREENDEBUGMODE_MIN_MATERIAL_FULL_SCREEN_DEBUG (41) +#define FULLSCREENDEBUGMODE_VALIDATE_DIFFUSE_COLOR (42) +#define FULLSCREENDEBUGMODE_VALIDATE_SPECULAR_COLOR (43) +#define FULLSCREENDEBUGMODE_MAX_MATERIAL_FULL_SCREEN_DEBUG (44) +#define FULLSCREENDEBUGMODE_WORLD_SPACE_POSITION (45) // Generated from UnityEngine.Rendering.HighDefinition.ShaderVariablesDebugDisplay // PackingRules = Exact diff --git a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader index 2c75dc617d2..372ed01b1ba 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugFullScreen.shader @@ -17,6 +17,9 @@ Shader "Hidden/HDRP/DebugFullScreen" #pragma vertex Vert #pragma fragment Frag + #pragma multi_compile _ DOTS_INSTANCING_ON + #pragma enable_d3d11_debug_symbols + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Color.hlsl" #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Debug.hlsl" @@ -26,7 +29,7 @@ Shader "Hidden/HDRP/DebugFullScreen" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/DebugDisplay.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Debug/FullScreenDebug.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Builtin/BuiltinData.hlsl" - #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl" CBUFFER_START (UnityDebug) float _FullScreenDebugMode; @@ -341,12 +344,53 @@ Shader "Hidden/HDRP/DebugFullScreen" float4 color = SAMPLE_TEXTURE2D_X(_DebugFullScreenTexture, s_point_clamp_sampler, input.texcoord) * GetCurrentExposureMultiplier(); return float4(color.rgb, 1.0f); } - if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER) + if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_INSTANCES || + _FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_MATERIALS || + _FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_PRIMITIVES || + _FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_BATCH) + { + uint debugIndex = 0; + + #ifdef DOTS_INSTANCING_ON + Visibility::VisibilityData visData = Visibility::LoadVisibilityData(input.positionCS.xy); + + if (!visData.valid) + return float4(pow(input.texcoord.yyy, 4.0), 1.0f); + if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_INSTANCES) + debugIndex = visData.DOTSInstanceIndex; + else if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_PRIMITIVES) + debugIndex = visData.primitiveID; + else if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_MATERIALS) + debugIndex = Visibility::GetMaterialKey(visData); + else if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUFFER_BATCH) + debugIndex = visData.batchID; + #endif + + return float4(Visibility::DebugVisIndexToRGB(debugIndex), 1.0f); + } + if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_FEATURE_TILE || + _FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_MATERIALS_TILE || + _FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUCKET_ID) { - uint value = LOAD_TEXTURE2D_X(_VisibilityTexture, (uint2)input.positionCS.xy).x; - VisibilityData visData; - unpackVisibilityData(value, visData); - return float4(DebugVisIndexToRGB(visData.primitiveID), 1.0f); + uint debugIndex = 0; + #ifdef DOTS_INSTANCING_ON + uint2 tileCoord = Visibility::GetTileCoord(input.positionCS.xy); + if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_FEATURE_TILE) + { + bool validTile = Visibility::LoadMaterialTile(tileCoord).y != 0; + if (validTile) + { + uint tileFeatures = Visibility::LoadFeatureTile(tileCoord); + debugIndex = Visibility::GetLightTileCategory(tileFeatures) + 1; + } + } + else if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_MATERIALS_TILE) + debugIndex = Visibility::LoadMaterialTile(tileCoord).y; //max is more interesting + else if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_VISIBILITY_BUCKET_ID) + debugIndex = Visibility::LoadBucketTile(tileCoord); + #endif + + return float4(Visibility::DebugVisIndexToRGB(debugIndex), 1.0f); } if (_FullScreenDebugMode == FULLSCREENDEBUGMODE_PRE_REFRACTION_COLOR_PYRAMID || _FullScreenDebugMode == FULLSCREENDEBUGMODE_FINAL_COLOR_PYRAMID) diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs index c0aaf020955..b1c14b3352f 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs @@ -85,6 +85,23 @@ internal enum LightFeatureFlags // If adding more light be sure to not overflow LightDefinitions.s_LightFeatureMaskFlags } + [GenerateHLSL] + internal enum LightVBufferTileCategory + { + Env, + EnvPunctual, + Everything, + Unknown + } + + [GenerateHLSL] + class LightVBufferTileCategoryFeatures + { + public static uint s_VBufferLightingFeaturesEnv = (uint)LightFeatureFlags.Directional | (uint)LightFeatureFlags.Sky | (uint)LightFeatureFlags.Env | LightDefinitions.s_MaterialFeatureMaskFlags; + public static uint s_VBufferLightingFeaturesEnvPunctual = (uint)LightFeatureFlags.Directional | (uint)LightFeatureFlags.Sky | (uint)LightFeatureFlags.Env | (uint)LightFeatureFlags.Punctual | LightDefinitions.s_MaterialFeatureMaskFlags; + public static uint s_VBufferLightingFeaturesEverything = (uint)LightFeatureFlags.Directional | (uint)LightFeatureFlags.Sky | (uint)LightFeatureFlags.Env | (uint)LightFeatureFlags.Punctual | (uint)LightFeatureFlags.Area | LightDefinitions.s_MaterialFeatureMaskFlags; + } + [GenerateHLSL] class LightDefinitions { diff --git a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs.hlsl index 4d84146d4bd..df89548ca1d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs.hlsl @@ -33,6 +33,21 @@ #define LIGHTFEATUREFLAGS_SSREFRACTION (131072) #define LIGHTFEATUREFLAGS_SSREFLECTION (262144) +// +// UnityEngine.Rendering.HighDefinition.LightVBufferTileCategory: static fields +// +#define LIGHTVBUFFERTILECATEGORY_ENV (0) +#define LIGHTVBUFFERTILECATEGORY_ENV_PUNCTUAL (1) +#define LIGHTVBUFFERTILECATEGORY_EVERYTHING (2) +#define LIGHTVBUFFERTILECATEGORY_UNKNOWN (3) + +// +// UnityEngine.Rendering.HighDefinition.LightVBufferTileCategoryFeatures: static fields +// +#define VBUFFER_LIGHTING_FEATURES_ENV (118783) +#define VBUFFER_LIGHTING_FEATURES_ENV_PUNCTUAL (122879) +#define VBUFFER_LIGHTING_FEATURES_EVERYTHING (131071) + // // UnityEngine.Rendering.HighDefinition.LightDefinitions: static fields // diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader index a69084cbbe5..f4258dd657d 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.shader @@ -908,6 +908,56 @@ Shader "HDRP/Lit" ENDHLSL } + Pass + { + Name "VBufferLighting" + Tags{ "LightMode" = "VBufferLighting"} + + Cull Back + AlphaToMask [_AlphaToMask] + + ZWrite Off + ZTest Equal + + HLSLPROGRAM + + #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + //enable GPU instancing support + #pragma multi_compile_instancing + #pragma instancing_options renderinglayer + #pragma multi_compile _ DOTS_INSTANCING_ON + // enable dithering LOD crossfade + #pragma multi_compile _ LOD_FADE_CROSSFADE + #pragma multi_compile_fragment SHADOW_LOW SHADOW_MEDIUM SHADOW_HIGH SHADOW_VERY_HIGH + + #pragma multi_compile VARIANT_DIR_ENV VARIANT_DIR_PUNCTUAL_ENV VARIANT_DIR_PUNCTUAL_AREA_ENV + + #pragma multi_compile _ LIGHTMAP_ON + #pragma multi_compile _ DYNAMICLIGHTMAP_ON + + #define HAS_LIGHTLOOP + + #define SHADERPASS SHADERPASS_VBUFFER_LIGHTING + + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Material.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/Lighting.hlsl" + + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/ShaderPass/LitDepthPass.hlsl" + + #define USE_FPTL_LIGHTLIST // Use light tiles for contact shadows + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoopDef.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.hlsl" + + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitData.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVBufferLighting.hlsl" + + #pragma vertex Vert + #pragma fragment Frag + + ENDHLSL + } + Pass { Name "TransparentDepthPostpass" diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/CreateMaterialDepth.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/CreateMaterialDepth.shader new file mode 100644 index 00000000000..38c173e79bc --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/CreateMaterialDepth.shader @@ -0,0 +1,79 @@ +Shader "Hidden/HDRP/CreateMaterialDepth" +{ + Properties + { + } + + SubShader + { + Tags{ "RenderPipeline" = "HDRenderPipeline" "RenderType" = "Opaque" } + + HLSLINCLUDE + #pragma editor_sync_compilation + #pragma target 4.5 + #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + //#pragma enable_d3d11_debug_symbols + + #define DOTS_INSTANCING_ON 1 + + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" + #include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" + #include "Packages/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPool.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl" + + struct Varyings + { + float4 positionCS : SV_POSITION; + float2 texcoord : TEXCOORD0; + UNITY_VERTEX_OUTPUT_STEREO + }; + + struct Attributes + { + uint vertexID : SV_VertexID; + UNITY_VERTEX_INPUT_INSTANCE_ID + }; + + Varyings Vert(Attributes inputMesh) + { + Varyings output; + UNITY_SETUP_INSTANCE_ID(inputMesh); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + output.positionCS = GetFullScreenTriangleVertexPosition(inputMesh.vertexID); + output.texcoord = GetFullScreenTriangleTexCoord(inputMesh.vertexID); + return output; + } + + void Frag(Varyings input, out float outDepth : SV_Depth) + { + Visibility::VisibilityData visData = Visibility::LoadVisibilityData(input.positionCS.xy); + outDepth = 0.0f; + if (!visData.valid) + { + clip(-1); + return; + } + + uint materialKey = Visibility::GetMaterialKey(visData); + uint materialBatchKey = (materialKey << 8) | (visData.batchID & 0xff); + // We assume a maximum of 65536 materials in scene. + outDepth = Visibility::PackDepthMaterialKey(materialBatchKey); + } + + ENDHLSL + + Pass + { + Name "CreateMaterialDepth" + Tags{ "LightMode" = "CreateMaterialDepth" } + + ZWrite On + + HLSLPROGRAM + #pragma vertex Vert + #pragma fragment Frag + ENDHLSL + } + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/CreateMaterialDepth.shader.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/CreateMaterialDepth.shader.meta new file mode 100644 index 00000000000..70f592c5316 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/CreateMaterialDepth.shader.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: dbc5c19310f2c544c91d4bf81b05ddc6 +ShaderImporter: + externalObjects: {} + defaultTextures: [] + nonModifiableTextures: [] + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VBufferClassification.compute b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VBufferClassification.compute new file mode 100644 index 00000000000..38d9a6b6fb9 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VBufferClassification.compute @@ -0,0 +1,138 @@ + +#define DOTS_INSTANCING_ON +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Common.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/ShaderLibrary/ShaderVariables.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Builtin/BuiltinData.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/Packing.hlsl" + +//#pragma enable_d3d11_debug_symbols + +#pragma kernel FeatureTileClassifyReduction +#pragma kernel MaterialReduction +#pragma kernel MaterialFinalReduction + +#define GROUP_SIZE 8 + +StructuredBuffer g_TileFeatureFlags; +RW_TEXTURE2D_X(uint, _VisBufferFeatureTileOutput); + +float4 _VisBufferTileSize; + +[numthreads(GROUP_SIZE, GROUP_SIZE, 1)] +void FeatureTileClassifyReduction(uint3 id : SV_DispatchThreadID) +{ + uint2 topLeftTileCoord = id.xy * (VIS_BUFFER_TILE_SIZE / TILE_SIZE_FPTL); + + if (any((int2)id.xy >= _VisBufferTileSize.xy)) + return; + + uint screenWidth = (uint)_ScreenSize.x; + uint numTilesX = (screenWidth + (TILE_SIZE_FPTL) - 1) / TILE_SIZE_FPTL; + + uint featureSet = 0; + // Very dumb loop. Can be vastly improved with LDS or wave intrinsics. + for (int x = 0; x < 4; ++x) + { + for (int y = 0; y < 4; ++y) + { + uint2 tileCoord = topLeftTileCoord + uint2(x, y); + uint tileIndex = tileCoord.x + tileCoord.y * numTilesX; + + featureSet |= g_TileFeatureFlags[tileIndex]; + } + } + + _VisBufferFeatureTileOutput[COORD_TEXTURE2D_X(id.xy)] = featureSet; +} + +#ifndef PLATFORM_SUPPORTS_WAVE_INTRINSICS +groupshared uint gs_minMatID[GROUP_SIZE * GROUP_SIZE]; +groupshared uint gs_maxMatID[GROUP_SIZE * GROUP_SIZE]; +groupshared uint gs_bucketID[GROUP_SIZE * GROUP_SIZE]; +#endif + +void ParallelReduction(uint threadIdx, uint minValueInput, uint maxValueInput, uint bucketValue, out uint minValue, out uint maxValue, out uint bucketOr) +{ +#ifdef PLATFORM_SUPPORTS_WAVE_INTRINSICS + minValue = WaveActiveMin(minValueInput); + maxValue = WaveActiveMax(maxValueInput); + bucketOr = WaveActiveBitOr(bucketValue); + return; +#else + gs_minMatID[threadIdx] = minValueInput; + gs_maxMatID[threadIdx] = maxValueInput; + gs_bucketID[threadIdx] = bucketValue; + + GroupMemoryBarrierWithGroupSync(); + + UNITY_UNROLL + for (uint s = (GROUP_SIZE * GROUP_SIZE) / 2u; s > 0u; s >>= 1u) + { + if (threadIdx < s) + { + gs_maxMatID[threadIdx] = max(gs_maxMatID[threadIdx], gs_maxMatID[threadIdx + s]); + gs_minMatID[threadIdx] = min(gs_minMatID[threadIdx], gs_minMatID[threadIdx + s]); + gs_bucketID[threadIdx] = (gs_bucketID[threadIdx] | gs_bucketID[threadIdx + s]); + } + + GroupMemoryBarrierWithGroupSync(); + } + minValue = gs_minMatID[0]; + maxValue = gs_maxMatID[0]; + bucketOr = gs_bucketID[0]; +#endif +} + +TEXTURE2D_X_UINT2(_VisBufferMaterialTileInput); +TEXTURE2D_X_UINT(_VisBufferBucketTileInput); +RW_TEXTURE2D_X(uint2, _VisBufferMaterialTileOutput); +RW_TEXTURE2D_X(uint, _VisBufferBucketTileOutput); + +void ParallelReduction(uint threadIdx, uint value, uint bucketValue, out uint minValue, out uint maxValue, out uint bucketOr) +{ + ParallelReduction(threadIdx, value, value, bucketValue, minValue, maxValue, bucketOr); +} + +[numthreads(GROUP_SIZE, GROUP_SIZE, 1)] +void MaterialReduction(uint3 id : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint3 groupID : SV_GroupID) +{ + uint threadIdx = groupThreadId.y * GROUP_SIZE + groupThreadId.x; + + uint materialKey = Visibility::GetMaterialKey(Visibility::LoadVisibilityData(id.xy)); + + uint minMat = 0xffffff; + uint maxMat = 0; + uint bucketOR = 0; + ParallelReduction(threadIdx, materialKey, materialKey, minMat, maxMat, bucketOR); + + if (any((int2)id.xy >= _ScreenSize.xy)) return; + + if (threadIdx == 0) + { + _VisBufferMaterialTileOutput[COORD_TEXTURE2D_X(groupID.xy)] = uint2(minMat, maxMat); + _VisBufferBucketTileOutput[COORD_TEXTURE2D_X(groupID.xy)] = bucketOR; + } +} + + +[numthreads(GROUP_SIZE, GROUP_SIZE, 1)] +void MaterialFinalReduction(uint3 id : SV_DispatchThreadID, uint2 groupThreadId : SV_GroupThreadID, uint3 groupID : SV_GroupID) +{ + uint threadIdx = groupThreadId.y * GROUP_SIZE + groupThreadId.x; + uint2 samplingCoord = min(id.xy, _ScreenSize.xy / 8); + + uint2 minMaxMatID = _VisBufferMaterialTileInput[COORD_TEXTURE2D_X(samplingCoord)]; + uint bucketID = _VisBufferBucketTileInput[COORD_TEXTURE2D_X(samplingCoord)]; + + uint minMat = 0xffffff; + uint maxMat = 0; + uint bucketOR = 0; + ParallelReduction(threadIdx, minMaxMatID.x, minMaxMatID.y, bucketID, minMat, maxMat, bucketOR); + + if (threadIdx == 0) + { + _VisBufferMaterialTileOutput[COORD_TEXTURE2D_X(groupID.xy)] = uint2(minMat, maxMat); + _VisBufferBucketTileOutput[COORD_TEXTURE2D_X(groupID.xy)] = bucketOR; + } +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VBufferClassification.compute.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VBufferClassification.compute.meta new file mode 100644 index 00000000000..e63922f43a8 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VBufferClassification.compute.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 8097d48cf7ce091419dc8bf4ffc35e1a +ComputeShaderImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.hlsl deleted file mode 100644 index ed958206527..00000000000 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.hlsl +++ /dev/null @@ -1,49 +0,0 @@ -#ifndef VISIBILITY_HLSL -#define VISIBILITY_HLSL - -TEXTURE2D_X_UINT(_VisibilityTexture); - -struct VisibilityData -{ - uint DOTSInstanceIndex; - uint primitiveID; -}; - -#define InvalidVisibilityData 0xffffffff - -float3 DebugVisIndexToRGB(uint index) -{ - if (index == 0) - return float3(0, 0, 0); - - // Xorshift*32 - // Based on George Marsaglia's work: http://www.jstatsoft.org/v08/i14/paper - uint value = index; - value ^= value << 13; - value ^= value >> 17; - value ^= value << 5; - - float H = float(value & 511) / 511.0; - - //standard hue to HSV - float R = abs(H * 6 - 3) - 1; - float G = 2 - abs(H * 6 - 2); - float B = 2 - abs(H * 6 - 4); - return saturate(float3(R,G,B)); -} - -uint packVisibilityData(in VisibilityData data) -{ - uint packedData = 0; - packedData |= (data.DOTSInstanceIndex & 0xffff); - packedData |= (data.primitiveID & 0xffff) << 16; - return packedData; -} - -void unpackVisibilityData(uint packedVisData, out VisibilityData data) -{ - data.DOTSInstanceIndex = (packedVisData & 0xffff); - data.primitiveID = packedVisData >> 16; -} - -#endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.shader b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.shader index 1082d7a19ad..b96e2ab2be3 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.shader +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.shader @@ -12,7 +12,7 @@ Shader "HDRP/Visibility" HLSLINCLUDE #pragma target 4.5 - #pragma enable_d3d11_debug_symbols + //#pragma enable_d3d11_debug_symbols //------------------------------------------------------------------------------------- // Variant @@ -32,8 +32,7 @@ Shader "HDRP/Visibility" // variable declaration //------------------------------------------------------------------------------------- - // #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/Lit.cs.hlsl" - //#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Lit/LitProperties.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityProperties.hlsl" ENDHLSL @@ -59,6 +58,10 @@ Shader "HDRP/Visibility" #pragma instancing_options renderinglayer #pragma multi_compile _ DOTS_INSTANCING_ON + #define SHADERPASS SHADERPASS_VISIBILITY + + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityPass.hlsl" #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVisibility.hlsl" #pragma vertex Vert @@ -66,5 +69,35 @@ Shader "HDRP/Visibility" ENDHLSL } + + Pass + { + Name "ShadowCaster" + Tags{ "LightMode" = "ShadowCaster" } + + Cull Back + ZWrite On + ZTest LEqual + + HLSLPROGRAM + + #pragma only_renderers d3d11 playstation xboxone xboxseries vulkan metal switch + + //enable GPU instancing support + #pragma multi_compile_instancing + #pragma instancing_options renderinglayer + #pragma multi_compile _ DOTS_INSTANCING_ON + + #define SHADERPASS SHADERPASS_SHADOWS + + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityDepthPass.hlsl" + #include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassDepthOnly.hlsl" + + #pragma vertex Vert + #pragma fragment Frag + + ENDHLSL + } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl new file mode 100644 index 00000000000..fef48f3981b --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl @@ -0,0 +1,137 @@ +#ifndef VISIBILITY_HLSL +#define VISIBILITY_HLSL + +#include "Packages/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPool.hlsl" +#include "Packages/com.unity.render-pipelines.core/ShaderLibrary/UnityInstancing.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Lighting/LightLoop/LightLoop.cs.hlsl" + +TEXTURE2D_X_UINT(_VisBufferTexture0); +TEXTURE2D_X_UINT2(_VisBufferTexture1); + +TEXTURE2D_X_UINT(_VisBufferFeatureTiles); +TEXTURE2D_X_UINT2(_VisBufferMaterialTiles); +TEXTURE2D_X_UINT(_VisBufferBucketTiles); + +#define VIS_BUFFER_TILE_LOG2 6 +#define VIS_BUFFER_TILE_SIZE (1 << VIS_BUFFER_TILE_LOG2) //64 + +namespace Visibility +{ + +#define InvalidVisibilityData 0 + +struct VisibilityData +{ + bool valid; + uint DOTSInstanceIndex; + uint primitiveID; + uint batchID; +}; + +float3 DebugVisIndexToRGB(uint index, uint maxCol = 512) +{ + if (index == 0) + return float3(0, 0, 0); + + float indexf = sin(816.0f * (index % maxCol)) * 2.0; + { + indexf = frac(indexf * 0.011); + indexf *= indexf + 7.5; + indexf *= indexf + indexf; + indexf = frac(indexf); + } + + float H = indexf; + + //standard hue to HSV + float R = abs(H * 6 - 3) - 1; + float G = 2 - abs(H * 6 - 2); + float B = 2 - abs(H * 6 - 4); + return saturate(float3(R,G,B)); +} + +void PackVisibilityData(in VisibilityData data, out uint packedData0, out uint2 packedData1) +{ + packedData0 = 0; + packedData0 |= (data.DOTSInstanceIndex & 0xffff); + packedData0 |= (data.primitiveID & 0x7fff) << 16; + packedData0 |= (data.valid ? 1 : 0) << 31; + packedData1.x = data.batchID; + packedData1.y = (data.primitiveID >> 15) & 0xFF; +} + +void UnpackVisibilityData(uint packedData0, uint2 packedData1, out VisibilityData data) +{ + data.valid = (packedData0 >> 31) != 0; + data.DOTSInstanceIndex = (packedData0 & 0xffff); + data.primitiveID = ((packedData0 >> 16) & 0x7fff ) | (packedData1.y << 15); + data.batchID = packedData1.x; + +} + +uint GetMaterialKey(in VisibilityData visData, out GeoPoolMetadataEntry metadataEntry) +{ + if (!visData.valid) + { + metadataEntry = (GeoPoolMetadataEntry)0; + return 0; + } + + metadataEntry = GeometryPool::GetMetadataEntry(visData.DOTSInstanceIndex, visData.batchID); + return GeometryPool::GetMaterialKey(metadataEntry, visData.primitiveID); +} + +VisibilityData LoadVisibilityData(uint2 coord) +{ + uint value0 = LOAD_TEXTURE2D_X(_VisBufferTexture0, (uint2)coord.xy).x; + uint2 value1 = LOAD_TEXTURE2D_X(_VisBufferTexture1, (uint2)coord.xy).xy; + VisibilityData visData; + Visibility::UnpackVisibilityData(value0, value1, visData); + return visData; +} + +uint GetMaterialKey(in VisibilityData visData) +{ + GeoPoolMetadataEntry unused; + return GetMaterialKey(visData, unused); +} + +uint2 GetTileCoord(uint2 coord) +{ + return coord >> VIS_BUFFER_TILE_LOG2; +} + +uint LoadFeatureTile(uint2 tileCoord) +{ + return LOAD_TEXTURE2D_X(_VisBufferFeatureTiles, tileCoord).x; +} + +uint2 LoadMaterialTile(uint2 tileCoord) +{ + return LOAD_TEXTURE2D_X(_VisBufferMaterialTiles, tileCoord).xy; +} + +uint LoadBucketTile(uint2 tileCoord) +{ + return LOAD_TEXTURE2D_X(_VisBufferBucketTiles, tileCoord).x; +} + +float PackDepthMaterialKey(uint materialGPUBatchKey) +{ + return float(materialGPUBatchKey & 0xffffff) / (float)0xffffff; +} + +uint GetLightTileCategory(uint featureFlags) +{ + if ((featureFlags & VBUFFER_LIGHTING_FEATURES_ENV) !=0 && (featureFlags & ~VBUFFER_LIGHTING_FEATURES_ENV) == 0) + return LIGHTVBUFFERTILECATEGORY_ENV; + if ((featureFlags & VBUFFER_LIGHTING_FEATURES_ENV_PUNCTUAL) !=0 && (featureFlags & ~VBUFFER_LIGHTING_FEATURES_ENV_PUNCTUAL) == 0) + return LIGHTVBUFFERTILECATEGORY_ENV_PUNCTUAL; + if ((featureFlags & VBUFFER_LIGHTING_FEATURES_EVERYTHING) !=0 && (featureFlags & ~VBUFFER_LIGHTING_FEATURES_EVERYTHING) == 0) + return LIGHTVBUFFERTILECATEGORY_EVERYTHING; + return LIGHTVBUFFERTILECATEGORY_UNKNOWN; +} + +} + +#endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl.meta similarity index 100% rename from com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.hlsl.meta rename to com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl.meta diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityDepthPass.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityDepthPass.hlsl new file mode 100644 index 00000000000..03f49ef9766 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityDepthPass.hlsl @@ -0,0 +1,25 @@ +#ifndef SHADERPASS +#error Undefine_SHADERPASS +#endif + +//Attributes +#define ATTRIBUTE_NEEDS_PROCEDURAL_POSITION +#define ATTRIBUTES_NEED_VERTEX_ID + +// This include will define the various Attributes/Varyings structure +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl" + +float3 LoadPositionFromGeometryPool(AttributesMesh input) +{ + GeoPoolMetadataEntry metadata = _GeoPoolGlobalMetadataBuffer[(int)_DeferredMaterialInstanceData.x]; + GeoPoolVertex vertexData = GeometryPool::LoadVertex(input.vertexIndex, metadata); + return vertexData.pos; +} + +//required by VertMesh +#define CreateProceduralPositionOS LoadPositionFromGeometryPool + +//empty functions to satisfy ShaderPassDepthOnly.hlsl +struct SurfaceData {}; +struct BuiltinData {}; +void GetSurfaceAndBuiltinData(in FragInputs input, float3 V, in PositionInputs posInput, out SurfaceData surfaceData, out BuiltinData builtinData) {} diff --git a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/VisibilityBufferCommon.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityDepthPass.hlsl.meta similarity index 75% rename from com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/VisibilityBufferCommon.hlsl.meta rename to com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityDepthPass.hlsl.meta index b0ae85f8d0f..b53c1a787fc 100644 --- a/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/VisibilityBufferCommon.hlsl.meta +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityDepthPass.hlsl.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: c4be027cc80a3754b98ba8fecf84f63c +guid: d2693c5b026d4374a941603b829ce094 ShaderIncludeImporter: externalObjects: {} userData: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityPass.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityPass.hlsl new file mode 100644 index 00000000000..88f06208f6a --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityPass.hlsl @@ -0,0 +1,41 @@ +#ifndef SHADERPASS +#error Undefine_SHADERPASS +#endif + +//Attributes +#define ATTRIBUTE_NEEDS_PROCEDURAL_POSITION +#define ATTRIBUTES_NEED_VERTEX_ID +#define VARYINGS_NEED_PASS +#define VARYINGS_NEED_PRIMITIVEID + +// This include will define the various Attributes/Varyings structure +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl" + +//Declarations required by the attributes above + +struct PackedVaryingsPassToPS +{ + uint batchID : ATTRIBUTE6; +}; + +struct VaryingsPassToPS +{ + uint batchID; +}; + +PackedVaryingsPassToPS PackVaryingsPassToPS(VaryingsPassToPS vpass) +{ + PackedVaryingsPassToPS packedToPS; + packedToPS.batchID = vpass.batchID; + return packedToPS; +} + +float3 LoadPositionFromGeometryPool(AttributesMesh input) +{ + GeoPoolMetadataEntry metadata = _GeoPoolGlobalMetadataBuffer[(int)_DeferredMaterialInstanceData.x]; + GeoPoolVertex vertexData = GeometryPool::LoadVertex(input.vertexIndex, metadata); + return vertexData.pos; +} + +//required by VertMesh +#define CreateProceduralPositionOS LoadPositionFromGeometryPool diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityPass.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityPass.hlsl.meta new file mode 100644 index 00000000000..319e0fe53ea --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityPass.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: f839e6c8c258d9f4d80ade4074f38280 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityProperties.hlsl b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityProperties.hlsl new file mode 100644 index 00000000000..31c85ef0027 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityProperties.hlsl @@ -0,0 +1,14 @@ + +CBUFFER_START(UnityPerMaterial) + float4 _DeferredMaterialInstanceData; +CBUFFER_END + +#if defined(UNITY_DOTS_INSTANCING_ENABLED) + +UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata) + UNITY_DOTS_INSTANCED_PROP(float4, _DeferredMaterialInstanceData) +UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata) + +#define _DeferredMaterialInstanceData UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(float4, _DeferredMaterialInstanceData) + +#endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityProperties.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityProperties.hlsl.meta new file mode 100644 index 00000000000..ab0eeeb0dcf --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityProperties.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 62807284fb260ba468e86c48d02157bb +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs index d029016e098..5d7f59a8634 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDProfileId.cs @@ -21,6 +21,10 @@ internal enum HDProfileId DeferredDepthPrepass, TransparentDepthPrepass, VBuffer, + VBufferMaterialDepth, + VBufferLightTileClassification, + VBufferMaterialTileClassification, + VBufferLighting, GBuffer, DBufferRender, DBufferPrepareDrawData, diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs index f37ca079d89..3c681730d2e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Debug.cs @@ -349,12 +349,13 @@ class ResolveFullScreenDebugPassData public ComputeBuffer depthPyramidOffsets; public TextureHandle output; public TextureHandle input; - public TextureHandle vBuffer; + public VBufferInformation vBufferInfo; public TextureHandle depthPyramid; public ComputeBufferHandle fullscreenBuffer; + public RenderBRGBindingData BRGBindData; } - TextureHandle ResolveFullScreenDebug(RenderGraph renderGraph, TextureHandle inputFullScreenDebug, TextureHandle vBuffer, TextureHandle depthPyramid, HDCamera hdCamera, GraphicsFormat rtFormat = GraphicsFormat.R16G16B16A16_SFloat) + TextureHandle ResolveFullScreenDebug(RenderGraph renderGraph, TextureHandle inputFullScreenDebug, VBufferInformation vBufferInfo, TextureHandle depthPyramid, HDCamera hdCamera, GraphicsFormat rtFormat = GraphicsFormat.R16G16B16A16_SFloat) { using (var builder = renderGraph.AddRenderPass("ResolveFullScreenDebug", out var passData)) { @@ -362,7 +363,7 @@ TextureHandle ResolveFullScreenDebug(RenderGraph renderGraph, TextureHandle inpu passData.debugDisplaySettings = m_CurrentDebugDisplaySettings; passData.debugFullScreenMaterial = m_DebugFullScreen; passData.input = builder.ReadTexture(inputFullScreenDebug); - passData.vBuffer = builder.ReadTexture(vBuffer); + passData.vBufferInfo = vBufferInfo.Read(builder); passData.depthPyramid = builder.ReadTexture(depthPyramid); passData.depthPyramidMip = (int)(m_CurrentDebugDisplaySettings.data.fullscreenDebugMip * hdCamera.depthBufferMipChainInfo.mipLevelCount); passData.depthPyramidOffsets = hdCamera.depthBufferMipChainInfo.GetOffsetBufferData(m_DepthPyramidMipLevelOffsetsBuffer); @@ -375,15 +376,23 @@ TextureHandle ResolveFullScreenDebug(RenderGraph renderGraph, TextureHandle inpu passData.output = builder.WriteTexture(renderGraph.CreateTexture(new TextureDesc(Vector2.one, false /* we dont want DRS on this output target*/, true /*We want XR support on this output target*/) { colorFormat = rtFormat, name = "ResolveFullScreenDebug" })); + passData.BRGBindData = new RenderBRGBindingData(); + if (IsVisibilityPassEnabled()) + passData.BRGBindData = RenderBRG.GetRenderBRGMaterialBindingData(); + builder.SetRenderFunc( (ResolveFullScreenDebugPassData data, RenderGraphContext ctx) => { var mpb = ctx.renderGraphPool.GetTempMaterialPropertyBlock(); ComputeBuffer fullscreenBuffer = data.fullscreenBuffer; + if (data.vBufferInfo.valid) + data.debugFullScreenMaterial.EnableKeyword("DOTS_INSTANCING_ON"); + else + data.debugFullScreenMaterial.DisableKeyword("DOTS_INSTANCING_ON"); + mpb.SetTexture(HDShaderIDs._DebugFullScreenTexture, data.input); mpb.SetTexture(HDShaderIDs._CameraDepthTexture, data.depthPyramid); - mpb.SetTexture(HDShaderIDs._VisibilityTexture, data.vBuffer); mpb.SetFloat(HDShaderIDs._FullScreenDebugMode, (float)data.debugDisplaySettings.data.fullScreenDebugMode); if (data.debugDisplaySettings.data.enableDebugDepthRemap) mpb.SetVector(HDShaderIDs._FullScreenDebugDepthRemap, new Vector4(data.debugDisplaySettings.data.fullScreenDebugDepthRemap.x, data.debugDisplaySettings.data.fullScreenDebugDepthRemap.y, data.hdCamera.camera.nearClipPlane, data.hdCamera.camera.farClipPlane)); @@ -400,6 +409,9 @@ TextureHandle ResolveFullScreenDebug(RenderGraph renderGraph, TextureHandle inpu if (fullscreenBuffer != null) ctx.cmd.SetRandomWriteTarget(1, fullscreenBuffer); + if (data.vBufferInfo.valid) + BindVBufferResources(data.debugFullScreenMaterial, data.vBufferInfo); + HDUtils.DrawFullScreen(ctx.cmd, data.debugFullScreenMaterial, data.output, mpb, 0); if (fullscreenBuffer != null) @@ -1153,7 +1165,7 @@ TextureHandle RenderExposureDebug(RenderGraph renderGraph, HDCamera hdCamera, Te TextureHandle RenderDebug(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer, - TextureHandle vBuffer, + VBufferInformation vBufferInfo, TextureHandle depthBuffer, TextureHandle depthPyramidTexture, TextureHandle colorPickerDebugTexture, @@ -1172,7 +1184,7 @@ TextureHandle RenderDebug(RenderGraph renderGraph, if (NeedsFullScreenDebugMode() && m_FullScreenDebugPushed) { - output = ResolveFullScreenDebug(renderGraph, m_DebugFullScreenTexture, vBuffer, depthPyramidTexture, hdCamera, colorFormat); + output = ResolveFullScreenDebug(renderGraph, m_DebugFullScreenTexture, vBufferInfo, depthPyramidTexture, hdCamera, colorFormat); // If we have full screen debug, this is what we want color picked, so we replace color picker input texture with the new one. if (NeedColorPickerDebug(m_CurrentDebugDisplaySettings)) diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs index a811ed3cee1..cb77207e380 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Prepass.cs @@ -219,7 +219,7 @@ PrepassOutput RenderPrepass(RenderGraph renderGraph, RenderObjectsMotionVectors(renderGraph, cullingResults, hdCamera, decalBuffer, result); } - RenderVBuffer(renderGraph, hdCamera, cullingResults, ref result); + RenderVBuffer(renderGraph, colorBuffer, hdCamera, cullingResults, ref result); // If we have MSAA, we need to complete the motion vector buffer before buffer resolves, hence we need to run camera mv first. // This is always fine since shouldRenderMotionVectorAfterGBuffer is always false for forward. diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs index b459ef926b5..ae884d16521 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.RenderGraph.cs @@ -101,6 +101,8 @@ void RecordRenderGraph(RenderRequest renderRequest, TextureHandle uiBuffer = m_RenderGraph.defaultResources.blackTextureXR; TextureHandle sunOcclusionTexture = m_RenderGraph.defaultResources.whiteTexture; + var vBufferInfo = VBufferInformation.NewDefault(); + if (m_CurrentDebugDisplaySettings.IsDebugDisplayEnabled() && m_CurrentDebugDisplaySettings.IsFullScreenDebugPassEnabled()) { // Stop Single Pass is after post process. @@ -183,6 +185,10 @@ void RecordRenderGraph(RenderRequest renderRequest, var volumetricLighting = VolumetricLightingPass(m_RenderGraph, hdCamera, prepassOutput.depthPyramidTexture, volumetricDensityBuffer, maxZMask, gpuLightListOutput.bigTileLightList, shadowResult); + vBufferInfo = VBufferTileClassification(m_RenderGraph, hdCamera, gpuLightListOutput.tileFeatureFlags, colorBuffer, prepassOutput.vbuffer); + + colorBuffer = RenderVBufferLighting(m_RenderGraph, cullingResults, hdCamera, vBufferInfo, shadowResult, colorBuffer, prepassOutput.depthBuffer, lightingBuffers, gpuLightListOutput); + var deferredLightingOutput = RenderDeferredLighting(m_RenderGraph, hdCamera, colorBuffer, prepassOutput.depthBuffer, prepassOutput.depthPyramidTexture, lightingBuffers, prepassOutput.gbuffer, shadowResult, gpuLightListOutput); ApplyCameraMipBias(hdCamera); @@ -311,7 +317,7 @@ void RecordRenderGraph(RenderRequest renderRequest, postProcessDest = RenderDebug(m_RenderGraph, hdCamera, postProcessDest, - prepassOutput.vbuffer.vbuffer, + vBufferInfo, prepassOutput.resolvedDepthBuffer, prepassOutput.depthPyramidTexture, colorPickerTexture, diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Visibility.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Visibility.cs index 6434a51a4ed..9b4f1e0344e 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Visibility.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.Visibility.cs @@ -9,7 +9,40 @@ public partial class HDRenderPipeline { struct VBufferOutput { - public TextureHandle vbuffer; + public bool valid; + public TextureHandle vbuffer0; + public TextureHandle vbuffer1; + public TextureHandle vbufferMaterialDepth; + public RenderBRGBindingData BRGBindingData; + + public static VBufferOutput NewDefault() + { + return new VBufferOutput() + { + valid = false, + vbuffer0 = TextureHandle.nullHandle, + vbuffer1 = TextureHandle.nullHandle, + vbufferMaterialDepth = TextureHandle.nullHandle, + BRGBindingData = RenderBRGBindingData.NewDefault() + }; + } + + public VBufferOutput Read(RenderGraphBuilder builder, bool readMaterialDepth = false) + { + VBufferOutput readVBuffer = VBufferOutput.NewDefault(); + if (!valid) + return readVBuffer; + + readVBuffer.valid = valid; + readVBuffer.vbuffer0 = builder.ReadTexture(vbuffer0); + readVBuffer.vbuffer1 = builder.ReadTexture(vbuffer1); + if (readMaterialDepth) + readVBuffer.vbufferMaterialDepth = builder.ReadTexture(vbufferMaterialDepth); + else + readVBuffer.vbufferMaterialDepth = vbufferMaterialDepth; + readVBuffer.BRGBindingData = BRGBindingData; + return readVBuffer; + } } internal bool IsVisibilityPassEnabled() @@ -21,21 +54,28 @@ class VBufferPassData { public FrameSettings frameSettings; public RendererListHandle rendererList; + public RenderBRGBindingData BRGBindingData; } - void RenderVBuffer(RenderGraph renderGraph, HDCamera hdCamera, CullingResults cull, ref PrepassOutput output) + void RenderVBuffer(RenderGraph renderGraph, TextureHandle colorBuffer, HDCamera hdCamera, CullingResults cull, ref PrepassOutput output) { - output.vbuffer = new VBufferOutput(); + output.vbuffer = VBufferOutput.NewDefault(); - var globalGeoPool = RenderBRG.FindGlobalGeometryPool(); - if (!IsVisibilityPassEnabled() || globalGeoPool == null) + var BRGBindingData = RenderBRG.GetRenderBRGMaterialBindingData(); + if (!IsVisibilityPassEnabled() || !BRGBindingData.valid) { - output.vbuffer.vbuffer = renderGraph.defaultResources.blackUIntTextureXR; + output.vbuffer.vbuffer0 = renderGraph.defaultResources.blackUIntTextureXR; + output.vbuffer.vbuffer1 = renderGraph.defaultResources.blackUIntTextureXR; + output.vbuffer.vbufferMaterialDepth = renderGraph.defaultResources.blackUIntTextureXR; return; } var visibilityMaterial = currentAsset.VisibilityMaterial; - var visFormat = GraphicsFormat.R32_UInt; + var visFormat0 = GraphicsFormat.R32_UInt; + var visFormat1 = GraphicsFormat.R8G8_UInt; + output.vbuffer.valid = true; + + TextureHandle vbuffer0, vbuffer1; using (var builder = renderGraph.AddRenderPass("VBuffer", out var passData, ProfilingSampler.Get(HDProfileId.VBuffer))) { builder.AllowRendererListCulling(false); @@ -45,28 +85,400 @@ void RenderVBuffer(RenderGraph renderGraph, HDCamera hdCamera, CullingResults cu passData.frameSettings = frameSettings; output.depthBuffer = builder.UseDepthBuffer(output.depthBuffer, DepthAccess.ReadWrite); - output.vbuffer.vbuffer = builder.UseColorBuffer(renderGraph.CreateTexture( + vbuffer0 = builder.UseColorBuffer(renderGraph.CreateTexture( new TextureDesc(Vector2.one, true, true) { - colorFormat = visFormat, + colorFormat = visFormat0, clearBuffer = true,//TODO: for now clear clearColor = Color.clear, - name = "VisibilityBuffer" + name = "VisibilityBuffer0" }), 0); + vbuffer1 = builder.UseColorBuffer(renderGraph.CreateTexture( + new TextureDesc(Vector2.one, true, true) + { + colorFormat = visFormat1, + clearColor = Color.clear, + name = "VisibilityBuffer1" + }), 1); + passData.BRGBindingData = BRGBindingData; passData.rendererList = builder.UseRendererList( renderGraph.CreateRendererList(CreateOpaqueRendererListDesc( cull, hdCamera.camera, - HDShaderPassNames.s_VBufferName, m_CurrentRendererConfigurationBakedLighting, null, null, visibilityMaterial, excludeObjectMotionVectors: false))); - - globalGeoPool.BindResources(visibilityMaterial); + HDShaderPassNames.s_VBufferName, + m_CurrentRendererConfigurationBakedLighting, + new RenderQueueRange() { lowerBound = (int)HDRenderQueue.Priority.Visibility, upperBound = (int)(int)HDRenderQueue.Priority.Visibility }))); builder.SetRenderFunc( (VBufferPassData data, RenderGraphContext context) => { + data.BRGBindingData.globalGeometryPool.BindResourcesGlobal(context.cmd); + DrawOpaqueRendererList(context, data.frameSettings, data.rendererList); + }); + } + + output.vbuffer.valid = true; + output.vbuffer.vbuffer0 = vbuffer0; + output.vbuffer.vbuffer1 = vbuffer1; + output.vbuffer.vbufferMaterialDepth = RenderMaterialDepth(renderGraph, hdCamera, colorBuffer); + output.vbuffer.BRGBindingData = BRGBindingData; + } + + static void BindVBufferResources(Material material, in VBufferOutput resources) + { + material.SetTexture(HDShaderIDs._VisBufferTexture0, resources.vbuffer0); + material.SetTexture(HDShaderIDs._VisBufferTexture1, resources.vbuffer1); + resources.BRGBindingData.globalGeometryPool.BindResources(material); + } + + static void BindVBufferResourcesCS(CommandBuffer cmd, ComputeShader cs, int kernel, in VBufferOutput resources) + { + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferTexture0, resources.vbuffer0); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferTexture1, resources.vbuffer1); + resources.BRGBindingData.globalGeometryPool.BindResourcesCS(cmd, cs, kernel); + } + + static void BindVBufferResourcesGlobal(CommandBuffer cmd, in VBufferOutput resources) + { + cmd.SetGlobalTexture(HDShaderIDs._VisBufferTexture0, resources.vbuffer0); + cmd.SetGlobalTexture(HDShaderIDs._VisBufferTexture1, resources.vbuffer1); + resources.BRGBindingData.globalGeometryPool.BindResourcesGlobal(cmd); + } + + static void BindVBufferResources(Material material, in VBufferInformation vBufferInfo) + { + BindVBufferResources(material, vBufferInfo.vBufferResources); + material.SetTexture(HDShaderIDs._VisBufferFeatureTiles, vBufferInfo.featureTileClassification); + material.SetTexture(HDShaderIDs._VisBufferMaterialTiles, vBufferInfo.materialTileClassification); + material.SetTexture(HDShaderIDs._VisBufferBucketTiles, vBufferInfo.materialBucketID); + } + + static void BindVBufferResourcesCS(CommandBuffer cmd, ComputeShader cs, int kernel, in VBufferInformation vBufferInfo) + { + BindVBufferResourcesCS(cmd, cs, kernel, vBufferInfo.vBufferResources); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferFeatureTiles, vBufferInfo.featureTileClassification); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferMaterialTiles, vBufferInfo.materialTileClassification); + cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferBucketTiles, vBufferInfo.materialBucketID); + } + + static void BindVBufferResourcesGlobal(CommandBuffer cmd, in VBufferInformation vBufferInfo) + { + BindVBufferResourcesGlobal(cmd, vBufferInfo.vBufferResources); + cmd.SetGlobalTexture(HDShaderIDs._VisBufferFeatureTiles, vBufferInfo.featureTileClassification); + cmd.SetGlobalTexture(HDShaderIDs._VisBufferMaterialTiles, vBufferInfo.materialTileClassification); + cmd.SetGlobalTexture(HDShaderIDs._VisBufferBucketTiles, vBufferInfo.materialBucketID); + } + + class VBufferMaterialDepthPassData + { + public TextureHandle outputDepthBuffer; + public TextureHandle dummyColorOutput; + public Material createMaterialDepthMaterial; + } + + TextureHandle RenderMaterialDepth(RenderGraph renderGraph, HDCamera hdCamera, TextureHandle colorBuffer) + { + if (!IsVisibilityPassEnabled() || currentAsset.CreateMaterialDepthMaterial == null) + return TextureHandle.nullHandle; + + var outputDepth = CreateDepthBuffer(renderGraph, true, hdCamera.msaaSamples); + using (var builder = renderGraph.AddRenderPass("Create Vis Buffer Material Depth", out var passData, ProfilingSampler.Get(HDProfileId.VBufferMaterialDepth))) + { + passData.outputDepthBuffer = outputDepth; + passData.createMaterialDepthMaterial = currentAsset.CreateMaterialDepthMaterial; + passData.dummyColorOutput = builder.WriteTexture(colorBuffer); + builder.UseDepthBuffer(passData.outputDepthBuffer, DepthAccess.ReadWrite); + + builder.SetRenderFunc( + (VBufferMaterialDepthPassData data, RenderGraphContext context) => + { + // Doesn't matter what's bound as color buffer + HDUtils.DrawFullScreen(context.cmd, passData.createMaterialDepthMaterial, passData.dummyColorOutput, passData.outputDepthBuffer, null, 0); + }); + } + + return outputDepth; + } + + struct VBufferInformation + { + public VBufferOutput vBufferResources; + public TextureHandle featureTileClassification; + public TextureHandle materialTileClassification; + public TextureHandle materialBucketID; + + public static VBufferInformation NewDefault() + { + return new VBufferInformation() + { + vBufferResources = VBufferOutput.NewDefault() + }; + } + + public VBufferInformation Read(RenderGraphBuilder builder, bool readMaterialDepth = false) + { + var newInfo = VBufferInformation.NewDefault(); + if (!valid) + return newInfo; + + newInfo.vBufferResources = vBufferResources.Read(builder); + newInfo.featureTileClassification = builder.ReadTexture(featureTileClassification); + newInfo.materialTileClassification = builder.ReadTexture(materialTileClassification); + newInfo.materialBucketID = builder.ReadTexture(materialBucketID); + return newInfo; + } + + public bool valid => vBufferResources.valid; + } + + VBufferInformation VBufferTileClassification( + RenderGraph renderGraph, HDCamera hdCamera, ComputeBufferHandle tileFeatureFlags, TextureHandle colorBuffer, VBufferOutput vBufferResources) + { + var vBufferInfo = VBufferInformation.NewDefault(); + if (!IsVisibilityPassEnabled()) + return vBufferInfo; + + vBufferInfo.vBufferResources = vBufferResources; + vBufferInfo.featureTileClassification = VBufferFeatureTileClassification(renderGraph, hdCamera, tileFeatureFlags, colorBuffer); + VBufferMaterialTileClassification(renderGraph, hdCamera, vBufferResources, out vBufferInfo.materialTileClassification, out vBufferInfo.materialBucketID); + return vBufferInfo; + } + + + class VBufferTileClassficationData + { + public int tileClassSizeX; + public int tileClassSizeY; + public ComputeShader createTileClassification; + public TextureHandle outputTile; + public ComputeBufferHandle tileFeatureFlagsBuffer; + } + + TextureHandle VBufferFeatureTileClassification(RenderGraph renderGraph, HDCamera hdCamera, ComputeBufferHandle tileFeatureFlags, TextureHandle colorBuffer) + { + if (!IsVisibilityPassEnabled()) + return TextureHandle.nullHandle; + + int tileClassSizeX = HDUtils.DivRoundUp(hdCamera.actualWidth, 64); + int tileClassSizeY = HDUtils.DivRoundUp(hdCamera.actualHeight, 64); + + var tileClassification = renderGraph.CreateTexture(new TextureDesc(tileClassSizeX, tileClassSizeY, true, true) + { colorFormat = GraphicsFormat.R32G32_UInt, clearBuffer = true, enableRandomWrite = true, name = "VBufferFeatureTile" }); + using (var builder = renderGraph.AddRenderPass("Create VBuffer Tiles", out var passData, ProfilingSampler.Get(HDProfileId.VBufferLightTileClassification))) + { + passData.outputTile = builder.WriteTexture(tileClassification); + + passData.tileClassSizeX = tileClassSizeX; + passData.tileClassSizeY = tileClassSizeY; + passData.createTileClassification = defaultResources.shaders.vbufferTileClassificationCS; + passData.tileFeatureFlagsBuffer = builder.ReadComputeBuffer(tileFeatureFlags); + + builder.AllowPassCulling(false); + + builder.SetRenderFunc( + (VBufferTileClassficationData data, RenderGraphContext context) => + { + var cs = data.createTileClassification; + var kernel = cs.FindKernel("FeatureTileClassifyReduction"); + + context.cmd.SetComputeBufferParam(cs, kernel, HDShaderIDs.g_TileFeatureFlags, data.tileFeatureFlagsBuffer); + context.cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferFeatureTileOutput, data.outputTile); + + int dispatchX = HDUtils.DivRoundUp(data.tileClassSizeX, 8); + int dispatchY = HDUtils.DivRoundUp(data.tileClassSizeY, 8); + + context.cmd.SetComputeVectorParam(cs, HDShaderIDs._VisBufferTileSize, new Vector4(data.tileClassSizeX, data.tileClassSizeY, 0, 0)); + + context.cmd.DispatchCompute(cs, kernel, dispatchX, dispatchY, 1); + }); + } + + return tileClassification; + } + + class VBufferMaterialTileClassficationData + { + public int tileClassSizeX; + public int tileClassSizeY; + public ComputeShader createMaterialTile; + public TextureHandle outputTile; + public TextureHandle outputBucketTile; + public TextureHandle tile8x; + public TextureHandle bucketTile8x; + public VBufferOutput vBufferResources; + public int actualWidth; + public int actualHeight; + public ComputeBufferHandle instancedDataBuffer; + } + + void VBufferMaterialTileClassification(RenderGraph renderGraph, HDCamera hdCamera, in VBufferOutput vBufferResources, out TextureHandle tileClassification, out TextureHandle bucketID) + { + if (!IsVisibilityPassEnabled() || !vBufferResources.valid) + { + tileClassification = TextureHandle.nullHandle; + bucketID = TextureHandle.nullHandle; + return; + } + + int tileClassSizeX = HDUtils.DivRoundUp(hdCamera.actualWidth, 64); + int tileClassSizeY = HDUtils.DivRoundUp(hdCamera.actualHeight, 64); + + tileClassification = renderGraph.CreateTexture(new TextureDesc(tileClassSizeX, tileClassSizeY, true, true) + { colorFormat = GraphicsFormat.R16G16_UInt, clearBuffer = true, enableRandomWrite = true, name = "Material Tile classification" }); + bucketID = renderGraph.CreateTexture(new TextureDesc(tileClassSizeX, tileClassSizeY, true, true) + { colorFormat = GraphicsFormat.R8_UInt, clearBuffer = true, enableRandomWrite = true, name = "Bucket ID" }); + + using (var builder = renderGraph.AddRenderPass("Create Material Tile", out var passData, ProfilingSampler.Get(HDProfileId.VBufferMaterialTileClassification))) + { + builder.AllowPassCulling(false); + + int tileClassSizeIntermediateX = HDUtils.DivRoundUp(hdCamera.actualWidth, 8); + int tileClassSizeIntermediateY = HDUtils.DivRoundUp(hdCamera.actualHeight, 8); + passData.tile8x = builder.CreateTransientTexture(new TextureDesc(tileClassSizeIntermediateX, tileClassSizeIntermediateY, true, true) + { colorFormat = GraphicsFormat.R16G16_UInt, enableRandomWrite = true, name = "Material mask 8x" }); + passData.bucketTile8x = builder.CreateTransientTexture(new TextureDesc(tileClassSizeIntermediateX, tileClassSizeIntermediateY, true, true) + { colorFormat = GraphicsFormat.R8_UInt, enableRandomWrite = true, name = "Bucket mask 8x" }); + + passData.tileClassSizeX = tileClassSizeX; + passData.tileClassSizeY = tileClassSizeY; + passData.outputTile = builder.WriteTexture(tileClassification); + passData.outputBucketTile = builder.WriteTexture(bucketID); + passData.vBufferResources = vBufferResources.Read(builder); + + passData.createMaterialTile = defaultResources.shaders.vbufferTileClassificationCS; + + passData.actualWidth = hdCamera.actualWidth; + passData.actualHeight = hdCamera.actualHeight; + + builder.SetRenderFunc( + (VBufferMaterialTileClassficationData data, RenderGraphContext context) => + { + var cs = data.createMaterialTile; + var kernel = cs.FindKernel("MaterialReduction"); + + context.cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferMaterialTileOutput, data.tile8x); + context.cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferBucketTileOutput, data.bucketTile8x); + + int dispatchX = HDUtils.DivRoundUp(data.actualWidth, 8); + int dispatchY = HDUtils.DivRoundUp(data.actualHeight, 8); + + BindVBufferResourcesCS(context.cmd, cs, kernel, data.vBufferResources); + + context.cmd.DispatchCompute(cs, kernel, dispatchX, dispatchY, 1); + + kernel = cs.FindKernel("MaterialFinalReduction"); + context.cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferMaterialTileInput, data.tile8x); + context.cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferBucketTileInput, data.bucketTile8x); + context.cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferMaterialTileOutput, data.outputTile); + context.cmd.SetComputeTextureParam(cs, kernel, HDShaderIDs._VisBufferBucketTileOutput, data.outputBucketTile); + + dispatchX = HDUtils.DivRoundUp(dispatchX, 8); + dispatchY = HDUtils.DivRoundUp(dispatchY, 8); + + context.cmd.DispatchCompute(cs, kernel, dispatchX, dispatchY, 1); + }); + } + } + + class VBufferLightingPassData : ForwardOpaquePassData + { + public int width; + public int height; + public TextureHandle colorBuffer; + public VBufferInformation vBufferInfo; + public TextureHandle materialDepthBuffer; + public TextureHandle cameraDepthTexture; + + //TODO: render lists get deallocated when calling DrawOpaqueRendererList immediately. + //Workaround is to declare 3 renderer lists for each draw renderes call, which sounds really freaking wasteful. + //We should instead build the renderer list once, and be able to draw many times. Check with seb. + //public RendererListHandle rendererList0; + public RendererListHandle rendererList1; + public RendererListHandle rendererList2; + } + + TextureHandle RenderVBufferLighting( + RenderGraph renderGraph, + CullingResults cull, + HDCamera hdCamera, + VBufferInformation vBufferInfo, + ShadowResult shadowResult, + TextureHandle colorBuffer, + TextureHandle depthBuffer, + in LightingBuffers lightingBuffers, + in BuildGPULightListOutput lightLists) + { + if (!vBufferInfo.valid) + return colorBuffer; + + using (var builder = renderGraph.AddRenderPass("VBuffer Lighting", out var passData, ProfilingSampler.Get(HDProfileId.VBufferLighting))) + { + var renderListDesc = CreateOpaqueRendererListDesc( + cull, + hdCamera.camera, + HDShaderPassNames.s_VBufferLightingName, m_CurrentRendererConfigurationBakedLighting); + //TODO: hide this from the UI!! + renderListDesc.renderingLayerMask = DeferredMaterialBRG.RenderLayerMask; + + PrepareCommonForwardPassData(renderGraph, builder, passData, true, hdCamera.frameSettings, renderListDesc, lightLists, shadowResult); + passData.rendererList1 = builder.UseRendererList(renderGraph.CreateRendererList(renderListDesc)); + passData.rendererList2 = builder.UseRendererList(renderGraph.CreateRendererList(renderListDesc)); + + builder.AllowRendererListCulling(false); + + passData.width = hdCamera.actualWidth; + passData.height = hdCamera.actualHeight; + passData.colorBuffer = builder.UseColorBuffer(colorBuffer, 0); + passData.vBufferInfo = vBufferInfo.Read(builder); + passData.materialDepthBuffer = builder.UseDepthBuffer(passData.vBufferInfo.vBufferResources.vbufferMaterialDepth, DepthAccess.ReadWrite); + passData.cameraDepthTexture = builder.ReadTexture(depthBuffer); + + passData.enableDecals = hdCamera.frameSettings.IsEnabled(FrameSettingsField.Decals); + passData.lightingBuffers = ReadLightingBuffers(lightingBuffers, builder); + + builder.SetRenderFunc( + (VBufferLightingPassData data, RenderGraphContext context) => + { + BindGlobalLightListBuffers(data, context); + BindDBufferGlobalData(data.dbuffer, context); + BindGlobalLightingBuffers(data.lightingBuffers, context.cmd); + + context.cmd.SetGlobalTexture(HDShaderIDs._VisBufferDepthTexture, data.cameraDepthTexture); + BindVBufferResourcesGlobal(context.cmd, passData.vBufferInfo); + + int quadTileSize = DeferredMaterialBRG.MaterialTileSize; + int numTileX = HDUtils.DivRoundUp(data.width, quadTileSize); + int numTileY = HDUtils.DivRoundUp(data.height, quadTileSize); + + // Note: SHADOWS_SHADOWMASK keyword is enabled in HDRenderPipeline.cs ConfigureForShadowMask + bool useFptl = data.frameSettings.IsEnabled(FrameSettingsField.FPTLForForwardOpaque); + // say that we want to use tile/cluster light loop + CoreUtils.SetKeyword(context.cmd, "USE_FPTL_LIGHTLIST", useFptl); + CoreUtils.SetKeyword(context.cmd, "USE_CLUSTERED_LIGHTLIST", !useFptl); + + context.cmd.SetGlobalVector(HDShaderIDs._VisBufferTileData, new Vector4((float)numTileX, (float)numTileY, (float)quadTileSize, (float)(numTileX * numTileY))); + + context.cmd.SetViewport(new Rect(0, 0, numTileX * quadTileSize, numTileY * quadTileSize)); + + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_ENV", false); + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_PUNCTUAL_ENV", false); + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_PUNCTUAL_AREA_ENV", true); DrawOpaqueRendererList(context, data.frameSettings, data.rendererList); + + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_ENV", true); + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_PUNCTUAL_ENV", false); + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_PUNCTUAL_AREA_ENV", false); + DrawOpaqueRendererList(context, data.frameSettings, data.rendererList1); + + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_ENV", false); + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_PUNCTUAL_AREA_ENV", false); + CoreUtils.SetKeyword(context.cmd, "VARIANT_DIR_PUNCTUAL_ENV", true); + DrawOpaqueRendererList(context, data.frameSettings, data.rendererList2); }); + + PushFullScreenDebugTexture(renderGraph, colorBuffer, FullScreenDebugMode.VisibilityBufferLighting); } + return colorBuffer; } } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs index 0fd2a5f795e..fcdf4ff3022 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipeline.cs @@ -2520,6 +2520,8 @@ static RendererListDesc CreateOpaqueRendererListDesc( sortingCriteria = SortingCriteria.CommonOpaque, stateBlock = stateBlock, overrideMaterial = overrideMaterial, + //TODO: hide this layer from the user so we can reserve it for the SRP + renderingLayerMask = ~DeferredMaterialBRG.RenderLayerMask, //exclude the deferred material draw calls by default. excludeObjectMotionVectors = excludeObjectMotionVectors }; return result; @@ -2543,6 +2545,7 @@ static RendererListDesc CreateOpaqueRendererListDesc( sortingCriteria = SortingCriteria.CommonOpaque, stateBlock = stateBlock, overrideMaterial = overrideMaterial, + renderingLayerMask = ~DeferredMaterialBRG.RenderLayerMask, //exclude the deferred material draw calls by default. excludeObjectMotionVectors = excludeObjectMotionVectors }; return result; @@ -2566,6 +2569,7 @@ static RendererListDesc CreateTransparentRendererListDesc( sortingCriteria = SortingCriteria.CommonTransparent | SortingCriteria.RendererPriority, stateBlock = stateBlock, overrideMaterial = overrideMaterial, + renderingLayerMask = ~DeferredMaterialBRG.RenderLayerMask, //exclude the deferred material draw calls by default. excludeObjectMotionVectors = excludeObjectMotionVectors }; return result; @@ -2589,6 +2593,7 @@ static RendererListDesc CreateTransparentRendererListDesc( sortingCriteria = SortingCriteria.CommonTransparent | SortingCriteria.RendererPriority, stateBlock = stateBlock, overrideMaterial = overrideMaterial, + renderingLayerMask = ~DeferredMaterialBRG.RenderLayerMask, //exclude the deferred material draw calls by default. excludeObjectMotionVectors = excludeObjectMotionVectors }; return result; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs index 9c1a86395ac..abfcdacab65 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineAsset.cs @@ -227,13 +227,40 @@ bool UpdateDefineList(bool flagValue, string defineMacroValue) private static Material s_VisibilityMaterial = null; public Material VisibilityMaterial { get { return s_VisibilityMaterial; } } + private static Material s_CreateMaterialDepthMaterial = null; + public Material CreateMaterialDepthMaterial { get { return s_CreateMaterialDepthMaterial; } } + + internal bool HasVlightingPass(Material m) + { + for (int i = 0; i < m.passCount; ++i) + { + if (m.GetPassName(i).IndexOf(HDShaderPassNames.s_VBufferLightingStr) >= 0) + return true; + } + + return false; + } + public RenderBRGMaterialRenderInfo GetMaterialInfoForBRG(RenderBRGGetMaterialRenderInfoArgs arguments) { + if (HDRenderPipeline.IsTransparentMaterial(arguments.material) || HDRenderPipeline.IsAlphaTestedMaterial(arguments.material)) + return new RenderBRGMaterialRenderInfo() { supportsVisibility = false, supportsBRGRendering = false }; + + if (!HasVlightingPass(arguments.material)) + return new RenderBRGMaterialRenderInfo() { supportsVisibility = false, supportsBRGRendering = true }; + if (s_VisibilityMaterial == null) + { s_VisibilityMaterial = CoreUtils.CreateEngineMaterial(globalSettings.renderPipelineResources.shaders.visibilityPS); + s_VisibilityMaterial.renderQueue = (int)HDRenderQueue.Priority.Visibility; + } + + if (s_CreateMaterialDepthMaterial == null) + s_CreateMaterialDepthMaterial = CoreUtils.CreateEngineMaterial(globalSettings.renderPipelineResources.shaders.createMaterialDepthPS); return new RenderBRGMaterialRenderInfo() { + supportsBRGRendering = true, supportsVisibility = true, materialOverride = s_VisibilityMaterial }; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs index d84e15e8588..a478bbfc2fd 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderPipelineRuntimeResources.cs @@ -127,6 +127,10 @@ public sealed class ShaderResources [Reload("Runtime/Material/Visibility/Visibility.shader")] public Shader visibilityPS; + [Reload("Runtime/Material/Visibility/CreateMaterialDepth.shader")] + public Shader createMaterialDepthPS; + [Reload("Runtime/Material/Visibility/VBufferClassification.compute")] + public ComputeShader vbufferTileClassificationCS; // Sky [Reload("Runtime/Sky/BlitCubemap.shader")] diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderQueue.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderQueue.cs index 0e3697c0344..07f063e065a 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderQueue.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDRenderQueue.cs @@ -44,7 +44,9 @@ public enum Priority AfterPostprocessTransparent = 3700, AfterPostprocessTransparentLast = 3700 + k_TransparentPriorityQueueRangeStep, - Overlay = RenderQueue.Overlay + Overlay = RenderQueue.Overlay, + + Visibility = Overlay + 500 } public enum RenderQueueType diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs index b3c84f2abc7..ceb42ba0186 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/HDStringConstants.cs @@ -18,6 +18,8 @@ public static class HDShaderPassNames public static readonly string s_VBufferStr = "VBuffer"; /// GBuffer pass name. public static readonly string s_GBufferStr = "GBuffer"; + /// VBufferLighting pass name. + public static readonly string s_VBufferLightingStr = "VBufferLighting"; /// GBuffer With Prepass pass name. public static readonly string s_GBufferWithPrepassStr = "GBufferWithPrepass"; /// Legacy Unlit cross pipeline pass name. @@ -77,6 +79,8 @@ public static class HDShaderPassNames public static readonly ShaderTagId s_VBufferName = new ShaderTagId(s_VBufferStr); /// GBuffer shader tag id. public static readonly ShaderTagId s_GBufferName = new ShaderTagId(s_GBufferStr); + /// VBufferLighting shader tag id. + public static readonly ShaderTagId s_VBufferLightingName = new ShaderTagId(s_VBufferLightingStr); /// GBufferWithPrepass shader tag id. public static readonly ShaderTagId s_GBufferWithPrepassName = new ShaderTagId(s_GBufferWithPrepassStr); /// Legacy Unlit cross pipeline shader tag id. @@ -758,9 +762,6 @@ static class HDShaderIDs public static readonly int _InputBufferDimension = Shader.PropertyToID("_InputBufferDimension"); public static readonly int _OutputBufferDimension = Shader.PropertyToID("_OutputBufferDimension"); - // Visibility Buffer - public static readonly int _VisibilityTexture = Shader.PropertyToID("_VisibilityTexture"); - // Primary Visibility public static readonly int _RaytracingFlagMask = Shader.PropertyToID("_RaytracingFlagMask"); public static readonly int _RaytracingPrimaryDebug = Shader.PropertyToID("_RaytracingPrimaryDebug"); @@ -1080,7 +1081,23 @@ static class HDShaderIDs public static readonly int _SrcOffset = Shader.PropertyToID("_SrcOffset"); //Visibility material - public static readonly int _VisBufferInstanceData = Shader.PropertyToID("_VisBufferInstanceData"); + public static readonly int _VisBufferTexture0 = Shader.PropertyToID("_VisBufferTexture0"); + public static readonly int _VisBufferTexture1 = Shader.PropertyToID("_VisBufferTexture1"); + public static readonly int _VisBufferFeatureTiles = Shader.PropertyToID("_VisBufferFeatureTiles"); + public static readonly int _VisBufferMaterialTiles = Shader.PropertyToID("_VisBufferMaterialTiles"); + public static readonly int _VisBufferBucketTiles = Shader.PropertyToID("_VisBufferBucketTiles"); + public static readonly int _VisBufferDepthTexture = Shader.PropertyToID("_VisBufferDepthTexture"); + + //Visibility classification + public static readonly int _VisBufferFeatureTileOutput = Shader.PropertyToID("_VisBufferFeatureTileOutput"); + public static readonly int _VisBufferTileSize = Shader.PropertyToID("_VisBufferTileSize"); + public static readonly int _VisBufferMaterialTileInput = Shader.PropertyToID("_VisBufferMaterialTileInput"); + public static readonly int _VisBufferBucketTileInput = Shader.PropertyToID("_VisBufferBucketTileInput"); + public static readonly int _VisBufferMaterialTileOutput = Shader.PropertyToID("_VisBufferMaterialTileOutput"); + public static readonly int _VisBufferBucketTileOutput = Shader.PropertyToID("_VisBufferBucketTileOutput"); + + //Visibility Lighting + public static readonly int _VisBufferTileData = Shader.PropertyToID("_VisBufferTileData"); } /// diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs index 26831296a02..7e5c2ebcdeb 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs @@ -185,14 +185,14 @@ static bool IsValidRayTracedMaterial(Material currentMaterial) return currentMaterial.GetTag("RenderPipeline", false) == "HDRenderPipeline" && !DecalSystem.IsDecalMaterial(currentMaterial); ; } - static bool IsTransparentMaterial(Material currentMaterial) + internal static bool IsTransparentMaterial(Material currentMaterial) { return currentMaterial.IsKeywordEnabled("_SURFACE_TYPE_TRANSPARENT") || (HDRenderQueue.k_RenderQueue_Transparent.lowerBound <= currentMaterial.renderQueue && HDRenderQueue.k_RenderQueue_Transparent.upperBound >= currentMaterial.renderQueue); } - static bool IsAlphaTestedMaterial(Material currentMaterial) + internal static bool IsAlphaTestedMaterial(Material currentMaterial) { return currentMaterial.IsKeywordEnabled("_ALPHATEST_ON") || (HDRenderQueue.k_RenderQueue_OpaqueAlphaTest.lowerBound <= currentMaterial.renderQueue diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs.hlsl index 9025e3267ae..bb61678808c 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/Raytracing/HDRaytracingManager.cs.hlsl @@ -16,6 +16,7 @@ #define RAYTRACINGRENDERERFLAG_GLOBAL_ILLUMINATION (32) #define RAYTRACINGRENDERERFLAG_RECURSIVE_RENDERING (64) #define RAYTRACINGRENDERERFLAG_PATH_TRACING (128) +#define RAYTRACINGRENDERERFLAG_ALL (255) #endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs index 258f163adc8..d13a9b7dd57 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs @@ -32,6 +32,7 @@ enum ShaderPass PathTracing, RayTracingDebug, Constant, + Visibility, FullScreenDebug, } } diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl index 0c38fceb269..b5a9802e5ef 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPass.cs.hlsl @@ -33,7 +33,8 @@ #define SHADERPASS_PATH_TRACING (23) #define SHADERPASS_RAY_TRACING_DEBUG (24) #define SHADERPASS_CONSTANT (25) -#define SHADERPASS_FULL_SCREEN_DEBUG (26) +#define SHADERPASS_VISIBILITY (26) +#define SHADERPASS_FULL_SCREEN_DEBUG (27) #endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVBufferLighting.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVBufferLighting.hlsl new file mode 100644 index 00000000000..010416334d0 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVBufferLighting.hlsl @@ -0,0 +1,296 @@ +#if (SHADERPASS != SHADERPASS_VBUFFER_LIGHTING) +#error SHADERPASS_is_not_correctly_define +#endif + +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl" +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/VisibilityCommon.hlsl" + +struct Attributes +{ + uint vertexID : SV_VertexID; + uint instanceID : SV_InstanceID; +}; + +struct Varyings +{ + float4 positionCS : SV_POSITION; + uint lightAndMaterialFeatures : FEATURES0; + uint debugIndex : FEATURES1; + UNITY_VERTEX_OUTPUT_STEREO +}; + +TEXTURE2D_X(_VisBufferDepthTexture); +float4 _VisBufferTileData; +#define _NumVBufferTileX (uint)_VisBufferTileData.x +#define _NumVBufferTileY (uint)_VisBufferTileData.y +#define _QuadTileSize (uint)_VisBufferTileData.z +#define _TotalTiles (uint) _VisBufferTileData.w + +uint GetCurrentMaterialBatchGPUKey() +{ +#ifdef DOTS_INSTANCING_ON + return unity_DOTSVisibleInstances[0].VisibleData.x; +#else + return 0; +#endif +} + +uint getCurrentMaterialGPUKey() +{ + return GetCurrentMaterialBatchGPUKey() >> 8; +} + +uint GetCurrentBatchID() +{ + return GetCurrentMaterialBatchGPUKey() & 0xFF; +} + +uint GetShaderTileCategory() +{ + uint shaderTileCategory = 0; + #if defined(VARIANT_DIR_ENV) + shaderTileCategory = LIGHTVBUFFERTILECATEGORY_ENV; + #elif defined(VARIANT_DIR_PUNCTUAL_ENV) + shaderTileCategory = LIGHTVBUFFERTILECATEGORY_ENV_PUNCTUAL; + #elif defined(VARIANT_DIR_PUNCTUAL_AREA_ENV) + shaderTileCategory = LIGHTVBUFFERTILECATEGORY_EVERYTHING; + #endif + return shaderTileCategory; +} + +uint GetShaderFeatureMask() +{ + uint featureMasks = 0; + #if defined(VARIANT_DIR_ENV) + featureMasks = VBUFFER_LIGHTING_FEATURES_ENV; + #elif defined(VARIANT_DIR_PUNCTUAL_ENV) + featureMasks = VBUFFER_LIGHTING_FEATURES_ENV_PUNCTUAL; + #elif defined(VARIANT_DIR_PUNCTUAL_AREA_ENV) + featureMasks = VBUFFER_LIGHTING_FEATURES_EVERYTHING; + #endif + return featureMasks; +} + +Varyings Vert(Attributes inputMesh) +{ + Varyings output; + ZERO_INITIALIZE(Varyings, output); + +#ifdef DOTS_INSTANCING_ON + UNITY_SETUP_INSTANCE_ID(inputMesh); + UNITY_INITIALIZE_VERTEX_OUTPUT_STEREO(output); + + uint tileIndex = inputMesh.vertexID >> 2; + + if (tileIndex >= _TotalTiles) + return output; + + int tileX = tileIndex % _NumVBufferTileX; + int tileY = tileIndex / _NumVBufferTileX; + int quadVertexID = inputMesh.vertexID % 4; + + int2 tileCoord = int2(tileX, tileY); + float2 tileSizeInUV = rcp(float2(_NumVBufferTileX, _NumVBufferTileY)); + float2 tileStartUV = tileCoord * rcp(float2(_NumVBufferTileX, _NumVBufferTileY)); + float2 vertPos = (float2(quadVertexID & 1, (quadVertexID >> 1) & 1) + tileCoord) * tileSizeInUV; + + int tapTileY = (_NumVBufferTileY-1) - tileY; + + uint2 tileCoords = uint2(tileX, tapTileY); + uint bucketIDMask = Visibility::LoadBucketTile(tileCoords); + uint2 matMinMax = Visibility::LoadMaterialTile(tileCoords); + output.lightAndMaterialFeatures = Visibility::LoadFeatureTile(tileCoords); + uint currentTileCategory = Visibility::GetLightTileCategory(output.lightAndMaterialFeatures); + + uint shaderTileCategory = GetShaderTileCategory(); + + if (((getCurrentMaterialGPUKey() & bucketIDMask) != 0) && (getCurrentMaterialGPUKey() >= matMinMax.x && getCurrentMaterialGPUKey() <= matMinMax.y) && shaderTileCategory == currentTileCategory) + { + output.positionCS.xy = vertPos * 2 - 1; + output.positionCS.w = 1; + output.positionCS.z = Visibility::PackDepthMaterialKey(GetCurrentMaterialBatchGPUKey()); + } + +#endif + + return output; +} + +#define INTERPOLATE_ATTRIBUTE(A0, A1, A2, BARYCENTRIC_COORDINATES) (A0 * BARYCENTRIC_COORDINATES.x + A1 * BARYCENTRIC_COORDINATES.y + A2 * BARYCENTRIC_COORDINATES.z) + +// Analytical derivatives, Hable 2021 +//http://filmicworlds.com/blog/visibility-buffer-rendering-with-material-graphs/ +struct BarycentricDeriv +{ + float3 m_lambda; + float3 m_ddx; + float3 m_ddy; +}; + +BarycentricDeriv CalcFullBary(float4 pt0, float4 pt1, float4 pt2, float2 pixelNdc, float2 winSize) +{ + BarycentricDeriv ret = (BarycentricDeriv)0; + + float3 invW = rcp(float3(pt0.w, pt1.w, pt2.w)); + + float2 ndc0 = pt0.xy * invW.x; + float2 ndc1 = pt1.xy * invW.y; + float2 ndc2 = pt2.xy * invW.z; + + float invDet = rcp(determinant(float2x2(ndc2 - ndc1, ndc0 - ndc1))); + ret.m_ddx = float3(ndc1.y - ndc2.y, ndc2.y - ndc0.y, ndc0.y - ndc1.y) * invDet; + ret.m_ddy = float3(ndc2.x - ndc1.x, ndc0.x - ndc2.x, ndc1.x - ndc0.x) * invDet; + + float2 deltaVec = pixelNdc - ndc0; + float interpInvW = (invW.x + deltaVec.x * dot(invW, ret.m_ddx) + deltaVec.y * dot(invW, ret.m_ddy)); + float interpW = rcp(interpInvW); + + ret.m_lambda.x = interpW * (invW[0] + deltaVec.x * ret.m_ddx.x * invW[0] + deltaVec.y * ret.m_ddy.x * invW[0]); + ret.m_lambda.y = interpW * (0.0f + deltaVec.x * ret.m_ddx.y * invW[1] + deltaVec.y * ret.m_ddy.y * invW[1]); + ret.m_lambda.z = interpW * (0.0f + deltaVec.x * ret.m_ddx.z * invW[2] + deltaVec.y * ret.m_ddy.z * invW[2]); + + ret.m_ddx *= (2.0f/winSize.x); + ret.m_ddy *= (2.0f/winSize.y); + + ret.m_ddy *= -1.0f; + + return ret; +} + + +FragInputs EvaluateFragInput( + float2 ndc, + float4 posSS, + in GeoPoolMetadataEntry geoMetadata, + in Visibility::VisibilityData visData, + float3 posWS, float3 V, out float3 debugValue) +{ + uint i0 = _GeoPoolGlobalIndexBuffer.Load((geoMetadata.indexOffset + 3 * visData.primitiveID + 0) << 2); + uint i1 = _GeoPoolGlobalIndexBuffer.Load((geoMetadata.indexOffset + 3 * visData.primitiveID + 1) << 2); + uint i2 = _GeoPoolGlobalIndexBuffer.Load((geoMetadata.indexOffset + 3 * visData.primitiveID + 2) << 2); + + GeoPoolVertex v0 = GeometryPool::LoadVertex(i0, geoMetadata); + GeoPoolVertex v1 = GeometryPool::LoadVertex(i1, geoMetadata); + GeoPoolVertex v2 = GeometryPool::LoadVertex(i2, geoMetadata); + + // Convert the positions to world space + float3 pos0WS = TransformObjectToWorld(v0.pos); + float3 pos1WS = TransformObjectToWorld(v1.pos); + float3 pos2WS = TransformObjectToWorld(v2.pos); + + float4 p0h = mul(GetWorldToHClipMatrix(), float4(pos0WS, 1.0)); + float4 p1h = mul(GetWorldToHClipMatrix(), float4(pos1WS, 1.0)); + float4 p2h = mul(GetWorldToHClipMatrix(), float4(pos2WS, 1.0)); + + BarycentricDeriv baryResult = CalcFullBary(p0h, p1h, p2h, ndc, (float2)_ScreenSize.xy); + + // Evaluate the barycentrics + float3 barycentricCoordinates = baryResult.m_lambda; + + // Get normal at position + float3 normalOS0 = v0.N; + float3 normalOS1 = v1.N; + float3 normalOS2 = v2.N; + float3 normalOS = INTERPOLATE_ATTRIBUTE(normalOS0, normalOS1, normalOS2, barycentricCoordinates); + + // Get tangent at position + float4 tangentOS0 = float4(v0.T, 1.0); + float4 tangentOS1 = float4(v1.T, 1.0); + float4 tangentOS2 = float4(v2.T, 1.0); + float4 tangentOS = INTERPOLATE_ATTRIBUTE(tangentOS0, tangentOS1, tangentOS2, barycentricCoordinates); + + // Get UV at position + float2 UV0 = (v0.uv); + float2 UV1 = (v1.uv); + float2 UV2 = (v2.uv); + float2 texCoord0 = INTERPOLATE_ATTRIBUTE(UV0, UV1, UV2, barycentricCoordinates); + + // Get UV1 at position + float2 UV1_0 = (v0.uv1); + float2 UV1_1 = (v1.uv1); + float2 UV1_2 = (v2.uv1); + float2 texCoord1 = INTERPOLATE_ATTRIBUTE(UV1_0, UV1_1, UV1_2, barycentricCoordinates); + + // Compute the world space normal and tangent. [IMPORTANT, we assume uniform scale here] + float3 normalWS = TransformObjectToWorldDir(normalOS); + float3 tangentWS = TransformObjectToWorldDir(tangentOS.xyz); + + // DEBG + //debugValue = saturate(dot(V, normalize(v0.N + v1.N + v2.N))).xxx; + //debugValue = saturate(dot(V, normalWS)).xxx; + debugValue = barycentricCoordinates.xyz; + /// + + FragInputs outFragInputs; + ZERO_INITIALIZE(FragInputs, outFragInputs); + outFragInputs.positionSS = posSS; + outFragInputs.positionRWS = posWS; + outFragInputs.texCoord0 = float4(texCoord0, 0.0, 1.0); + outFragInputs.texCoord1 = float4(texCoord1, 0.0, 1.0); + //outFragInputs.tangentToWorld = CreateTangentToWorld(normalWS, tangentWS, 1.0); + outFragInputs.tangentToWorld = CreateTangentToWorld(normalWS, tangentWS, sign(tangentOS.w)); + outFragInputs.isFrontFace = dot(V, normalWS) > 0.0f; + return outFragInputs; +} + +void Frag(Varyings packedInput, out float4 outColor : SV_Target0) +{ + UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(packedInput); +#ifdef DOTS_INSTANCING_ON + Visibility::VisibilityData visData = Visibility::LoadVisibilityData(packedInput.positionCS.xy); + + //Setup visibility buffer + { + DOTSVisibleData dotsVisData; + dotsVisData.VisibleData = uint4(visData.DOTSInstanceIndex, 0, 0, 0); + unity_SampledDOTSVisibleData = dotsVisData; + } + + GeoPoolMetadataEntry geometryMetadata; + uint materialKey = Visibility::GetMaterialKey(visData, geometryMetadata); + if (materialKey != getCurrentMaterialGPUKey()) + { + outColor = float4(0,0,0,0); + return; + } + + float2 pixelCoord = packedInput.positionCS.xy; + float depthValue = LOAD_TEXTURE2D_X(_VisBufferDepthTexture, pixelCoord).x; + float2 ndc = pixelCoord * _ScreenSize.zw; + float3 posWS = ComputeWorldSpacePosition(ndc, depthValue, UNITY_MATRIX_I_VP); + ndc = (ndc * 2.0 - 1.0) * float2(1.0, -1.0); + float3 V = GetWorldSpaceNormalizeViewDir(posWS); + + float3 debugValue = float3(0,0,0); + FragInputs input = EvaluateFragInput(ndc, packedInput.positionCS, geometryMetadata, visData, posWS, V, debugValue); + + int2 tileCoord = (float2)input.positionSS.xy / GetTileSize(); + PositionInputs posInput = GetPositionInput(input.positionSS.xy, _ScreenSize.zw, depthValue, UNITY_MATRIX_I_VP, GetWorldToViewMatrix(), tileCoord); + + SurfaceData surfaceData; + BuiltinData builtinData; + GetSurfaceAndBuiltinData(input, V, posInput, surfaceData, builtinData); + BSDFData bsdfData = ConvertSurfaceDataToBSDFData(input.positionSS.xy, surfaceData); + + PreLightData preLightData = GetPreLightData(V, posInput, bsdfData); + + float3 colorVariantColor = 0; + uint featureFlags = packedInput.lightAndMaterialFeatures; + + LightLoopOutput lightLoopOutput; + LightLoop(V, posInput, preLightData, bsdfData, builtinData, featureFlags, lightLoopOutput); + + float3 diffuseLighting = lightLoopOutput.diffuseLighting; + float3 specularLighting = lightLoopOutput.specularLighting; + + diffuseLighting *= GetCurrentExposureMultiplier(); + specularLighting *= GetCurrentExposureMultiplier(); + + + outColor.rgb = diffuseLighting + specularLighting; + outColor.a = 1; + //outColor = float4(debugValue, 1.0); +#else + outColor = 0; +#endif +} diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVBufferLighting.hlsl.meta b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVBufferLighting.hlsl.meta new file mode 100644 index 00000000000..f87e088c5c5 --- /dev/null +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVBufferLighting.hlsl.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 07a74a7e50665a342886a1b44ef11210 +ShaderIncludeImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVisibility.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVisibility.hlsl index 22bf2fda479..c595d16ecaf 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVisibility.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/ShaderPassVisibility.hlsl @@ -1,75 +1,52 @@ -#ifndef VISIBILITY_PASS_HLSL -#define VISIBILITY_PASS_HLSL - - -#include "Packages/com.unity.render-pipelines.high-definition/Runtime/Material/Visibility/Visibility.hlsl" -#include "Packages/com.unity.render-pipelines.core/Runtime/GeometryPool/Resources/GeometryPool.hlsl" - -CBUFFER_START(UnityPerMaterial) - float4 _DeferredMaterialInstanceData; -CBUFFER_END - -#if defined(UNITY_DOTS_INSTANCING_ENABLED) -UNITY_DOTS_INSTANCING_START(MaterialPropertyMetadata) - UNITY_DOTS_INSTANCED_PROP(float4, _DeferredMaterialInstanceData) -UNITY_DOTS_INSTANCING_END(MaterialPropertyMetadata) - -#define _DeferredMaterialInstanceData UNITY_ACCESS_DOTS_INSTANCED_PROP_WITH_DEFAULT(float4, _DeferredMaterialInstanceData) - +#if SHADERPASS != SHADERPASS_VISIBILITY +#error SHADERPASS_is_not_correctly_define #endif -struct GeoPoolInput -{ - uint vertId : SV_VertexID; - UNITY_VERTEX_INPUT_INSTANCE_ID -}; - -struct VisibilityVtoP -{ - float4 pos : SV_Position; - - UNITY_VERTEX_INPUT_INSTANCE_ID - UNITY_VERTEX_OUTPUT_STEREO -}; +#ifndef ATTRIBUTES_NEED_VERTEX_ID + #error Attributes_requires_vertex_id +#endif -struct VisibilityDrawInput -{ - uint vertexIndex : SV_VertexID; - UNITY_VERTEX_INPUT_INSTANCE_ID -}; +#include "Packages/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl" -VisibilityVtoP Vert(VisibilityDrawInput input) +PackedVaryingsType Vert(AttributesMesh inputMesh) { - VisibilityVtoP v2p; - - UNITY_SETUP_INSTANCE_ID(input); - UNITY_TRANSFER_INSTANCE_ID(input, v2p); - - GeoPoolMetadataEntry metadata = _GeoPoolGlobalMetadataBuffer[(int)_DeferredMaterialInstanceData.x]; - - GeoPoolVertex vertexData; - GeometryPool::LoadVertex(input.vertexIndex, metadata, vertexData); + VaryingsType varyingsType; + +#if defined(HAVE_RECURSIVE_RENDERING) + // If we have a recursive raytrace object, we will not render it. + // As we don't want to rely on renderqueue to exclude the object from the list, + // we cull it by settings position to NaN value. + // TODO: provide a solution to filter dyanmically recursive raytrace object in the DrawRenderer + if (_EnableRecursiveRayTracing && _RayTracing > 0.0) + { + ZERO_INITIALIZE(VaryingsType, varyingsType); // Divide by 0 should produce a NaN and thus cull the primitive. + } + else +#endif + { + varyingsType.vmesh = VertMesh(inputMesh); + varyingsType.vpass.batchID = (int)_DeferredMaterialInstanceData.y; + } - float3 worldPos = TransformObjectToWorld(vertexData.pos); - v2p.pos = TransformWorldToHClip(worldPos); - return v2p; + return PackVaryingsType(varyingsType); } void Frag( - VisibilityVtoP packedInput, - uint primitiveID : SV_PrimitiveID, - out uint outVisibility : SV_Target0) + PackedVaryingsToPS packedInput, + out uint outVisibility0 : SV_Target0, + out uint2 outVisibility1 : SV_Target1) { UNITY_SETUP_STEREO_EYE_INDEX_POST_VERTEX(packedInput); - UNITY_SETUP_INSTANCE_ID(packedInput); + FragInputs input = UnpackVaryingsToFragInputs(packedInput); #ifdef DOTS_INSTANCING_ON - VisibilityData visData; + Visibility::VisibilityData visData; + visData.valid = true; visData.DOTSInstanceIndex = GetDOTSInstanceIndex(); - visData.primitiveID = primitiveID; - outVisibility = packVisibilityData(visData); + visData.primitiveID = input.primitiveID; + visData.batchID = packedInput.vpass.batchID; + Visibility::PackVisibilityData(visData, outVisibility0, outVisibility1); #else - outVisibility = InvalidVisibilityData; + outVisibility0 = 0; + outVisibility1 = 0; #endif } - -#endif diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl index 73b66c28ab8..e8741939b28 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VaryingMesh.hlsl @@ -1,6 +1,9 @@ struct AttributesMesh { +//by default, all AttributeMesh have position enabled +#ifndef ATTRIBUTE_NEEDS_PROCEDURAL_POSITION float3 positionOS : POSITION; +#endif #ifdef ATTRIBUTES_NEED_NORMAL float3 normalOS : NORMAL; #endif @@ -22,6 +25,9 @@ struct AttributesMesh #ifdef ATTRIBUTES_NEED_COLOR float4 color : COLOR; #endif +#ifdef ATTRIBUTES_NEED_VERTEX_ID + uint vertexIndex : SV_VertexID; +#endif UNITY_VERTEX_INPUT_INSTANCE_ID }; diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl index 2f82dc8ad23..11e00f109f2 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipeline/ShaderPass/VertMesh.hlsl @@ -166,7 +166,18 @@ VaryingsMeshType VertMesh(AttributesMesh input, float3 worldSpaceOffset #endif // This return the camera relative position (if enable) - float3 positionRWS = TransformObjectToWorld(input.positionOS) + worldSpaceOffset; +#ifndef ATTRIBUTE_NEEDS_PROCEDURAL_POSITION + float3 positionOS = input.positionOS; +#else + //Means we need a procedural position, so lets make sure the callee declared this macro + #ifndef CreateProceduralPositionOS + #error Must_declare_CreateProceduralPositionOS_macro + #endif + float3 positionOS = CreateProceduralPositionOS(input); +#endif + + float3 positionRWS = TransformObjectToWorld(positionOS) + worldSpaceOffset; + #ifdef ATTRIBUTES_NEED_NORMAL float3 normalWS = TransformObjectToWorldNormal(input.normalOS); #else diff --git a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset index b26fab4e5f0..c2200c23326 100644 --- a/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset +++ b/com.unity.render-pipelines.high-definition/Runtime/RenderPipelineResources/HDRenderPipelineRuntimeResources.asset @@ -64,6 +64,8 @@ MonoBehaviour: upsampleTransparentPS: {fileID: 4800000, guid: 2ad7ce40f0dbaf64dadef1f58d8524d3, type: 3} resolveStencilCS: {fileID: 7200000, guid: 65b89cac5f286b043a31bf8041776ee7, type: 3} visibilityPS: {fileID: 4800000, guid: 633338306378163479b295584aba76c3, type: 3} + createMaterialDepthPS: {fileID: 4800000, guid: dbc5c19310f2c544c91d4bf81b05ddc6, type: 3} + vbufferTileClassificationCS: {fileID: 7200000, guid: 8097d48cf7ce091419dc8bf4ffc35e1a, type: 3} blitCubemapPS: {fileID: 4800000, guid: d05913e251bed7a4992c921c62e1b647, type: 3} buildProbabilityTablesCS: {fileID: 7200000, guid: b9f26cf340afe9145a699753531b2a4c, type: 3} computeGgxIblSampleDataCS: {fileID: 7200000, guid: 764a24bb47ef5ba4781d9ae82ca07445, type: 3}