#spir-v #language #shader #graphics

菊花

一种编译为SPIR-V的纯函数式语言玩具

1个不稳定版本

0.0.1 2019年8月7日

#14#spirv

MIT/Apache

72KB
1.5K SLoC

菊花

这是一项关于制作一个可编译为SPIR-V着色器(用于Vulkan)的玩具编程语言的实验。

基本上,我想创建一个针对SPIRV的编译器,它比shaderc更容易嵌入,并且我想有一个主要是纯函数式的着色语言(因为着色器本质上就是纯函数),所以我们就是在这里。我可能永远也完成不了它。

构建

到目前为止,它只经过Linux测试。由于没有平台特定的依赖项,可能可以在任何东西上正常运行。

运行单元测试需要官方Khronos SPIR-V工具中的命令行程序spirv-val;在Debian上,你只需运行apt install spirv-toolsglslang-tools可能也有用。

为了真正看到正在发生的事情的细节,还可以使用cargo test -- --nocapture --test-threads=1进行测试。

设计

这主要是一个关于如何使某种东西编译为SPIR-V的实验,所以。它将是一个强类型、纯函数式语言,可能看起来有点像ML。但现在我正在从IR和后端开始,因为编写解析器既令人沮丧又缓慢。

实际上,没有突变并不会使任何东西更难,因为SPIR-V已经是SSA形式。

尽管在传统上,处理此类语言中的循环的方式是通过递归,而着色器通常不能递归,所以这将是棘手的。我们可能不得不引入具有相应突变的循环(模拟的或真实的),或者只允许可以展平为循环的递归。尽管SPIR-V规范对递归是否允许相当沉默...

我想这甚至还不是一种真正的函数式语言,因为它还没有实现函数作为值,尽管看起来SPIR-V可以支持它。

目标

  • 编译为SPIR-V
  • 在真实GPU上执行顶点+片段着色器
  • 易于使用
  • 简单/快速(?)构建
  • 作为库或独立程序运行

非目标

  • 优化
  • 非常完整
  • 非常舒适
  • 其他类型的着色器
  • 类型推断
  • 模块

待办事项

实际上要做的

  • 将unwrap替换为expect。
  • 更好地考虑错误处理。
  • 使入口点工作得更好。
  • 创建实际的CLI——最终生成的代码测试可能应该包含spirv-val
  • 命名/标签/更有利于调试的东西。

要考虑的事情

  • 向量交错——我们需要它吗?我们能否只通过模式匹配来完成所有操作?让我们试试。
  • 向量类型——它们是否可以是结构体?这将很好地与模式匹配配合使用。
  • 枚举/选项类型
  • 结构体布局和绑定
  • 循环(递归?)
  • 数学和类型系统
  • 尝试模糊测试?

与(希望)已知有效的编译器生成的代码进行比较

# -G for GLSL semantics, -V for Vulkan semantics.
glslangValidator -V test.frag.glsl; spirv-dis frag.spv

暂不执行

  • 入口点声明
  • 除了f32之外的标量
  • 更好的结构体和向量处理

语法注意事项

ML-y语法还是Lispy语法?

让我们先采用ML-y语法,看看它是什么样子。

实际上,我不确定如何处理数学运算;我们没有泛型或特型,所以创建一个Add特型不起作用。然而,我们也没有类型推断,所以不一定需要OCaml风格的++.似乎我们可以以C风格完成,将数学运算符作为特殊情况重载,这我不喜欢,但在实践中很容易,或者我们可以以ML风格完成,不重载任何东西,这更简单但更烦人。

但我们可以使其整数加法为+,浮点数为+.,向量为+/,矩阵为++。这几乎是太可爱而无法抗拒。但目前,未定义。

-- Yes, Lua style comments
-- just to mess with people.
/- Because why not -/

-- DECLARATIONS

-- Anyway, two types of decl's, functions and structs.

fn foo x: F32, y: F32 -> bool
    -- ...
end

-- Types must start with a capital letter
struct SomeStruct
    x: F32,
    y: F32,
end

-- EXPRESSIONS

-- Floats must have a decimal point
let foo: F32 = 10.0

-- Math
x + y
x - y
x * y
x / y
x % y
-- Comparison
x == y
x != y
x > y
x >= y
x < y
x <= y

-- Logic, on booleans.  No bitwise stuff yet.
x or y
x and y
x xor y
not x

-- Blocks
do
    ...
end

-- Function calls
foo(x, y, z)

-- Structure literals
SomeStruct { x: 1.0, y: 2.0 }

-- Pattern matches

match foo
    | 1.0 -> foo * 2.0
    | 2.0 -> foo / 2.0
    | _ -> -9999.0
end

-- Destructuring matches
-- variables always are lowercase.

let SomeStruct { x, _ } = foo
-- x is now bound

依赖关系

~7.5MB
~169K SLoC