using System; using System.Runtime.InteropServices; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering.RenderGraphModule; using UnityEngine.Rendering.HighDefinition; namespace UnityEngine.Rendering { partial class LineRendering { internal struct Arguments { public Camera camera; public Vector3 cameraPosition; public Frustum cameraFrustum; // TODO: Frustum us HDRP-specific, we should not use it here. public RenderGraph renderGraph; public TextureHandle depthTexture; public SystemSettings settings; public ShadingAtlas shadingAtlas; public Vector2 viewport; public Matrix4x4 matrixIVP; public RenderTargets targets; public int viewCount; public int viewIndex; } internal struct SystemSettings { public int clusterCount; public CompositionMode compositionMode; public SortingQuality sortingQuality; public float tileOpacityThreshold; public int debugMode; public MemoryBudget memoryBudget; public bool executeAsync; } internal struct SystemResources { public GPUSort gpuSort; public GPUPrefixSum gpuPrefixSum; public ComputeShader stagePrepareCS; public ComputeShader stageSetupSegmentCS; public ComputeShader stageShadingSetupCS; public ComputeShader stageRasterBinCS; public ComputeShader stageWorkQueue; public ComputeShader stageRasterFineCS; } /// /// Determines the size of graphics memory allocations for high quality line rendering. /// [Serializable] public enum MemoryBudget { /// Low Budget MemoryBudgetLow = 128, /// Medium Budget MemoryBudgetMedium = 256, /// High Budget MemoryBudgetHigh = 512, } /// /// List of line rendering debug views. /// [GenerateHLSL] public enum DebugMode { /// Draw a heat value per tile representing the number of segments being computed in the tile. SegmentsPerTile, /// Draw the tile's compute index. TileProcessorUV, /// Draw the cluster index for each computed fragment. ClusterDepth, } /// /// Container for parameters defining a renderable instance for the line rendering system. /// [Serializable] public struct RendererData { /// Mesh with line topology. public Mesh mesh; /// World Matrix. public Matrix4x4 matrixW; /// Previous World Matrix. public Matrix4x4 matrixWP; /// Material to draw the lines. public Material material; /// Compute asset for computing the vertex shader in a compute shader. public ComputeShader vertexSetupCompute; /// Merging group for sorting between multiple renderer datas. public RendererGroup group; /// Spherical harmonic coefficients for probe lighting. public SphericalHarmonicsL2 probe; /// Rendering mask. public uint renderingLayerMask; /// Motion vector parameters. public Vector4 motionVectorParams; /// Offscreen shading pass index. public int offscreenShadingPass; /// Handle to the line topology's index buffer resource. public BufferHandle indexBuffer; /// Distance to camera for sorting purposes. public float distanceToCamera; /// The number of lines in the mesh. public int lineCount; /// The number of segments-per-line. public int segmentsPerLine; /// Handle to a buffer for computing level of detail. public BufferHandle lodBuffer; /// Level of detail mode. public RendererLODMode lodMode; /// Percentage of strands to render. public float lod; /// Percentage of shading samples to compute. public float shadingFraction; /// Unique identifier for the renderer data. public int hash; /// Bounds of the renderer public Bounds bounds; } /// /// The method by which line renderer's level of detail will be computed. /// public enum RendererLODMode { /// No level of detail will be computed. None, /// Define level of detail with a fixed value. Fixed, /// Compute level of detail based on bounding box screen coverage. ScreenCoverage, /// Compute level of detail based on camera distance. CameraDistance } /// /// The group that line renderers will be merged into for better transparent sorting. /// public enum RendererGroup { /// No merging will occur with other line renderers. None, /// Group 0. Group0, /// Group 1. Group1, /// Group 2. Group2, /// Group 3. Group3, /// Group 4. Group4, } internal struct RenderTargets { public TextureHandle color; public TextureHandle depth; public TextureHandle motion; } [GenerateHLSL(needAccessors = false, generateCBuffer = true)] internal struct ShaderVariables { // Stage group sizes. public const int NumLaneSegmentSetup = 1024; public const int NumLaneRasterBin = 512; // Due to structure alignment issues on certain API (Metal, Vulkan) we ensure 16-byte alignment // like this to ensure there is no mismatch. public Vector4 _Params0; // { Dim Bin X, Dim Bin Y, Segment Count, Bin Count } public Vector4 _Params1; // { Size Screen, Inv. Size Screen } public Vector4 _Params2; // { Size Bin, Inv. Size Bin } public Vector4 _Params3; // { Vertex Count, Vertex Stride, Active Bin Count, Cluster Depth } public Vector4 _Params4; // { Shading Atlas Dim, Cluster Count, Tile Opacity Threshold } public Vector4 _Params5; // { View Index, Padding } // Aliases public Vector2 _DimBin { get => new Vector2(_Params0.x, _Params0.y); set { _Params0.x = value.x; _Params0.y = value.y; } } public int _SegmentCount { get => (int)_Params0.z; set => _Params0.z = (float)value; } public int _BinCount { get => (int)_Params0.w; set => _Params0.w = (float)value; } public Vector4 _SizeScreen { get => _Params1; set => _Params1 = value; } public Vector4 _SizeBin { get => _Params2; set => _Params2 = value; } public int _VertexCount { get => (int)_Params3.x; set => _Params3.x = (float)value; } public int _VertexStride { get => (int)_Params3.y; set => _Params3.y = (float)value; } public int _ActiveBinCount { get => (int)_Params3.z; set => _Params3.z = (float)value; } public int _ClusterDepth { get => (int)_Params3.w; set => _Params3.w = (float)value; } public Vector2 _ShadingAtlasDimensions { get => new Vector2(_Params4.x, _Params4.y); set { _Params4.x = value.x; _Params4.y = value.y; } } public int _ClusterCount { get => (int)_Params4.z; set => _Params4.z = (float)value; } public float _TileOpacityThreshold { get => _Params4.w; set => _Params4.w = value; } public int _ViewIndex { get => (int)_Params5.x; set => _Params5.x = (float)value; } } static unsafe int GetShaderVariablesSize() { return sizeof(ShaderVariables); } [GenerateHLSL(PackingRules.Exact, false)] struct VertexRecord { public Vector4 positionCS; public Vector4 previousPositionCS; public Vector3 positionRWS; public Vector3 tangentWS; public Vector3 normalWS; public uint texCoord0; public uint texCoord1; } [GenerateHLSL(PackingRules.Exact, false)] struct SegmentRecord { public Vector2 positionSS0; public Vector2 positionSS1; public float depthVS0; public float depthVS1; public uint vertexIndex0; public uint vertexIndex1; } [GenerateHLSL(PackingRules.Exact, false)] struct ClusterRecord { public uint segmentIndex; public uint clusterIndex; public uint clusterOffset; } internal class SharedPassData { public ShaderVariables shaderVariables; public ConstantBuffer shaderVariablesBuffer; public TextureHandle depthRT; public SystemResources systemResources; public Buffers sharedBuffers; internal struct Buffers { public BufferHandle vertexStream0; // Vertex Stream 0: Position CS public BufferHandle vertexStream1; // Vertex Stream 1: Previous Position CS public BufferHandle vertexStream2; // Vertex Stream 2: XY Tangent ZW Normal public BufferHandle vertexStream3; // Vertex Stream 3: Texcoord public BufferHandle viewSpaceDepthRange; public BufferHandle counterBuffer; public BufferHandle recordBufferSegment; public TextureHandle groupShadingSampleAtlas; public Vector2Int groupShadingSampleAtlasDimensions; internal struct AllocationParameters { public int countSegment; public int countVertex; } public static Buffers Allocate(RenderGraph renderGraph, AllocationParameters parameters) { BufferHandle CreateBuffer(int elementCount, int stride, GraphicsBuffer.Target target, string name) { return renderGraph.CreateBuffer(new BufferDesc(elementCount, stride, target) {name = name}); } int shadingSampleAtlasWidth = Mathf.NextPowerOfTwo(Mathf.CeilToInt(Mathf.Sqrt(parameters.countVertex))); shadingSampleAtlasWidth = Math.Max(shadingSampleAtlasWidth, 1); int shadingSampleAtlasHeight = Mathf.NextPowerOfTwo(Mathf.CeilToInt(DivRoundUp(parameters.countVertex, shadingSampleAtlasWidth))); var resource = new Buffers { vertexStream0 = CreateBuffer(16 * parameters.countVertex, sizeof(uint), GraphicsBuffer.Target.Raw, "Record Buffer [Vertex Stream 0]"), vertexStream1 = CreateBuffer(16 * parameters.countVertex, sizeof(uint), GraphicsBuffer.Target.Raw, "Record Buffer [Vertex Stream 1]"), vertexStream2 = CreateBuffer(16 * parameters.countVertex, sizeof(uint), GraphicsBuffer.Target.Raw, "Record Buffer [Vertex Stream 2]"), vertexStream3 = CreateBuffer(8 * parameters.countVertex, sizeof(uint), GraphicsBuffer.Target.Raw, "Record Buffer [Vertex Stream 3]"), counterBuffer = CreateBuffer(8, sizeof(uint), GraphicsBuffer.Target.Raw, "Counters"), recordBufferSegment = CreateBuffer(4 * 2 * parameters.countSegment, sizeof(uint), GraphicsBuffer.Target.Raw, "Record Buffer [Segment]"), viewSpaceDepthRange = CreateBuffer(2, sizeof(float), GraphicsBuffer.Target.Raw, "View Space Depth Range"), groupShadingSampleAtlas = renderGraph.CreateTexture(new TextureDesc(shadingSampleAtlasWidth, shadingSampleAtlasHeight) { colorFormat = GraphicsFormat.R32G32B32A32_SFloat, enableRandomWrite = true }), groupShadingSampleAtlasDimensions = new Vector2Int(shadingSampleAtlasWidth, shadingSampleAtlasHeight) }; return resource; } } } internal class GeometryPassData : SharedPassData { public Buffers transientBuffers; public RendererData[] rendererData; public ShadingAtlas shadingAtlas; public Matrix4x4 matrixIVP; public MaterialPropertyBlock materialPropertyBlock; // TODO: Move into RendererData? public int[] offsetsVertex; public int[] offsetsSegment; internal new struct Buffers { public const int SHADING_SAMPLE_HISTOGRAM_SIZE = 512; //needs to match the shader public TextureHandle shadingScratchTexture; public Vector2Int shadingScratchTextureDimensions; public GPUPrefixSum.RenderGraphResources prefixResources; public BufferHandle shadingScratchBuffer; public BufferHandle shadingSampleHistogram; internal struct AllocationParameters { public int countVertex; public int countVertexMaxPerRenderer; } public static Buffers Allocate(RenderGraph renderGraph, RenderGraphBuilder builder, AllocationParameters parameters) { BufferHandle CreateBuffer(int elementCount, int stride, GraphicsBuffer.Target target, string name) { return builder.CreateTransientBuffer(new BufferDesc(elementCount, stride, target) { name = name }); } int scratchTextureDimension = Mathf.NextPowerOfTwo(Mathf.CeilToInt(Mathf.Sqrt(parameters.countVertexMaxPerRenderer))); int shadingScratchSize = parameters.countVertexMaxPerRenderer + 1; int prefixMaxItems = Mathf.Max(SHADING_SAMPLE_HISTOGRAM_SIZE, shadingScratchSize); var resource = new Buffers { shadingScratchBuffer = CreateBuffer(shadingScratchSize, sizeof(uint), GraphicsBuffer.Target.Raw, "Shading Scratch"), shadingSampleHistogram = CreateBuffer(SHADING_SAMPLE_HISTOGRAM_SIZE + 1, sizeof(uint), GraphicsBuffer.Target.Raw, "Shading Sample Histogram"), prefixResources = GPUPrefixSum.RenderGraphResources.Create(prefixMaxItems, renderGraph, builder), shadingScratchTexture = builder.CreateTransientTexture(new TextureDesc(scratchTextureDimension, scratchTextureDimension) { colorFormat = GraphicsFormat.R32G32B32A32_SFloat, enableRandomWrite = true }), shadingScratchTextureDimensions = new Vector2Int(scratchTextureDimension, scratchTextureDimension), }; return resource; } } } internal class RasterizationPassData : SharedPassData { public Buffers transientBuffers; public RenderTargets renderTargets; public int qualityModeIndex; public int debugModeIndex; #if UNITY_EDITOR public bool renderDataStillHasShadersCompiling; #endif public int binCount; public int clusterCount; public int clusterDepth; internal new struct Buffers { public BufferHandle counterBufferClusters; public BufferHandle binCounters; public BufferHandle binIndices; public BufferHandle workQueueArgs; public BufferHandle fineRasterArgs; public BufferHandle workQueue; public BufferHandle clusterCounters; public BufferHandle clusterRanges; public BufferHandle activeClusterIndices; public BufferHandle binningIndirectArgs; public BufferHandle recordBufferCluster; public GPUPrefixSum.RenderGraphResources prefixResources; public GPUSort.RenderGraphResources binSortResources; internal struct AllocationParameters { public int countBin; public int countCluster; public int depthCluster; public int countBinRecords; public int countWorkQUeue; } public static Buffers Allocate(RenderGraph renderGraph, RenderGraphBuilder builder, AllocationParameters parameters) { BufferHandle CreateBuffer(int elementCount, int stride, GraphicsBuffer.Target target, string name) { return builder.CreateTransientBuffer(new BufferDesc(elementCount, stride, target) { name = name }); } var resource = new Buffers { clusterCounters = CreateBuffer(parameters.countCluster, sizeof(uint), GraphicsBuffer.Target.Raw, "Cluster Counters"), recordBufferCluster = CreateBuffer(parameters.countBinRecords, Marshal.SizeOf(), GraphicsBuffer.Target.Structured, "Record Buffer [Cluster]"), binCounters = CreateBuffer(parameters.countBin, sizeof(uint), GraphicsBuffer.Target.Raw | GraphicsBuffer.Target.CopySource, "Bin Counters"), binIndices = CreateBuffer(parameters.countBin, sizeof(uint), GraphicsBuffer.Target.Raw | GraphicsBuffer.Target.CopySource, "Bin Indices"), clusterRanges = CreateBuffer(2 * parameters.depthCluster, sizeof(float), GraphicsBuffer.Target.Raw, "Cluster Ranges"), activeClusterIndices = CreateBuffer(parameters.countCluster, sizeof(uint), GraphicsBuffer.Target.Raw, "Active Cluster Indices"), workQueueArgs = CreateBuffer(4, sizeof(uint), GraphicsBuffer.Target.IndirectArguments, "Work Queue Args"), fineRasterArgs = CreateBuffer(4, sizeof(uint), GraphicsBuffer.Target.IndirectArguments, "Fine Raster Args"), workQueue = CreateBuffer(parameters.countWorkQUeue, sizeof(uint), GraphicsBuffer.Target.Raw, "Segment Queue"), binningIndirectArgs = CreateBuffer(4, sizeof(uint), GraphicsBuffer.Target.IndirectArguments, "Binning Args"), prefixResources = GPUPrefixSum.RenderGraphResources.Create(parameters.countCluster, renderGraph, builder), binSortResources = GPUSort.RenderGraphResources.Create(parameters.countBin, renderGraph, builder), }; return resource; } } } } }