跳转到内容
查看源码

第一个 Kernel

Kernel 是 Entelechy 的“定律”:一个小的类型化函数 Y = K(X, P, C)——输出 Y 由输入 Field X、参数 P 和上下文 C(坐标、时间、指针……)决定。本页写一个画同心圆环的 Kernel,并用 entelechy check 检查它。

终端窗口
mkdir -p rings/kernels rings/tests
cd rings

新建 kernels/rings.ent:

/// Concentric rings: every pixel works out its own color from where it is.
kernel demo.rings@1 {
requires { field.write; }
/// How many rings fit from the center to the edge.
param count: Float = 6.0;
output result: Image;
compute {
let uv = coord() / domain() * 2.0 - 1.0;
let r = length(uv);
let band = step(0.5, fract(r * count));
return vec4(band, band * 0.6, 1.0 - band, 1.0);
}
}

逐行看:

写法 含义
kernel demo.rings@1 Kernel 的身份 名字@版本。场景按这个 id 绑定,而不是按文件。
requires { field.write; } 声明需要的能力。只写输出、不读输入,所以只要 field.write。
param count: Float = 6.0; 参数及默认值,场景可以覆盖它。Float 字面量必须写成 6.0,不能写 6。
output result: Image; 输出端口。Image 是 Grid<Vec4>,每个通道 0–1。
compute { … } map 模式:对输出定义域中的每个元素各运行一次,返回该元素的值。
coord()、domain() 当前元素的坐标与整个定义域的尺寸(见上下文函数)。
/// 文档注释,会随 Kernel 一起发布,kernels 协议操作会返回它。
终端窗口
entelechy check kernels/rings.ent
kernels/rings.ent: demo.rings@1
kernel demo.rings@1
requires field.write
param count: Float = 6.0
output result: Image

check 打印每个 Kernel 的清单(manifest)。加 --ir 可以看到后端实际运行的、经过校验的 IR。

把 fract(r * count) 改成 fract(r * cnt),再检查:

kernels/rings.ent:10:40: `cnt` is not defined
error: 1 problem(s) found

诊断总是 文件:行:列: 信息。运行中的会话遇到这种错误会拒绝新版本、保留旧版本,这就是热替换的基础。

在同一个文件里追加一个给图片上色的 Kernel:

kernel demo.tint@1 {
requires { field.read; field.write; }
input source: Image;
param warmth: Float = 0.8;
output result: Image;
compute {
let c = sample(source);
return vec4(c.rgb * vec3(1.0, warmth, 0.4), c.a);
}
}

sample(source) 读取输入在当前元素处的值,所以它需要 field.read。一个 .ent 文件可以放任意多个 Kernel 以及它们共享的 struct、type、fn。

Kernel 本身不会运行——它需要被场景放置。下一页:第一个场景。