# iris: notable public API changes For Iris to read on her own time. Each entry is a change to iris's public surface that a widget author or app author would notice: a trait method added, removed or re-shaped; a type that callers construct differently; a capability that moved. Small and trivial changes do not go here. An entry gives the date, what changed, why, and a short before/after where it helps judge the change without the session that made it. Newest first. ## 2026-09-04: `Widget::draw` reports the size it used; `desired_width`/`desired_height` are gone A widget used to implement three methods (`draw`, `desired_width`, `desired_height`); it now implements one, `fn draw(&mut self, painter: &mut Painter) -> Size`, which draws into `painter.region()` and returns how much of it was used. Why: the two extra methods routinely re-simulated what `draw` was about to do anyway (`Span::desired_ortho` copied its own draw loop to get cross-axis sizing right) — one visit per widget per frame instead of up to three. A container that needs a child's size before placing it (alignment, centering) draws the child once at a provisional region, reads the returned `Size`, and calls the new `Painter::reposition` to move it into its final spot — an O(1) offset write, not a second draw. A widget whose drawn output never depends on the size it's given (a fixed-size `Rect`, a decoded `Image`) overrides the new `fn is_size_independent(&self) -> bool { false }` to `true`, which skips redrawing it when only its offered region changes shape. ```rust // before fn draw(&mut self, painter: &mut Painter) { /* ... */ } fn desired_width(&mut self, ctx: &mut SizeCtx) -> Len { /* ... */ } fn desired_height(&mut self, ctx: &mut SizeCtx) -> Len { /* ... */ } // after fn draw(&mut self, painter: &mut Painter) -> Size { /* ... */ } ``` `SizeCtx` and `Cache` are gone with it — see `LAYOUT.md` for the full design, the move-offset mechanism this shipped alongside, and the file list. ## 2026-09-04: texture pipeline rebuilt off the binding array `Textures`/`TextureHandle`, `GlyphPrimitive`, and `UiRenderNode::new` all changed shape. Why: the old pipeline bound every texture ever drawn in one `binding_array>` and asked every device, unconditionally, for `VK_EXT_descriptor_indexing` — a real share of Android GPUs lack it, and it failed outright on the Android emulator's software Vulkan. See TEXTURES.md's "Recommended shape" and "Implemented, 2026-09-04". - **`UiRenderNode::new` drops its `limits: UiLimits` parameter, and `UiLimits` is gone.** Before: `UiRenderNode::new(&device, &queue, &config, UiLimits::default())`. After: `UiRenderNode::new(&device, &queue, &config)`. Nothing replaces it — there are no more binding-array limits to size. - **`src/default/render.rs`'s device request asks for no features and no binding-array limits.** Before: `required_features: Features::TEXTURE_BINDING_ARRAY | Features::PARTIALLY_BOUND_BINDING_ARRAY | Features::SAMPLED_TEXTURE_AND_STORAGE_BUFFER_ARRAY_NON_UNIFORM_INDEXING` plus two `max_binding_array_*` limits. After: `Features::empty()` (the `DeviceDescriptor` default) and only `max_buffer_size` set, which was never about the binding array. - **`TextureHandle` has no `primitive()` method any more**; a caller outside `iris` shouldn't have been calling it (it fed the old renderer's internals), but if something did: use `image_index()` for a standalone image's bind-group index. There is no equivalent for a page — a page has no bind group of its own now, see below. - **`GlyphPrimitive` has no public constructor from a struct literal.** Before: `GlyphPrimitive { uv_min, uv_max, view_idx, sampler_idx, color, flags }`. After: `GlyphPrimitive::new(uv_min, uv_max, layer, color, flags)` — one `layer` (the shared atlas array's layer) instead of a `view_idx`/`sampler_idx` pair, since a page is now a layer of one array texture rather than its own bound texture. - **A widget author drawing images is unaffected**: `Painter::texture`/ `texture_at`/`texture_within` and `Textures::add` keep their signatures. What changed underneath is that each standalone image now gets its own `wgpu::BindGroup` and draw call instead of a slot in the shared array — invisible from the widget API, visible only in `UiRenderNode`'s internals and in `iris`'s device requirements.