You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

169 lines
7.2 KiB

using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
namespace UnityEngine.Rendering
{
partial class LineRendering
{
static int ComputeBinningRecordCapacity(MemoryBudget budget) => (int)Mathf.Ceil(((int) budget * 1024 * 1024) / Marshal.SizeOf<ClusterRecord>()) ;
static int ComputeWorkQueueCapacity(MemoryBudget budget) => (int)Mathf.Ceil(((int) budget * 1024 * 1024) / sizeof(uint)) ;
static int DivRoundUp(int x, int y) => (x + y - 1) / y;
static int NextPowerOfTwo(int v)
{
v -= 1;
v |= v >> 16;
v |= v >> 8;
v |= v >> 4;
v |= v >> 2;
v |= v >> 1;
return v + 1;
}
struct BindRendererToComputeKernel : IDisposable
{
private List<GraphicsBuffer> boundBuffers;
static void GetAttributeBufferNames(VertexAttribute attribute, out string bufferName, out string strideName, out string offsetName)
{
var attributeName = Enum.GetName(typeof(VertexAttribute), attribute);
bufferName = $"_VertexBuffer{attributeName}";
strideName = $"_VertexBuffer{attributeName}Stride";
offsetName = $"_VertexBuffer{attributeName}Offset";
}
internal BindRendererToComputeKernel(CommandBuffer cmd, RendererData renderer)
{
boundBuffers = new List<GraphicsBuffer>();
renderer.mesh.vertexBufferTarget |= GraphicsBuffer.Target.Raw;
// Disable all keywords first.
foreach (var keyword in renderer.vertexSetupCompute.keywordSpace.keywords)
{
#if !UNITY_EDITOR
// Catch an unfortunate case where the editor-only hair system vertex setup variant will be stripped from the
// material shader and thus will not be set on the compute material correctly -- so manually enable it here.
if (keyword.name == "HAIR_VERTEX_LIVE")
{
cmd.SetKeyword(renderer.vertexSetupCompute, keyword, true);
continue;
}
#endif
cmd.SetKeyword(renderer.vertexSetupCompute, keyword, false);
}
cmd.SetComputeIntParam(renderer.vertexSetupCompute, "_VertexCount", renderer.mesh.vertexCount);
// Bind the existing attribute buffers, bind a dummy one if it doesn't exist (prevents compiler warning).
{
void TryBindVertexBuffer(VertexAttribute attribute, ref List<GraphicsBuffer> buffers)
{
var streamIndex = renderer.mesh.GetVertexAttributeStream(attribute);
GraphicsBuffer streamBuffer;
int streamOffset, streamStride;
if (streamIndex < 0)
{
streamBuffer = CoreUtils.emptyBuffer;
streamOffset = 0;
streamStride = 4;
}
else
{
streamBuffer = renderer.mesh.GetVertexBuffer(streamIndex);
streamOffset = renderer.mesh.GetVertexAttributeOffset(attribute);
streamStride = renderer.mesh.GetVertexBufferStride(streamIndex);
buffers.Add(streamBuffer);
}
GetAttributeBufferNames(attribute, out var bufferName, out var strideName, out var offsetName);
cmd.SetComputeBufferParam(renderer.vertexSetupCompute, 0, bufferName, streamBuffer);
cmd.SetComputeIntParam(renderer.vertexSetupCompute, offsetName, streamOffset);
cmd.SetComputeIntParam(renderer.vertexSetupCompute, strideName, streamStride);
}
// Try to bind all existing mesh vertex buffer streams to the kernel.
foreach (var attribute in Enum.GetValues(typeof(VertexAttribute)).Cast<VertexAttribute>())
{
TryBindVertexBuffer(attribute, ref boundBuffers);
}
}
// Also need to bind these matrices manually. (TODO: Is it cross-SRP safe?)
cmd.SetComputeMatrixParam(renderer.vertexSetupCompute, "unity_ObjectToWorld", renderer.matrixW);
cmd.SetComputeMatrixParam(renderer.vertexSetupCompute, "unity_WorldToObject", renderer.matrixW.inverse);
cmd.SetComputeMatrixParam(renderer.vertexSetupCompute, "unity_MatrixPreviousM", renderer.matrixWP);
cmd.SetComputeMatrixParam(renderer.vertexSetupCompute, "unity_MatrixPreviousMI", renderer.matrixWP.inverse);
cmd.SetComputeVectorParam(renderer.vertexSetupCompute, "unity_MotionVectorsParams", renderer.motionVectorParams);
// Not the greatest way to do this, but not really possible to do any better unless it is done on the native side.
foreach (var keywordName in renderer.material.shaderKeywords)
{
var keyword = renderer.vertexSetupCompute.keywordSpace.FindKeyword(keywordName);
if (keyword.isValid)
{
cmd.SetKeyword(renderer.vertexSetupCompute, keyword, true);
}
}
cmd.SetComputeParamsFromMaterial(renderer.vertexSetupCompute, 0, renderer.material);
}
public void Dispose()
{
foreach (var buffer in boundBuffers)
buffer.Dispose();
}
}
// TODO: Need to optimize this whole routine.
private IEnumerable<RendererData[]> SortRenderDatasByCameraDistance(RendererData[] renderData, Camera camera)
{
var renderDatasNoGroup = renderData.Where(o => o.@group == RendererGroup.None).Select(o => new[] { o });
var renderDatasInGroup = renderData.GroupBy(o => o.@group).Where(g => g.Key != RendererGroup.None).Select(o => o.ToArray());
var renderDatasToSort = renderDatasNoGroup.Concat(renderDatasInGroup).ToArray();
if (renderDatasToSort.Length > 1)
{
// Sort
Array.Sort(renderDatasToSort, (RendererData[] a, RendererData[] b) =>
{
float cameraDistanceA = a.Average(i => i.distanceToCamera);
float cameraDistanceB = b.Average(i => i.distanceToCamera);
return cameraDistanceA.CompareTo(cameraDistanceB);
});
}
foreach (var data in renderDatasToSort)
{
yield return data;
}
}
// Exclusive prefix sum.
int[] PrefixSum(int[] input)
{
int[] output = new int[input.Length];
int sum = 0;
for (int i = 0; i < input.Length; ++i)
{
output[i] = sum;
sum += input[i];
}
return output;
}
}
}