Draw the glyph atlas as an array texture and images with their own bind groups
The renderer bound every texture through one `binding_array<texture_2d<f32>>` indexed per primitive. That needs `VK_EXT_descriptor_indexing`, which a real share of Android GPUs do not have, so the shape did not run there at all. Split the two things being bound, since they want opposite treatment: - Glyph atlas pages become layers of one `texture_2d_array`. A glyph primitive carries a layer rather than a view/sampler index pair, and a layer index is an ordinary sampling operand -- no extension. Growing the atlas recreates the array with headroom and copies the old layers across GPU-side. - 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` at all: the bind group has already picked the texture. `Primitives` therefore keeps images in a list of their own, with `PrimitiveChange::is_image` saying which list a renumbering belongs to -- the two have independent index spaces, so `(layer, inst_idx)` alone would collide between them. Verified on this machine's real GPU (Venus onto an RX 7900 XT, confirmed by the loaded ICD rather than assumed): the `tabs` example renders byte-identical screenshots before and after, both for a text-and-rect tab and for one holding a standalone image.
This commit is contained in:
1 parent
0f6a28b4dd
commit
bafaa1db6d
10 files changed
+794
-255
No files matched your search
+24
-11
@@ -77,17 +77,31 @@ impl<'a> Painter<'a> {
|
||||
|
||||
pub fn texture_within(&mut self, handle: &TextureHandle, region: UiRegion) {
|
||||
self.textures.push(handle.clone());
|
||||
self.primitive_at(handle.primitive(), region.within(&self.region));
|
||||
self.write_image(handle.image_index(), region.within(&self.region));
|
||||
}
|
||||
|
||||
pub fn texture(&mut self, handle: &TextureHandle) {
|
||||
self.textures.push(handle.clone());
|
||||
self.primitive(handle.primitive());
|
||||
self.write_image(handle.image_index(), self.region);
|
||||
}
|
||||
|
||||
pub fn texture_at(&mut self, handle: &TextureHandle, region: UiRegion) {
|
||||
self.textures.push(handle.clone());
|
||||
self.primitive_at(handle.primitive(), region);
|
||||
self.write_image(handle.image_index(), region);
|
||||
}
|
||||
|
||||
/// A standalone image draws with its own bind group rather than sharing
|
||||
/// the layer's one instanced draw, so it goes through
|
||||
/// `Primitives::write_image` instead of `primitive_at`/`Primitive::vec`.
|
||||
fn write_image(&mut self, texture_idx: u32, region: UiRegion) {
|
||||
let h = self
|
||||
.state
|
||||
.layers
|
||||
.write_image(self.layer, self.id, texture_idx, region, self.mask);
|
||||
if self.mask != MaskIdx::NONE {
|
||||
self.rsc.ui_mut().masks.push_ref(self.mask);
|
||||
}
|
||||
self.primitives.push(h);
|
||||
}
|
||||
|
||||
pub fn render_text(
|
||||
@@ -109,14 +123,13 @@ impl<'a> Painter<'a> {
|
||||
region.x.end = region.x.start + UiScalar::abs(glyph.entry.width as f32);
|
||||
region.y.end = region.y.start + UiScalar::abs(glyph.entry.height as f32);
|
||||
self.primitive_at(
|
||||
GlyphPrimitive {
|
||||
uv_min: glyph.entry.uv_min,
|
||||
uv_max: glyph.entry.uv_max,
|
||||
view_idx: glyph.entry.view_idx,
|
||||
sampler_idx: glyph.entry.sampler_idx,
|
||||
color: text.color,
|
||||
flags: glyph.entry.flags(),
|
||||
},
|
||||
GlyphPrimitive::new(
|
||||
glyph.entry.uv_min,
|
||||
glyph.entry.uv_max,
|
||||
glyph.entry.layer,
|
||||
text.color,
|
||||
glyph.entry.flags(),
|
||||
),
|
||||
region,
|
||||
);
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user