Replaces the bindless `binding_array<texture_2d<f32>>` the renderer bound every texture through. That array needs `VK_EXT_descriptor_indexing`, which a real share of Android GPUs lack, so the old shape did not run there at all. The two things being bound want opposite treatment, so they are now split: - **Glyph atlas pages become layers of one `texture_2d_array`.** A glyph primitive carries a `layer` instead of a view/sampler index pair. A layer index is an ordinary sampling operand, so this needs nothing beyond plain Vulkan 1.0 / GLES. Growing the atlas recreates the array with headroom and `copy_texture_to_texture`s the old layers across, no readback. - **A standalone image gets its own texture and its own bind group,** and draws in its own call. It no longer needs a per-instance entry in `PrimitiveData`: the bind group has already picked the texture. `Primitives` keeps images in a list of their own as a result, with `PrimitiveChange::is_image` naming which list a renumbering belongs to -- the two have independent index spaces, so `(layer, inst_idx)` alone would collide between them. Two notes on judgement calls, since this slice was rebuilt on top of `main` rather than transplanted: - The source version renamed `GlyphEntry::is_colored` to `is_color` and added a second `IS_COLOR` flag constant beside the existing `GlyphEntry::IS_COLORED`. Both dropped: #10's naming and its `flags()` are kept, and UVs stay `Vec2` rather than going back to `[f32; 2]`. - `ImageGpu` no longer holds the `Texture` behind its view, which removes an `#[allow(dead_code)]`. A `TextureView` keeps its own reference to the texture, checked by rendering rather than assumed -- see below. ### Verification ``` cargo fmt --all --check cargo clippy --workspace --all-targets --locked -- -D warnings cargo test --workspace --locked ``` All clean; the 4 text-edit tests pass. The only clippy output is the pre-existing future-incompatibility notice about `naga`/`wgpu`/`winit`. Because this is a rendering change, it was also run for real rather than only compiled. The `tabs` example was rendered on this machine's GPU -- Venus onto an RX 7900 XT, confirmed from the loaded ICD (`libvulkan_virtio.so` on `/dev/dri/renderD128`) rather than assumed, since a failed Vulkan init here silently falls back to llvmpipe and would make the screenshots meaningless. Screenshots before and after the change are **byte-identical** (same md5) in two scenes: the default tab, which exercises text (the atlas path) and rects, and the image tab with a standalone image pushed at startup, which exercises the per-image bind group. The image-tab scene needed a temporary local edit to the example to push the image without a click; that edit is not part of this branch. The same comparison, re-run after dropping the `Texture` field, is still byte-identical -- which is the check that the view alone keeps it alive. --------- Co-authored-by: iris <2+iris@noreply.localhost> Reviewed-on: #11 Reviewed-by: iris <2+iris@noreply.localhost> Co-authored-by: AIris <4+iris-ai@noreply.localhost>
90 lines
2.3 KiB
Rust
90 lines
2.3 KiB
Rust
use crate::{
|
|
Axis, AxisT, IdLike, Len, RenderedText, Size, TextAttrs, TextBuffer, TextData, UiVec2,
|
|
WidgetAxisFns, WidgetId, Widgets, XAxis, YAxis, ui::cache::Cache, util::Vec2,
|
|
};
|
|
|
|
pub struct SizeCtx<'a> {
|
|
pub text: &'a mut TextData,
|
|
pub(super) source: WidgetId,
|
|
pub(super) widgets: &'a Widgets,
|
|
pub(super) cache: &'a mut Cache,
|
|
/// TODO: should this be pub? rn used for sized
|
|
pub outer: UiVec2,
|
|
pub(super) output_size: Vec2,
|
|
pub(super) id: WidgetId,
|
|
}
|
|
|
|
impl SizeCtx<'_> {
|
|
pub fn id(&self) -> &WidgetId {
|
|
&self.id
|
|
}
|
|
|
|
pub fn source(&self) -> &WidgetId {
|
|
&self.source
|
|
}
|
|
|
|
pub(super) fn len_inner<A: const AxisT>(&mut self, id: WidgetId) -> Len {
|
|
if let Some((_, len)) = self.cache.size.axis::<A>().get(&id) {
|
|
return *len;
|
|
}
|
|
let len = self
|
|
.widgets
|
|
.get_dyn_dynamic(id)
|
|
.desired_len::<A>(&mut SizeCtx {
|
|
text: self.text,
|
|
source: self.source,
|
|
widgets: self.widgets,
|
|
cache: self.cache,
|
|
outer: self.outer,
|
|
output_size: self.output_size,
|
|
id,
|
|
});
|
|
self.cache.size.axis::<A>().insert(id, (self.outer, len));
|
|
len
|
|
}
|
|
|
|
pub fn width(&mut self, id: impl IdLike) -> Len {
|
|
self.len_inner::<XAxis>(id.id())
|
|
}
|
|
|
|
pub fn height(&mut self, id: impl IdLike) -> Len {
|
|
self.len_inner::<YAxis>(id.id())
|
|
}
|
|
|
|
pub fn len_axis(&mut self, id: impl IdLike, axis: Axis) -> Len {
|
|
match axis {
|
|
Axis::X => self.width(id),
|
|
Axis::Y => self.height(id),
|
|
}
|
|
}
|
|
|
|
pub fn size(&mut self, id: impl IdLike) -> Size {
|
|
let id = id.id();
|
|
Size {
|
|
x: self.width(id),
|
|
y: self.height(id),
|
|
}
|
|
}
|
|
|
|
pub fn px_size(&mut self) -> Vec2 {
|
|
self.outer.to_abs(self.output_size)
|
|
}
|
|
|
|
pub fn output_size(&mut self) -> Vec2 {
|
|
self.output_size
|
|
}
|
|
|
|
pub fn draw_text(
|
|
&mut self,
|
|
buffer: &mut TextBuffer,
|
|
attrs: &TextAttrs,
|
|
width: Option<f32>,
|
|
) -> RenderedText {
|
|
self.text.render(buffer, attrs, width)
|
|
}
|
|
|
|
pub fn label(&self, id: WidgetId) -> &String {
|
|
self.widgets.label(id)
|
|
}
|
|
}
|