The render hardware interface
A backend-abstract GPU service
The render hardware interface is Platform's GPU service: a backend-abstract API for creating GPU resources and submitting draw work, with Metal behind it today. It is raster- and draw-focused — the surface Prism UI's 2-D canvas is built on — and it keeps the rest of the stack from ever touching Metal directly.
#include "prism/platform/Rhi.h"
using namespace prism::platform::rhi;
auto device = Device::create(Backend::Metal); // or Device::createHeadless()
auto buffer = device->newBuffer(vertices, bytes);
auto texture = device->newRenderTexture(w, h, PixelFormat::RGBA8Unorm);
auto shader = device->newShader(mslSource);
auto pipeline = device->newPipeline({shader, /* vertex layout, blend … */});
The resource set
The interface covers exactly what a 2-D drawer and a viewport need, no more:
- Device — creates everything; real (from a window context) or headless (for tests).
- Buffers & textures — vertex/index/uniform buffers, sampled and render textures.
- Shaders & pipeline state — compile MSL, bake a pipeline (shader + vertex layout + blend).
- Encoders & passes — record draw commands into a command buffer for an offscreen texture or a window drawable.
- Readback —
readbackRGBApulls pixels back to the CPU.
Pipelining, the right way
Responsiveness depends on not stalling the CPU on the GPU every frame. The RHI follows the principle of committing work and continuing during interaction, and blocking only for an explicit readback and at present:
endsubmits a pass withwait = false— live frames pipeline; pacing comes from drawable acquisition, not a per-pass stall.readbackRGBAdoes the onewaitUntilCompletedit needs (same-queue ordering covers earlier offscreen passes), so a--shotrender stays correct.
This is what fixed a per-frame CPU↔GPU stall that used to make panning lag: never block per pass, only at the boundaries that truly need it. The per-region offscreen buffers in the UI toolkit are RHI render textures used exactly this way — render a panel once, then re-composite its texture.
Headless = testable
Device::createHeadless() gives a GPU device with no window, so rendering is covered by automated tests: render an offscreen triangle, read it back, assert on the pixels — no display required. That is why the drawing stack ships with real GPU tests rather than "looks right on my machine." The RHI is intentionally separate from any compute-focused render engine: a tracer would create its own device abstraction sharing the same MTLDevice — two abstractions, one piece of hardware. The other cross-cutting infrastructure Platform carries is the buses.