如何通过随机访问纹理来提高FPS并克服内存带宽?

时间:2016-09-27 03:09:55

标签: opengl-es textures shader compute-shader

在我的虚拟现实程序中,我受到内存带宽的严重限制:

func toAnyObject() -> AnyObject {
    return [
        "name": title,
        "addedByUser": subtitle,
        "completed": imageURL
    ] as NSDictionary
}

你可以看到我在#version 320 es precision lowp float; const int n_pool = 30; layout(local_size_x = 8, local_size_y = 16, local_size_z = 1) in; layout(rgba8, binding = 0) writeonly uniform lowp image2D image; layout(rgba8, binding = 1) readonly uniform lowp image2DArray pool; uniform mat3 RT[n_pool]; // <- this is a rotation-translation matrix void main() { uint u = gl_GlobalInvocationID.y; uint v = gl_GlobalInvocationID.x; vec4 Ir = imageLoad(pool, ivec3(u,v,29)); float cost = 1.0/0.0; for (int j = 0; j < 16; j++) { float C = 0.0; for (int i = 0; i < n_pool; i++) { vec3 w = RT[i]*vec3(u,v,j); C += length(imageLoad(pool, ivec3(w[0],w[1],i)) - Ir); } } cost = C < cost ? C : cost; } imageStore(image, ivec2(u,v), vec4(cost, cost, cost, 1.0)); } 上有很多随机访问(宽度= 320,高度= 240,图层= 30)。但是,访问不是随机,因为它将在 u,v 附近。

以下是我的想法:

  • 另一种纹理格式,而不是rgba-floats(可能是rgba-unsigned字节?)。
  • 共享内存太小,甚至无法存储一张灰度图像。
  • 更改循环顺序。奇怪的是,这种排序速度更快,但另一种应该有更好的缓存行为。
  • 调整工作组的大小以更好地适应纹理。
  • 使用压缩图像(不太可能提高性能)。然而,理论上,这应该有助于带宽。

你有什么想法?

2 个答案:

答案 0 :(得分:0)

您是否有任何实际数据显示您遇到的问题是纹理 带宽,还是只是一个假设?

我可以看到一些问题,这些问题可能实际上不是你的问题。例如:

vec3 w = RT[i]*vec3(u,v,j);

...你的内部循环中有一个mat3数组加载,所以在大多数架构中,我知道你可能是统一的获取绑定,而不是纹理绑定。这应该在GPU数据缓存中很好地缓存,但是每次循环迭代可能仍然会被重新获取,这比单个imageLoad()要贵得多,除非你的纹理格式异常宽......

如果使用fp16或fp32 RGBA纹理输入,则较窄的8位unorm格式总是会更快(fp32特别昂贵)。

对于以下内容:

cost = C < cost ? C : cost;

...在代码生成方面使用min()内置函数可能更可靠。

答案 1 :(得分:0)

更新1

  • 从传统的像素管道转移到计算着色器带来了3倍的加速

更新2

  • 使用压缩格式增加5%FPS

更新3

  • 在这个简化版本中,我没有表明我确实在运行中创建了许多临时向量(包括外部和内部循环)。通过在循环内删除mat3/vec4/vec3创建带来了2倍的加速。非常令我惊讶的是,在循环中创建向量非常昂贵。

现在我已经深入实时并实现了我的目标......