如何以 bgra8Unorm 像素格式绘制 MTLTexture

How to draw on MTLTexture in bgra8Unorm pixel format

当我使用 rgba32Float 像素格式在 MTLTexture 上绘图时,我的代码有效,然后我可以从中取出 CVPixelBuffer

但是 FlutterTexture 需要 bgra8Unorm 格式。由于性能开销,我不想转换 CVPixelBuffer

所以我尝试在 MTLTexture 上使用 bgra8Unorm 像素格式进行渲染,但无法编译以下片段着色器代码:

fragment vector_uchar4 fragmentShader2(Vertex interpolated [[stage_in]]) {
    return 0xFFFFFFFF;
}

有错误:Invalid return type 'vector_uchar4' for fragment function 我试图用 uint 类型替换它,但它崩溃并出现错误:

Fatal error: 'try!' expression unexpectedly raised an error:
Error Domain=AGXMetalA11 Code=3 
"output of type uint is not compatible with a MTLPixelFormatBGRA8Unorm color attachement."
UserInfo={NSLocalizedDescription=output of type uint is not compatible with a MTLPixelFormatBGRA8Unorm color attachement.}

如果我使用 vector_float4vector_half4 return 键入我的纹理和缓冲区是空的。

我必须为 bgra8Unorm 像素格式使用哪种 return 类型并获得非空图像?金属有可能吗?

这取决于许多不同的因素。在大多数情况下,您应该使用 float4half4.

所有支持 metal 的现代苹果 GPU 都设计用于对(32 位或 64 位)浮点数据执行计算。这就是 GPU 的工作方式,这意味着着色器在 FloatSnormUnorm 格式上计算的任何读取操作都将在 32 位或 64 位浮点数上执行,无论的原始输入格式。 在任何写入操作中,着色器都会执行从 32 位或 64 位浮点到目标格式的转换。
转换规则请见Metal Shading Language specification第217页

任何使用 FloatSnormUnorm 后缀的金属格式都是浮点格式,而 UintSint 是无符号和有符号整数。

Float - metal 定义的任何表示形式中的浮点值。
Unorm - [0.0, 1.0] 范围内的浮点值。
Snorm - [-1.0, 1.0] 范围内的浮点值。
Uint - 无符号整数。
Sint - 有符号整数。

我在 Metal Shading Language specification

的第 30 页找到了答案

最后这段代码按预期绘制图像:

fragment float4 fragmentShader2(Vertex interpolated [[stage_in]]) {
    // ...
    rgba8unorm<float4> rgba;
    rgba = float4(color.r, color.g, color.b, 1.0);
    return rgba;
}

如果有人能解释幕后发生的事情,我真的不想浪费赏金。