2017-03-17 37 views
2

下面是一个简单的顶点和片段着色器组合,其中metal表示64个相同的2D四边形。通过更改UV坐标在金属中发生意外的性能下降

vertex VertexOut vertexMain(uint k [[ vertex_id ]], 
          uint ii [[instance_id]], 
          device float2* tex [[buffer(2)]], 
          device float2* position [[buffer(1)]], 
          device float* state [[buffer(0)]]){ 
    VertexOut output; 
    int i = 4*ii+1; 
    float2 pos = position[k]; 
    pos *= float2(state[i+2],state[i+3]); 
    pos += float2(state[i],state[i+1]); 
    pos.x *= state[0]; 
    output.position = float4(pos,0,1); 
    output.tex = tex[k]*float2(du,dv); 
    return output; 
}; 
fragment float4 fragmentMain(VertexOut input [[stage_in]], 
          texture2d<float> texture [[texture(0)]], 
          sampler sam [[sampler(0)]]){ 
    return texture.sample(sam, input.tex); 
}; 

采样是使用归一化的坐标,以便dudv的范围可以从0到1,并控制如何大纹理的剪辑的将被采样开始在左下角。

看来我对如何在金属中进行取样工作存在误解。无论dudv是什么值,我都希望计算成本保持不变。但是,当我将dudv增加到1时,帧频下降。我没有使用任何mipmapping,也没有更改屏幕上栅格化四边形的大小。线性滤波的影响更加剧烈,但最接近的滤波也会发生。在我看来,由于绘制到屏幕上的像素数量相同,因此GPU上的负载不应取决于dudv。我错过了什么?

编辑:这是我的采样器和附色:

let samplerDescriptor = MTLSamplerDescriptor() 
    samplerDescriptor.normalizedCoordinates = true 
    samplerDescriptor.minFilter = .linear 
    samplerDescriptor.magFilter = .linear 
    let sampler = device.makeSamplerState(descriptor: samplerDescriptor) 

    let attachment = pipelineStateDescriptor.colorAttachments[0] 
      attachment?.isBlendingEnabled = true 
      attachment?.sourceRGBBlendFactor = .one 
      attachment?.destinationRGBBlendFactor = .oneMinusSourceAlpha 
+0

你能量化你经历多少帧频下降吗? – warrenm

+0

从60到40线性采样。从最近的采样60到50。 – gloo

+0

在哪个设备和操作系统版本? – warrenm

回答

0

当你增加dudv您的股四头肌是显示您更多的质感。 GPU倾向于使用纹理数据的小型高速缓存,并且当您显示更多纹理时,您将更多地丢弃和重新填充该高速缓存。

抖动纹理缓存将使用更多的内存带宽,这是一个相当有限的资源,通常纹理内存带宽不是瓶颈,但由于您的片段着色器除了纹理拾取几乎没有什么功能,所以并不意外这是你的瓶颈。因此,改变你的紫外线对性能有影响并不奇怪。

令人惊讶的是,在这些非常强大的设备上,当你所做的只是渲染64个四边形(特别是iPad Pro是一个非常强大的设备)时,帧速率会降到60以下。也就是说,也许如果所有64个四边形都覆盖了大部分屏幕,那么帧率下降可能是可以理解的。

为了提高性能,您需要减少需要由GPU铲除的纹理数据量。从32位纹理格式(8888)更改为16位(565/4444)或4位(PVRTC压缩纹理)会产生很大的影响。

真正的大赢家可能是启用mipmapping。假设dudv的值很高,最终会使纹理最小化,然后使用mipmapping可以提供巨大的性能优势,并且作为额外的好处,纹理也会更加美观(它将修复混叠)。 33%的纹理记忆增加并不是一个坏的回报。

+0

这非常有趣。我正在使用实例渲染,这意味着所有64个四边形都与一个纹理绑定和一个绘制调用一起绘制。这种缓存问题是否仍会在这种情况下发生? – gloo

+0

是的,纹理缓存通常只有几KB,大多数纹理都是几百KB。这是一个很好的入门书:https://fgiesen.wordpress。com/2011/07/04/a-trip-through-the-graphics-pipeline-2011-part-4/ 更好地理解你的渲染场景可能是有用的 - 也许是一个截图。如果你不能达到60fps,那么64个小四边形就不算什么,而且有趣的事情正在发生。每个64个四边形覆盖整个屏幕,然后我可以理解这个问题。 – Columbo

+0

每个四分之一只覆盖屏幕的1%。我已经添加了更多描述我的管道的代码。 – gloo