GPU framebuffer / render-target readback for sokol applications.
- Zig 100%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
Keeps the four-way pin byte-identical — reveal, dvui-sokol, sokey and this must name the same sokol commit or Zig resolves two of them and app.Event stops equalling app.Event. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> |
||
| src | ||
| .gitignore | ||
| build.zig | ||
| build.zig.zon | ||
| LICENSE | ||
| README.md | ||
sokol-capture
GPU framebuffer / render-target readback for sokol-gpu applications. Pure Zig, no dvui dependency — usable from raw-sokol engines and dvui-sokol apps alike.
Status
- Backend: Metal (macOS) only. Reads
MTLStorageModePrivaterender targets via a blit to a sharedMTLBuffer, thengetBytes. Other backends returnerror.UnsupportedBackend; D3D11 / GL / WGPU paths are TODO. - Capture: synchronous one-shot —
capturePixels(allocator, img)blocks onwaitUntilCompleted. Async / per-frame video-style capture is planned, not implemented. - Encoding: built-in pure-Zig PNG encoder (RGBA8, filter 0, zlib via
std.compress.flate).
Usage
const std = @import("std");
const sg = @import("sokol").gfx;
const capture = @import("sokol_capture");
// `img` is any sokol render-target sg.Image.
var pixels = try capture.capturePixels(allocator, img);
defer pixels.deinit();
// pixels.pixels is tightly packed RGBA8, top-to-bottom.
const png_bytes = try capture.encodePng(allocator, pixels);
defer allocator.free(png_bytes);
// Write png_bytes to disk with your own file API.
Or in one shot:
const png_bytes = try capture.capturePngBytes(allocator, img);
defer allocator.free(png_bytes);
The module is Io-agnostic — it returns bytes; callers handle file writes
with whatever they already have (Zig std's std.Io, a runtime shim, etc).
Why a separate module?
- A raw-sokol game engine needs screenshot capability without depending on dvui.
- A dvui-sokol app (wk / cue / quote) gets the same primitive without duplicating Metal FFI in dvui-sokol.
- Apple Silicon's private-storage render targets need a blit step; this module owns that pattern so consumers don't reinvent it.
Build
Requires Zig 0.16. Depends only on
https://git.urverk.org/urverk/sokol-zig (same fork dvui-sokol pins, so
the build graph dedupes when both are used).
zig build check # compile-check
zig build test # unit tests (PNG encoder)
Consumers add it as a path dep:
.sokol_capture = .{ .path = "../sokol-capture" },
then in build.zig:
const sokol_capture_dep = b.dependency("sokol_capture", .{
.target = target,
.optimize = optimize,
});
// add to your exe's imports:
.{ .name = "sokol_capture", .module = sokol_capture_dep.module("sokol_capture") },