Apple 的 Metal 已经来到了3.0版本,所以到倒闭他也不可能去支持 Vulkan。 但是 Moltenvk 这个项目能让开发者在 MacOS 下写跨平台图形应用,它把你 shader 生成的 SPIR-V 转换成 metal shader 文件,然后在 MacOS 下以 Metal Framework 的方式运行,所以调试 Metal 的方法同样适用于 Moltenvk。
起因
看 Vulkan Spec 的 文档的时候,对GLSL 的 component 属性的用法感到好奇,于是简单的画了个三角形,但是一直没有图像输出,于是想调试一下 GPU 数据。 MacOS 并没有 RenderDoc 之类的东西,不过 Xcode 自带 GPU 调试,具体启用方法看 Apple - Metal debug shaders。
过程
我的 Demo 是 Cmake 写的,所以直接生成 Xcode 项目,启用 Metal Debug 的方法如下:
-
在项目 TARGETS 选择你的项目
-
选中 Build Phases
-
添加
Metal.frameworklib
之后你在底部控制台 就可以看到一个 Metal 的小图标 用来抓帧数据了。
现在讲讲 component 的用法,其实是对同一份数据,进行一个偏移量的访问,对于不同类型的偏移位,官方文档有详细的表格。
// 这是我想上传的顶点数据
glm::vec4 vertData[] = {
// we use components keywords.
{0.1f, 0.2f, 0.3f, 0.4f},
{0.5f, 0.6f, 0.7f, 0.8f},
{0.9f, 1.0f, 1.1f, 1.2f},
};
// shader 部分代码
layout(location = 0, component = ?) in vec3 position;
gl_Position = vec4(position, 1.0);
这是 Xcode 捕获到的帧数据,下图是 component = 0 的情况,发现虽然上传的是vec4,但是还是按照 vec3 使用, m_18 属性的值 和 我们上传的意义对应,注意到 gl_Position 的 y 分量是相反的。
看看 component = 1 的情况,发现数据有偏移了,访问了后面 三个分量。
那么为什么 gl_Position 的 y 分量是负数? 其实看一看 SPIR-V 翻译生成的 Metal 代码就知道了。
#include <metal_stdlib>
#include <simd/simd.h>
using namespace metal;
struct main0_out
{
float3 m_28 [[user(locn0)]];
float4 gl_Position [[position]];
};
struct main0_in
{
float4 m_location_0 [[attribute(0)]];
};
vertex main0_out main0(main0_in in [[stage_in]])
{
main0_out out = {};
float3 _18 = {};
_18 = in.m_location_0.yzw;
out.gl_Position = float4(_18, 1.0);
out.m_28 = float3(_18.x, _18.y, _18.z);
out.gl_Position.y = -(out.gl_Position.y); // Invert Y-axis for Metal
return out;
}
发现生成的位置 y 做了个反转, 至于为什么反转,因为 Metal Spec 规定的 y 正方向 和 Vulkan 的 坐标系可能有所不同,可自行查阅。
总结
流水账一般的文章,但是确实 蛮有用的。让我感触最大的 跨平台框架 的实现真的太不容易了。