【问题标题】:Slow texture fetch in fragment shader using Vulkan使用 Vulkan 在片段着色器中缓慢获取纹理
【发布时间】:2016-08-15 10:46:37
【问题描述】:

我正在做一个内核大小为 64 的 SSAO 着色器。

SSAO 片段着色器:

const int kernelSize = 64;
for (int i = 0; i < kernelSize; i++) {
        //Get sample position
        vec3 s = tbn * ubo.kernel[i].xyz;
        s = s * radius + origin;
        vec4 offset = vec4(s, 1.0);
        offset = ubo.projection * offset;
        offset.xy /= offset.w;
        offset.xy = offset.xy * 0.5 + 0.5;
        float sampleDepth = texture(samplerposition, offset.xy).z;
        float rangeCheck = abs(origin.z - sampleDepth) < radius ? 1.0 : 0.0;
        occlusion += (sampleDepth >= s.z ? 1.0 : 0.0) * rangeCheck;
    }

samplerposition 纹理的格式为VK_FORMAT_R16G16B16A16_SFLOAT,并使用标志VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT 上传。

我正在使用带有 nvidia K1100M 显卡的笔记本电脑。如果我在 renderdoc 中运行代码,这个着色器需要 114 毫秒。如果我将 kernelSize 更改为 1,则需要 1 毫秒

这个纹理获取时间正常吗?还是我在某处设置了错误?

就像布局过渡没有通过,所以纹理在VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL而不是VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL

【问题讨论】:

  • 为什么你认为这是 vulkan 特有的?你只是做了很多工作!我认为运行循环 64x 与 1x 的成本超过 64x 的事实是因为在 1x 上编译器将摆脱循环。尝试更改分辨率。时间是否随像素数线性变化?如果是,那么您只是使 GPU 饱和。优化循环!

标签: glsl vulkan ssao


【解决方案1】:

GPU 内存依赖于大量缓存使用,如果彼此靠近的片段不采样彼此相邻的纹素 - 也称为缺乏空间连贯性,这将非常有限。我预计随机访问纹理与线性连贯访问相比,速度会降低 10 倍或更多。当使用大半径时,SSAO 很容易出现这种情况。

我建议使用较小的半径并优化纹理访问。您正在对 4 个 16 位浮点数进行采样,但您只使用了一个。将深度设置为单独的 16 位深度图像应该可以轻松实现 4 倍加速。

【讨论】:

  • 完全不写位置可能会更好。只需根据深度和片段坐标根据需要重构即可;这就是大多数延迟渲染器的工作方式。
  • @NicolBolas 有趣,我只是在寻找它,想知道为什么我以前从未读过它。不过,这对 SSAO 没有帮助
  • @Samantha:当然会。您只获取 32 个字节(深度缓冲区值),而不是获取 64 个字节。
  • @NicolBolas 确实如此,但这是人们通常这样做的方式,在像素着色器或 ssao 中迭代 32-64 次,仍然需要很多时间,因为您仍然会遇到缓存未命中
  • @Samantha:我的意思是每次 fetch 只访问 32 字节的数据。减少您检索的数据的大小可以提高缓存的一致性,并且总体上有助于提高纹理访问性能。
【解决方案2】:

您正在片段着色器上计算纹理坐标,这意味着您不允许 GPU 预取纹理。更好地计算顶点着色器上的所有纹理坐标并将其作为变量传递。

更新: 我建议在 SSAO 上添加一些高级技巧,而不是尝试纯粹计算 AO 地图。 1.您可以渲染一个小得多的AO Map并通过添加一些模糊过滤器对其进行放大。这将产生更好的结果。 2.如果你是做实时渲染,那么AO Map就不需要每帧都计算。你可以根据你的设置来伪造它。

免责声明:我做了很多基于 OpenGL ES 的着色器,我的知识主要限于移动平台。

【讨论】:

  • 所以 114 毫秒听起来像是一个正常的时间,如果它没有被着色器预取?
  • 说 114 毫秒是指每个片段吗?还是整个框架?
  • 对于 SSAO 着色器,整个绘制调用,在 1024x1024 窗口上每个纹素提取需要 114 毫秒 / 64 = 17 毫秒。
  • 据我所知,依赖纹理读取确实只是移动平台上的一个问题。不过,在所有平台上,尽可能将计算从片段着色器转移到顶点着色器仍然是一个好主意。
  • @codetiger 当我在顶点着色器中预先计算坐标时它会快得多,但在这种情况下我真的做不到,我不会得到相同的插值。
猜你喜欢
  • 2013-09-17
  • 2019-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多