我正在使用Unity开发VR应用程序,使用本地插件进行视频解码,并希望对解码后的视频帧进行一些处理。我的第一步是使用Unity计算着色器,从Unity应用程序中的C#脚本触发调度。这个方法可以正常工作,我也看到了预期的结果,但是在渲染线程上运行的本地插件需要将一个参数提取出来,传递给主线程运行的计算着色器,这是一个同步问题。我认为可以通过将Unity计算着色器转换为D3D11计算着色器来解决这个问题,并且尽早在本地插件中处理已解码的帧。这样也会得到预期的结果,但性能损失非常大。应用程序的帧率下降,使用RenderDoc来分析单个帧时,计算调度调用在插件中的时间约为32毫秒,而使用Unity的计算着色器时只有3毫秒。
我找不到任何信息来解释两者之间存在如此大的差异。我尝试简化D3D11着色器,只输出零,但Profiler仍然显示大约32ms,这让我认为这与我在插件中设置着色器有关。我包含了一些代码来展示我的插件计算着色器的设置和执行过程。
原生C++插件中的计算着色器:
简化后的计算着色器本身:
有什么明显的问题我忽略了吗,还是Unity在优化方面做得非常好?
我找不到任何信息来解释两者之间存在如此大的差异。我尝试简化D3D11着色器,只输出零,但Profiler仍然显示大约32ms,这让我认为这与我在插件中设置着色器有关。我包含了一些代码来展示我的插件计算着色器的设置和执行过程。
原生C++插件中的计算着色器:
void process()
{
ID3D11DeviceContext* ctx = NULL;
device->GetImmediateContext(&ctx);
ctx->UpdateSubresource(_pCB, 0, nullptr, &_bufferStruct, 0, 0);
if (!_resourcesSet) {
// Set read texture
ID3D11ShaderResourceView * inY = nullptr;
ID3D11ShaderResourceView * inU = nullptr;
ID3D11ShaderResourceView * inV = nullptr;
_inputTexture->getSRVs(&inY, &inU, &inV);
// Set write texture
ID3D11UnorderedAccessView * outY;
ID3D11UnorderedAccessView * outU;
ID3D11UnorderedAccessView * outV;
_outputTexture->getUAVs(&outY, &outU, &outV);
ctx->CSSetConstantBuffers(0, 1, &_pCB);
ctx->CSSetShaderResources(0, 1, &inY);
ctx->CSSetShaderResources(1, 1, &inU);
ctx->CSSetShaderResources(2, 1, &inV);
ctx->CSSetUnorderedAccessViews(0, 1, &outY, nullptr);
ctx->CSSetUnorderedAccessViews(1, 1, &outU, nullptr);
ctx->CSSetUnorderedAccessViews(2, 1, &outV, nullptr);
ctx->CSSetShader(_computeShader, NULL, 0);
_resourcesSet = true;
}
ctx->Dispatch(outputWidth / 8, outputHeight / 8, 1);
ctx->Release();
}
简化后的计算着色器本身:
SamplerState TextureSampler
{
Filter = MIN_MAG_MIP_LINEAR;
AddressU = Wrap;
AddressV = Wrap;
};
Texture2D<float> inY : register(t0);
Texture2D<float> inU : register(t1);
Texture2D<float> inV : register(t2);
RWTexture2D<float> outY : register(u0);
RWTexture2D<float> outU : register(u1);
RWTexture2D<float> outV : register(u2);
[numthreads(8,8,1)]
void CSMain (uint3 id : SV_DispatchThreadID)
{
float3 col = float3(0.0, 0.0, 0.0);
outY[id.xy] = col.r;
outU[id.xy / 2] = col.g;
outV[id.xy / 2] = col.b;
}
有什么明显的问题我忽略了吗,还是Unity在优化方面做得非常好?
id.xy / 2
提取到一个本地的 unit2 变量中,并将其更改为id.xy * 0.5
。乘法通常比除法快3-4倍,只进行一次而不是两次可能会给您带来更高的收益。 - NextInLine