Make a texture a registered primitive like any other

`write_texture` differed from `write` by one argument, which is what the
generic parameter was already for, so textures register as a primitive
with a `TexturePrimitive` holding the slot. `write_texture`,
`InstanceKind` and the layer's separate texture list are gone;
`DrawLayers` is back to `write` and `free`, with the kind carried in
`PrimitiveInst` as it carries everything else.

What differs between a texture and a rect is only what it samples, so
that is what registration says: `PrimitiveTexture::Atlas` binds the
shared atlas once for the layer, `PerInstance` binds the texture its own
data names and draws one instance at a time. One loop over a layer's
lists, one match on that.

`Pod` is back to being a supertrait of `Primitive` rather than the bound
itself. The guarantee is that a `PrimitiveKind<P>` is only minted by
`register::<P>` and `write` takes the kind and the value together, so a
primitive always has a list of its own to go in and the write does not
check anything: a list takes its stride from the type it was made for
instead of inferring it from the first write and asserting on the rest.

Also from reviewing this: a layer's lists and their buffers are created
only when that layer draws that primitive, so a primitive nobody uses no
longer costs two buffers in every layer -- which matters more now the set
is open-ended. `ListBuffers::update` takes the two things it uses rather
than the whole pipeline.

Verified again over all five cases: an image alone in a layer, three
images added and one deleted, the masked text-edit tab, the text-layout
tab and the default tab.
This commit is contained in:
iris committed 2026-09-13 14:46:08 -04:00
1 parent 89491a5949
commit 7b318e3271
5 files changed
+216 -194

No files matched your search

+29 -15
View File
@@ -1,9 +1,10 @@
use bytemuck::Pod;
use crate::{
Axis, Len, RenderedText, Size, SizeCtx, StrongWidget, TextAttrs, TextBuffer, TextData,
TextureHandle, UiRegion, UiRenderState, UiRsc, UiScalar, UiVec2, Widget, WidgetId,
render::{GLYPH, GlyphPrimitive, Mask, MaskIdx, PrimitiveHandle, PrimitiveKind},
render::{
GLYPH, GlyphPrimitive, Mask, MaskIdx, Primitive, PrimitiveHandle, PrimitiveInst,
PrimitiveKind, TEXTURE, TexturePrimitive,
},
util::Vec2,
};
@@ -22,11 +23,22 @@ pub struct Painter<'a> {
}
impl<'a> Painter<'a> {
fn primitive_at<P: Pod>(&mut self, kind: PrimitiveKind<P>, primitive: P, region: UiRegion) {
let h = self
.state
.layers
.write(self.layer, kind, self.id, primitive, region, self.mask);
fn primitive_at<P: Primitive>(
&mut self,
kind: PrimitiveKind<P>,
primitive: P,
region: UiRegion,
) {
let h = self.state.layers.write(
self.layer,
PrimitiveInst {
kind,
id: self.id,
primitive,
region,
mask_idx: self.mask,
},
);
self.push_primitive(h);
}
@@ -39,11 +51,11 @@ impl<'a> Painter<'a> {
}
/// Writes a primitive to be rendered
pub fn primitive<P: Pod>(&mut self, kind: PrimitiveKind<P>, primitive: P) {
pub fn primitive<P: Primitive>(&mut self, kind: PrimitiveKind<P>, primitive: P) {
self.primitive_at(kind, primitive, self.region)
}
pub fn primitive_within<P: Pod>(
pub fn primitive_within<P: Primitive>(
&mut self,
kind: PrimitiveKind<P>,
primitive: P,
@@ -91,11 +103,13 @@ impl<'a> Painter<'a> {
pub fn texture_at(&mut self, handle: &TextureHandle, region: UiRegion) {
self.textures.push(handle.clone());
let h =
self.state
.layers
.write_texture(self.layer, self.id, handle.slot(), region, self.mask);
self.push_primitive(h);
self.primitive_at(
TEXTURE,
TexturePrimitive {
slot: handle.slot(),
},
region,
);
}
pub fn render_text(