A shading language and shader compiler infrastructure for building shaders and shader tools.

Bento compiles to its own IR and lowers that directly to what your graphics API requires. The whole infrastructure is one C library without dependencies, small enough to vendor, and safe to run on untrusted input.

Example

Fragment shader with a struct of inputs and a struct of outputs. Each field is bound through an attribute.

hello.bento
import std;

struct Pixel {
	[[location(0)]] uv: f32x2,
}

struct Color {
	[[color(0)]] rgba: f32x4,
}

[[stage(.Fragment)]]
fn main(px: Pixel) -> Color {
	let corner = px.uv.x * px.uv.y;
	let glow = std::smooth_step(0.0, 1.0, corner);
	return { f32x4 { px.uv, glow, 1.0 } };
}
compiled to bytecode, then to GLSL or SPIR-V
bento-c hello.bento
bento-llc hello.bbc
bento-llc --target=spirv hello.bbc

Language

Barriers, subgroups, and uniformity are concepts built into the language rather than thinly typed intrinsics bolted onto C. Language tour

Uniformity analysis

How widely every value is shared is proven during compilation for every rung from the whole dispatch down to one thread. Derivatives, simdgroup operations, and bindless indices are checked against it.

Automatic barriers

Wherever workgroup memory written by one thread is read by another, a barrier is inserted in uniform code before the read.

Context parameters

Built-in values such as the thread id, and values defined in the shader, are available at any depth of the call chain through checked with clauses. There are no globals and no parameters passed by hand.

Generics

Bracket parameters with built-in bounds and structural interfaces. Generics are type checked once and can be exported through bytecode.

Compile-time code

Under the type checker, code is selected with const if and unrolled with const for. Modules and a linker are used in place of #include.

Memory spaces

Every reference type includes the memory space: &thread, &workgroup, &storage, or &constant. Buffers and workgroup memory can be passed to functions on every target.

Infrastructure

An IR and a set of language agnostic tools that work on it. The Bento language and compiler are a small client on top of all that, kind of like how clang is the C/C++ frontend for LLVM. Tools, IR and bytecode, Library

Structured SSA

Blocks belong to if and loop instructions rather than to a control flow graph. IR can be built, edited, printed, and verified from other programs.

Bytecode

Modules can be linked at build time or at run time, left incomplete, and mixed with IR from any source.

Tools

Compiler, linker, optimizer, code generator, disassembler, validator, stripper, and language server.

Optimizer

Inlining, mem2reg, scalar replacement of aggregates, folding, if-conversion, CSE, dead store and redundant load elimination, aggressive dead code elimination, and load narrowing. Comprehensive rule-driven algebraic simplifications.

Library

One C header. Memory, files, and diagnostics are provided by the host through callbacks.

Untrusted input

No source or bytecode can crash the library, hang it, or cause out of memory without being reported and gracefully handled. If you can provide an input that proves otherwise, it's worth up to $500 USD as part of our bug bounty program.

Comparison with GLSL, HLSL, and WGSL

BentoGLSL, HLSL, WGSL
OutputLowered straight to SPIR-V, AIR, or GLSLglslang, DXC, Tint, or a transpiler in between
ReuseModules, imports, and a linker#include
VariantsType checked const if, const for, and genericsPreprocessor macros
UniformityProven for every value and checked across modulesUnchecked in GLSL and HLSL but checked for derivatives and barriers in WGSL
BarriersInserted automaticallyWritten by hand
Built-insContext parameters checked per stageGlobals or semantics
Buffers in functionsReferences with a memory spaceNot allowed in GLSL
ResultsMultiple return valuesout parameters
EmbeddingOne C library without dependenciesLarge C++ code bases
AccessEvery stage public, down to the IRSource in, code out

Rationale

“The shader situation in Vulkan and DX12 is somewhat dire and this is an attempt at trying to address it.”

The rationale is about the lessons from past mistakes, why Bento is not a transpiler, and why the library comes first. Status is on the roadmap.