标签:|| cas function metal pac 矩阵 mes ken 邮件
在 上一篇 中使用ComputeShader进行了向量和矩阵的相乘计算,然后在C#代码中通过ComputeBuffer.GetData
方法从GPU中读取计算结果,这个方法是一个同步操作,即调用时会堵塞调用线程,直到GPU返回数据为止,所以在需要读取的数据量很大时会有比较高的耗时,会导致游戏卡顿影响体验。
Google了一番法线有异步的方法可以调用,在Unity2018版本以后增加了AsyncGPUReadback
和AsyncGPUReadbackRequest
类,可以实现异步方式从GPU读取数据,大致逻辑是:
下面是主要部分的代码
C#部分:
void Dispach()
{
if (computeShader == null)
{
return;
}
int kernelIndex = -1;
try
{
kernelIndex = computeShader.FindKernel(GetKernelName(method));
}
catch (Exception error)
{
Debug.LogFormat("Error: {0}", error.Message);
return;
}
switch (method)
{
case EMethod.ComputerBuffer:
if (m_comBuffer != null)
{
m_comBuffer.Release();
}
// 初始化m_dataArr //
InitDataArr();
m_comBuffer = new ComputeBuffer(m_dataArr.Length, sizeof(float) * Stride);
m_comBuffer.SetData(m_dataArr);
computeShader.SetBuffer(kernelIndex, "ResultBuffer", m_comBuffer);
// 在Shader中只需要用到X维的数据作为数组索引,因此只需要给X维的thread group设置数值,Y维和Z维的thread group数量为1即可 //
computeShader.Dispatch(kernelIndex, 32, 1, 1);
break;
}
}
void GetResultAsync()
{
switch (method)
{
case EMethod.ComputerBuffer:
if (m_comBuffer == null ||
m_objArr == null ||
m_dataArr == null)
{
break;
}
m_processed = false;
m_request = AsyncGPUReadback.Request(m_comBuffer, m_dataArr.Length * Stride, 0);
m_asyncFrameNum = 0;
break;
}
}
void Update()
{
if (!m_processed)
{
m_asyncFrameNum++;
if (m_request.done && !m_request.hasError)
{
m_processed = true;
Profiler.BeginSample("GetDataFromGPU_Async");
using (Timer timer = new Timer(Timer.ETimerLogType.Millisecond))
{
// 方式2 //
m_request.GetData<DataStruct>(0).CopyTo(m_dataArr);
// 方式1, ToArray 方法会有GC产生 //
//m_dataArr = null;
//m_dataArr = m_request.GetData<DataStruct>(0).ToArray();
}
Profiler.EndSample();
if (m_computeShaderWarmedUp)
{
Callback();
}
else
{
m_computeShaderWarmedUp = true;
}
Scene curScene = SceneManager.GetActiveScene();