Graphics
Vertex, fragment, geometry, and tessellation shaders are written as plain Julia functions and compiled to SPIR-V. There is no GLSL, no shader file format, no external preprocessor — your shaders live in the same module as your CPU code, share types and helpers with the rest of your codebase, and are subject to the same Julia tooling.
The graphics surface area is functional and exercised by real-world renderers, but the public API is still being refined. Expect minor breaking changes between 0.x releases.
Pipelines
The high-level entry points are Rasterizer, TrianglePipeline, and LinePipeline. Each takes a vertex and fragment shader plus optional state (blend mode, cull face, depth test, topology):
using Lava, GeometryBasics
vertex(pos, mvp) = mvp * pos # → vec4 clip-space position
fragment(color) = color # → vec4 RGBA
pipeline = Rasterizer(
vertex = vertex,
fragment = fragment,
blend = :alpha,
cull = :back,
depth = :less,
topology = :triangle_list,
)The shader functions are regular Julia: they can call each other, dispatch on types, use packages (GeometryBasics, LinearAlgebra, StaticArrays, …), and are compiled per-instantiation just like compute kernels.
Render targets and present
window = RenderWindow(width=1280, height=720, title="demo")
framebuffer = window.framebuffer
while window_should_close(window) == false
draw!(pipeline, framebuffer; vertices=mesh, uniforms=params)
present_frame!(window)
endOffscreen rendering uses LavaFramebuffer(width, height) directly without opening a window:
fb = LavaFramebuffer(1920, 1080)
draw!(pipeline, fb; vertices=mesh, uniforms=params)
img = Array(fb) # → Matrix{RGBA{N0f8}}Textures and samplers
img = LavaTexture2D(load("brick.png"))
sampler = LavaSampler(; filter=:linear, wrap=:clamp_to_edge)
fragment(uv, tex, smp) = sample(tex, smp, uv)Textures and samplers participate in the same BDA arg-packing as buffer arguments; descriptor set management is hidden from the user.
Geometry and tessellation
Geometry and tessellation control / evaluation stages are wired in the same way: you pass geometry=... and tess_control=... / tess_eval=... to Rasterizer. The custom emitter handles all five graphics stages — Lava does not delegate to llc, which still crashes on geometry shaders today.
Pixel readback
For most workflows you'll just call Array(framebuffer) to grab the final image after vk_flush!. The conversion handles the GPU → CPU staging, pixel format, and row-pitch unswizzling.