GPU Screens
● Intermediate4 minBefore this: WindowsSpec 14.24
std.gpu draws into a window with the GPU: a screen for the window, a frame for each picture, cleared and shown at the screen's rate. Drawing triangles with shaders written in Kavach comes next.
use std.window
use std.gpu
fn main() ! Error uses Window {
const win = try window.open("Hello", 640, 480)
const screen = try gpu.screen(win)
let open = true
while open {
for e in win.poll() {
match e {
Event.Closed => {
open = false
},
_ => {},
}
}
const frame = try screen.frame()
frame.clear(0.1, 0.2, 0.3)
frame.show()
}
}gpu.screen(win)gives what draws into the window, using the program's GPU.screen.frame()gives the next picture, as big as the window is now. It waits for the screen's next refresh when the last picture isn't shown yet (vsync), so the loop runs at the screen's rate.frame.clear(r, g, b)fills it with one color, each part from 0 to 1, andframe.show()puts it on the screen. A frame never shown is thrown away.- Drawing changes the program's own windows, so it needs
Window. - Where there is no GPU, or the window can't be drawn into, it fails with
GpuError.Unavailable(reason). So does a frame of a minimized window; the nextframe()tries again.
A private function may leave its uses out, and the compiler works it out. A pub one must say it, so a function that draws for other modules names Window:
use std.window
use std.gpu
pub fn paint(win: AppWindow) ! GpuError {
const screen = try gpu.screen(win)
const frame = try screen.frame()
frame.clear(0.1, 0.2, 0.3)
frame.show()
}
fn main() uses Window {
const win = window.open("Hello", 640, 480) catch _ => return
paint(win) catch _ => {}
}The compiler refused the program:
kavach run screen-needs-window.kav
error: `paint` is `pub`, so it must say what it uses: add `uses Window` (through `screen`) (spec 8.1)Every function and method
| Function or method | Gives |
|---|---|
gpu.screen(win) -> Screen ! GpuError | What draws into the window win, using the program's GPU |
screen.frame() -> Frame ! GpuError | The next picture to draw, as big as the window is now. It waits for the screen's next refresh when the last picture isn't shown yet (vsync), so a loop of frames runs at the screen's rate |
frame.clear(r, g, b) | Fills the picture with one color; each part is a Float32 from 0 to 1 |
frame.draw(pipeline, vertices) | Draws vertices through pipeline (15.3) |
frame.draw(pipeline, vertices, instances: items) | The same once for each item of items, which the vertex fn gets as its second parameter |
frame.draw(pipeline, vertices, instances: items, with: shared) | The same, shared given to every vertex as the vertex fn's last parameter |
frame.show() | Puts the picture on the screen |
gpu.pipeline(vertex_fn, fragment_fn) -> Pipeline | A pipeline drawing triangles with a gpu vertex fn and a gpu fragment fn (15.3) |
Built now: gpu.screen, frame, clear and show. frame.draw and gpu.pipeline are specified but not built yet: they come with the shaders below.
Coming next: shaders in Kavach
Triangles will be drawn by two kinds of gpu fn: a gpu vertex fn works out where each corner goes on the screen, and a gpu fragment fn gives the color of each pixel inside. This is the spec's example; it doesn't compile yet:
type Corner {
x: Float32
y: Float32
}
type Dot {
x: Float32
y: Float32
heat: Float32
}
type Camera {
zoom: Float32
}
type Lit {
position: (Float32, Float32, Float32, Float32)
heat: Float32
}
gpu vertex fn place(c: Corner, d: Dot, cam: Camera) -> Lit {
Lit(position: ((c.x + d.x) * cam.zoom, (c.y + d.y) * cam.zoom, 0.0, 1.0), heat: d.heat)
}
gpu fragment fn glow(l: Lit) -> (Float32, Float32, Float32, Float32) {
(l.heat, 0.2, 1.0 - l.heat, 1.0)
}
const dots = gpu.pipeline(place, glow)
frame.draw(dots, square, instances: swarm, with: Camera(zoom: 1.0))A list a GPU map made, and that is still in GPU memory, will be drawn from there with nothing copied: a particle swarm moved by a map each frame is drawn where it is. See GPU for gpu fn and map today.