Netcode Bootstrap
This commit is contained in:
@@ -0,0 +1,169 @@
|
||||
using Unity.Assertions;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Toolbox
|
||||
{
|
||||
public static class ComputeBufferTools
|
||||
{
|
||||
static ComputeShader copyCS;
|
||||
static ComputeKernel copyKernel;
|
||||
static ComputeKernel clearKernel;
|
||||
|
||||
static readonly string COMPUTE_SHADER_NAME = "RukhankaGPUBufferManipulation";
|
||||
static readonly string COPY_KERNEL_NAME = "CopyBuffer";
|
||||
static readonly string CLEAR_KERNEL_NAME = "ClearBuffer";
|
||||
|
||||
static readonly int ShaderID_copyBufferElementsCount = Shader.PropertyToID("copyBufferElementsCount");
|
||||
static readonly int ShaderID_srcBuf = Shader.PropertyToID("srcBuf");
|
||||
static readonly int ShaderID_dstBuf = Shader.PropertyToID("dstBuf");
|
||||
static readonly int ShaderID_srcOffset = Shader.PropertyToID("srcOffset");
|
||||
static readonly int ShaderID_dstOffset = Shader.PropertyToID("dstOffset");
|
||||
static readonly int ShaderID_clearValue = Shader.PropertyToID("clearValue");
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static GraphicsBuffer GrowNoCopy(GraphicsBuffer gb, int newElementCount)
|
||||
{
|
||||
Assert.IsNotNull(gb);
|
||||
if (gb == null)
|
||||
return null;
|
||||
|
||||
if (newElementCount <= gb.count)
|
||||
return gb;
|
||||
|
||||
var newBuf = new GraphicsBuffer(gb.target, gb.usageFlags, newElementCount, gb.stride);
|
||||
gb.Dispose();
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void Copy<T>(GraphicsBuffer src, GraphicsBuffer dst, uint srcOffsetInElements, uint dstOffsetInElements, uint copyCount) where T: unmanaged
|
||||
{
|
||||
var elementSizeInBytes = UnsafeUtility.SizeOf<T>();
|
||||
Copy(src, dst, (uint)(srcOffsetInElements * elementSizeInBytes), (uint)(dstOffsetInElements * elementSizeInBytes), (uint)(copyCount * elementSizeInBytes));
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void Copy(GraphicsBuffer src, GraphicsBuffer dst, uint srcOffsetInBytes, uint dstOffsetInBytes, uint numBytesToCopy)
|
||||
{
|
||||
Assert.IsTrue(numBytesToCopy % 4 == 0);
|
||||
Assert.IsTrue(srcOffsetInBytes % 4 == 0);
|
||||
Assert.IsTrue(dstOffsetInBytes % 4 == 0);
|
||||
|
||||
var numIntsToCopy = numBytesToCopy / 4;
|
||||
if (numIntsToCopy > 0)
|
||||
{
|
||||
copyCS ??= Resources.Load<ComputeShader>(COMPUTE_SHADER_NAME);
|
||||
copyKernel ??= new ComputeKernel(copyCS, COPY_KERNEL_NAME);
|
||||
|
||||
const uint maxDispatchCount = 0xffff;
|
||||
uint maxCopyOpsForSingleDispatch = maxDispatchCount * copyKernel.numThreadGroups.x;
|
||||
uint copyByteCounter = 0;
|
||||
while (numIntsToCopy > 0)
|
||||
{
|
||||
var iterationNumCopyOps = math.min(maxCopyOpsForSingleDispatch, numIntsToCopy);
|
||||
numIntsToCopy -= iterationNumCopyOps;
|
||||
copyCS.SetBuffer(copyKernel, ShaderID_srcBuf, src);
|
||||
copyCS.SetBuffer(copyKernel, ShaderID_dstBuf, dst);
|
||||
copyCS.SetInt(ShaderID_copyBufferElementsCount, (int)iterationNumCopyOps);
|
||||
copyCS.SetInt(ShaderID_dstOffset, (int)(dstOffsetInBytes + copyByteCounter));
|
||||
copyCS.SetInt(ShaderID_srcOffset, (int)(srcOffsetInBytes + copyByteCounter));
|
||||
copyKernel.Dispatch((int)iterationNumCopyOps, 1, 1);
|
||||
copyByteCounter += iterationNumCopyOps * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// We cannot resize compute buffer. The only way is to create new, copy data, destroy old and return created one.
|
||||
public static GraphicsBuffer Resize(GraphicsBuffer gb, int newElementCount)
|
||||
{
|
||||
Assert.IsNotNull(gb);
|
||||
if (gb == null)
|
||||
return null;
|
||||
|
||||
// In case of new and old sizes match simply return
|
||||
if (newElementCount == gb.count)
|
||||
return gb;
|
||||
|
||||
Assert.IsTrue((gb.target & GraphicsBuffer.Target.Raw) != 0, "Graphics buffer must be created with 'GraphicsBuffer.Target.Raw' flag");
|
||||
|
||||
var newBuf = new GraphicsBuffer(gb.target, gb.usageFlags, newElementCount, gb.stride);
|
||||
var elementsToCopy = math.min(newBuf.count, gb.count);
|
||||
Copy(gb, newBuf, 0, 0, (uint)(elementsToCopy * gb.stride));
|
||||
gb.Dispose();
|
||||
return newBuf;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static void Clear(GraphicsBuffer gb, uint startByteOffset, uint clearBytesCount, uint clearValue = 0)
|
||||
{
|
||||
Assert.IsNotNull(gb);
|
||||
Assert.IsTrue(clearBytesCount % 4 == 0);
|
||||
if (gb == null)
|
||||
return;
|
||||
|
||||
Assert.IsTrue((gb.target & GraphicsBuffer.Target.Raw) != 0, "Partial clear only for raw buffers");
|
||||
|
||||
if (clearBytesCount > 0)
|
||||
{
|
||||
copyCS ??= Resources.Load<ComputeShader>(COMPUTE_SHADER_NAME);
|
||||
clearKernel ??= new ComputeKernel(copyCS, CLEAR_KERNEL_NAME);
|
||||
|
||||
const uint maxDispatchCount = 0xffff;
|
||||
uint maxClearOpsForSingleDispatch = maxDispatchCount * clearKernel.numThreadGroups.x;
|
||||
var numIntsToClear = clearBytesCount / 4;
|
||||
uint clearByteCounter = 0;
|
||||
while (numIntsToClear > 0)
|
||||
{
|
||||
var iterationNumClearOps = math.min(maxClearOpsForSingleDispatch, numIntsToClear);
|
||||
numIntsToClear -= iterationNumClearOps;
|
||||
copyCS.SetBuffer(clearKernel, ShaderID_dstBuf, gb);
|
||||
copyCS.SetInt(ShaderID_copyBufferElementsCount, (int)iterationNumClearOps);
|
||||
copyCS.SetInt(ShaderID_dstOffset, (int)(startByteOffset + clearByteCounter));
|
||||
copyCS.SetInt(ShaderID_clearValue, (int)clearValue);
|
||||
clearKernel.Dispatch((int)iterationNumClearOps, 1, 1);
|
||||
clearByteCounter += iterationNumClearOps * 4;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static GraphicsBuffer CreateOrGrowGraphicsBuffer<T>
|
||||
(
|
||||
GraphicsBuffer gb,
|
||||
GraphicsBuffer.Target target,
|
||||
GraphicsBuffer.UsageFlags usage,
|
||||
int elementCount,
|
||||
bool preserveContents,
|
||||
int extraCountAfterResize = 0x1000
|
||||
) where T: unmanaged
|
||||
{
|
||||
if (gb == null)
|
||||
{
|
||||
// In case of zero input size, increase it to make a buffer in any case
|
||||
elementCount = math.max(0xff, elementCount);
|
||||
gb = new GraphicsBuffer(target, usage, elementCount, UnsafeUtility.SizeOf<T>());
|
||||
return gb;
|
||||
}
|
||||
|
||||
if (elementCount <= gb.count)
|
||||
return gb;
|
||||
|
||||
// To prevent frequent buffer recreations, resize buffer with some additional capacity
|
||||
elementCount += extraCountAfterResize;
|
||||
|
||||
gb = preserveContents ? Resize(gb, elementCount) : GrowNoCopy(gb, elementCount);
|
||||
return gb;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ed8ef19ce487f1945a429a413ea24b6c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Toolbox/GPU/ComputeBufferTools.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,76 @@
|
||||
using Unity.Assertions;
|
||||
using Unity.Mathematics;
|
||||
using UnityEngine;
|
||||
using SystemInfo = UnityEngine.Device.SystemInfo;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Toolbox
|
||||
{
|
||||
public class ComputeKernel
|
||||
{
|
||||
public readonly uint3 numThreadGroups;
|
||||
public readonly int kernelIndex;
|
||||
public readonly string kernelName;
|
||||
public readonly ComputeShader computeShader;
|
||||
readonly uint MAX_WORKGROUP_COUNT = 0xffff;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ComputeKernel(ComputeShader cs, string kernelName)
|
||||
{
|
||||
kernelIndex = cs.FindKernel(kernelName);
|
||||
this.kernelName = kernelName;
|
||||
cs.GetKernelThreadGroupSizes(kernelIndex, out numThreadGroups.x, out numThreadGroups.y, out numThreadGroups.z);
|
||||
Assert.IsTrue(numThreadGroups.x <= SystemInfo.maxComputeWorkGroupSizeX, $"Kernel '{kernelName}({kernelIndex})' of shader '{cs.name}' work group size X '{numThreadGroups.x}' exceeds hardware limit of '{SystemInfo.maxComputeWorkGroupSizeX}'");
|
||||
Assert.IsTrue(numThreadGroups.y <= SystemInfo.maxComputeWorkGroupSizeY, $"Kernel '{kernelName}({kernelIndex})' of shader '{cs.name}' work group size Y '{numThreadGroups.y}' exceeds hardware limit of '{SystemInfo.maxComputeWorkGroupSizeY}'");
|
||||
Assert.IsTrue(numThreadGroups.z <= SystemInfo.maxComputeWorkGroupSizeZ, $"Kernel '{kernelName}({kernelIndex})' of shader '{cs.name}' work group size Z '{numThreadGroups.z}' exceeds hardware limit of '{SystemInfo.maxComputeWorkGroupSizeZ}'");
|
||||
computeShader = cs;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Dispatch(int workGroupSizeX, int workgroupSizeY, int workgroupSizeZ)
|
||||
{
|
||||
var workGroupSize = new int3(workGroupSizeX, workgroupSizeY, workgroupSizeZ);
|
||||
var numDispatches = (int3)math.ceil(workGroupSize / (float3)numThreadGroups);
|
||||
#if UNITY_ASSERTIONS
|
||||
if (ValidateDispatch(workGroupSizeX, workgroupSizeY, workgroupSizeZ))
|
||||
#endif
|
||||
computeShader.Dispatch(kernelIndex, numDispatches.x, numDispatches.y, numDispatches.z);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Dispatch(uint workGroupSizeX, uint workgroupSizeY, uint workgroupSizeZ)
|
||||
{
|
||||
Dispatch((int)workGroupSizeX, (int)workgroupSizeY, (int)workgroupSizeZ);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public uint3 GetMaxWorkGroupSize()
|
||||
{
|
||||
return MAX_WORKGROUP_COUNT * numThreadGroups;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public bool ValidateDispatch(int workGroupSizeX, int workgroupSizeY, int workgroupSizeZ)
|
||||
{
|
||||
var workGroupSize = new int3(workGroupSizeX, workgroupSizeY, workgroupSizeZ);
|
||||
var numDispatches = (int3)math.ceil(workGroupSize / (float3)numThreadGroups);
|
||||
if (numDispatches.x > MAX_WORKGROUP_COUNT)
|
||||
Debug.LogError($"Kernel '{kernelName}({kernelIndex})' of shader '{computeShader.name}' dispatch thread group count X '{numDispatches.x}' exceeds hardware limit of '{MAX_WORKGROUP_COUNT}'. Try to increase kernel work group size.");
|
||||
if (numDispatches.y > MAX_WORKGROUP_COUNT)
|
||||
Debug.LogError($"Kernel '{kernelName}({kernelIndex})' of shader '{computeShader.name}' dispatch thread group count Y '{numDispatches.y}' exceeds hardware limit of '{MAX_WORKGROUP_COUNT}'. Try to increase kernel work group size.");
|
||||
if (numDispatches.z > MAX_WORKGROUP_COUNT)
|
||||
Debug.LogError($"Kernel '{kernelName}({kernelIndex})' of shader '{computeShader.name}' dispatch thread group count Z '{numDispatches.z}' exceeds hardware limit of '{MAX_WORKGROUP_COUNT}'. Try to increase kernel work group size.");
|
||||
return math.all(numDispatches <= (int)MAX_WORKGROUP_COUNT);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static implicit operator int(ComputeKernel c) => c.kernelIndex;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e59641556c7d860438f1848a81d5e0ab
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Toolbox/GPU/ComputeKernel.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,133 @@
|
||||
using System;
|
||||
using Unity.Collections;
|
||||
using Unity.Collections.LowLevel.Unsafe;
|
||||
using Unity.Rendering;
|
||||
using Unity.Assertions;
|
||||
using UnityEngine;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Toolbox
|
||||
{
|
||||
|
||||
// This class purpose to wrap compute buffer which updated every frame
|
||||
public class FrameFencedGPUBufferPool<T>: IDisposable where T: unmanaged
|
||||
{
|
||||
BufferPool bufferPool;
|
||||
NativeQueue<int> busyBuffers;
|
||||
int currentFrameBufferIndex = -1;
|
||||
int elementCount;
|
||||
readonly GraphicsBuffer.Target bufferTargetFlags;
|
||||
readonly GraphicsBuffer.UsageFlags bufferUsageFlags;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public FrameFencedGPUBufferPool(int count, GraphicsBuffer.Target target, GraphicsBuffer.UsageFlags usageFlags)
|
||||
{
|
||||
elementCount = count;
|
||||
bufferTargetFlags = target;
|
||||
bufferUsageFlags = usageFlags;
|
||||
bufferPool = new BufferPool(count, UnsafeUtility.SizeOf<T>(), target, usageFlags);
|
||||
busyBuffers = new (Allocator.Persistent);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
busyBuffers.Dispose();
|
||||
bufferPool?.Dispose();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void BeginFrame()
|
||||
{
|
||||
Assert.IsTrue(currentFrameBufferIndex == -1);
|
||||
RecoverBuffers();
|
||||
currentFrameBufferIndex = bufferPool.GetBufferId();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void EndFrame()
|
||||
{
|
||||
Assert.IsFalse(currentFrameBufferIndex == -1);
|
||||
busyBuffers.Enqueue(currentFrameBufferIndex);
|
||||
currentFrameBufferIndex = -1;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void RecoverBuffers()
|
||||
{
|
||||
var totalLiveFrames = SparseUploader.NumFramesInFlight + 1;
|
||||
for (var i = totalLiveFrames; i < busyBuffers.Count; ++i)
|
||||
{
|
||||
var bufID = busyBuffers.Dequeue();
|
||||
bufferPool.PutBufferId(bufID);
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public bool Grow(int requiredElementsCount)
|
||||
{
|
||||
var chunkSizeInBytes = 0x1000 * 16;
|
||||
var elementSizeInBytes = UnsafeUtility.SizeOf<T>();
|
||||
var chunkSizeInElements = chunkSizeInBytes / elementSizeInBytes;
|
||||
var newSizeInElements = requiredElementsCount + chunkSizeInElements;
|
||||
if (elementCount < newSizeInElements)
|
||||
{
|
||||
var newSizeInBytes = newSizeInElements * elementSizeInBytes;
|
||||
|
||||
if (newSizeInBytes > SystemInfo.maxGraphicsBufferSize)
|
||||
{
|
||||
var formattedRequiredBytes = CommonTools.FormatMemory(newSizeInBytes);
|
||||
var formattedMaxComputeBufferBytes = CommonTools.FormatMemory(SystemInfo.maxGraphicsBufferSize);
|
||||
throw new InvalidOperationException($"Requested buffer size ({requiredElementsCount} elements, {formattedRequiredBytes}) exceeded maximum compute buffer capacity of '{formattedMaxComputeBufferBytes}'");
|
||||
}
|
||||
|
||||
bufferPool?.Dispose();
|
||||
busyBuffers.Clear();
|
||||
bufferPool = new BufferPool(newSizeInElements, UnsafeUtility.SizeOf<T>(), bufferTargetFlags, bufferUsageFlags);
|
||||
elementCount = newSizeInElements;
|
||||
currentFrameBufferIndex = -1;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public NativeArray<T> LockBufferForWrite(int startIndex, int count)
|
||||
{
|
||||
var b = bufferPool.GetBufferFromId(currentFrameBufferIndex);
|
||||
var rv = b.LockBufferForWrite<T>(startIndex, count);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void UnlockBufferAfterWrite(int count)
|
||||
{
|
||||
var b = bufferPool.GetBufferFromId(currentFrameBufferIndex);
|
||||
b.UnlockBufferAfterWrite<T>(count);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public GraphicsBuffer GetBuffer()
|
||||
{
|
||||
if (currentFrameBufferIndex < 0)
|
||||
return null;
|
||||
|
||||
var b = bufferPool.GetBufferFromId(currentFrameBufferIndex);
|
||||
return b;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static implicit operator GraphicsBuffer(FrameFencedGPUBufferPool<T> b) => b.GetBuffer();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 348ddec2996af1d44bc38079d7dfa13e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Toolbox/GPU/FrameFencedGPUBufferPool.cs
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f33d6ad918265a147aaf4ae0b3655ab8
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
#pragma kernel CopyBuffer
|
||||
#pragma kernel ClearBuffer
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
ByteAddressBuffer srcBuf;
|
||||
RWByteAddressBuffer dstBuf;
|
||||
int copyBufferElementsCount;
|
||||
int srcOffset, dstOffset;
|
||||
int clearValue;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(128, 1, 1)]
|
||||
void CopyBuffer(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= (uint)copyBufferElementsCount)
|
||||
return;
|
||||
|
||||
uint inDataOffset = tid * 4 + srcOffset;
|
||||
int v = srcBuf.Load(inDataOffset);
|
||||
uint outDataOffset = tid * 4 + dstOffset;
|
||||
dstBuf.Store(outDataOffset, v);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
[numthreads(128, 1, 1)]
|
||||
void ClearBuffer(uint tid: SV_DispatchThreadID)
|
||||
{
|
||||
if (tid >= (uint)copyBufferElementsCount)
|
||||
return;
|
||||
|
||||
uint outDataOffset = tid * 4 + dstOffset;
|
||||
dstBuf.Store(outDataOffset, clearValue);
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2f4338f751d23e4db39523b314244b9
|
||||
ComputeShaderImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Toolbox/GPU/Resources/RukhankaGPUBufferManipulation.compute
|
||||
uploadId: 897522
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.Rendering;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
namespace Rukhanka.Toolbox
|
||||
{
|
||||
public class SparseUploaderPool: IDisposable
|
||||
{
|
||||
Stack<SparseUploader> freeUploaders;
|
||||
List<SparseUploader> allUploaders;
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public SparseUploaderPool()
|
||||
{
|
||||
freeUploaders = new ();
|
||||
allUploaders = new ();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (var u in allUploaders)
|
||||
{
|
||||
u.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void FrameCleanup()
|
||||
{
|
||||
foreach (var u in allUploaders)
|
||||
{
|
||||
u.FrameCleanup();
|
||||
}
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public SparseUploader GetUploader(GraphicsBuffer gb)
|
||||
{
|
||||
SparseUploader rv;
|
||||
if (freeUploaders.Count > 0)
|
||||
{
|
||||
rv = freeUploaders.Pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
rv = new SparseUploader(gb);
|
||||
allUploaders.Add(rv);
|
||||
Assert.IsTrue(allUploaders.Count < 0xff, "Looks like 'PutUploader' call is forgotten somewhere! There are too much of created uploaders.");
|
||||
}
|
||||
|
||||
rv.ReplaceBuffer(gb);
|
||||
return rv;
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void PutUploader(SparseUploader su)
|
||||
{
|
||||
freeUploaders.Push(su);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 18f595187c7f2c141b045a24d8360f70
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
AssetOrigin:
|
||||
serializedVersion: 1
|
||||
productId: 298480
|
||||
packageName: Rukhanka Animation System 2
|
||||
packageVersion: 2.9.0
|
||||
assetPath: Packages/com.rukhanka.animation/Rukhanka.Toolbox/GPU/SparseUploaderPool.cs
|
||||
uploadId: 897522
|
||||
Reference in New Issue
Block a user