Draw textures separately, and keep them out of Primitives
Interleaving textures with primitives was solving a problem that does not exist: within a layer, order is already undefined because freeing an instance swap-removes it, and layering is what layers are for. So the run batching is gone. A layer is now `LayerDraws`: a `Primitives` and a texture `InstanceList` side by side, with `updated` covering both. `Primitives` holds only primitives again -- its instance list plus the group-1 data those instances read -- and `InstanceList` is the shared push/free/apply_free the two lists have in common rather than a second copy of it. `PrimitiveHandle` names which list with `InstanceKind`, and `PrimitiveChange` carries the same, since the two index independently. The handle no longer carries a group-1 index at all: a primitive instance already records where its entry is. The renderer gives each layer a second instance buffer and draws its textures one at a time after the instanced draw, each binding its own group 2. Review fixes alongside: `GlyphAtlas::allocate` returns the `PageUpload` it reserved instead of a bare tuple; a page or image region uploads through a new `write_region`, which passes the row stride to `write_texture` rather than copying the rectangle out first. Verified by replaying taps into the `tabs` example: three images added and one deleted leaves two drawn with two live texture slots, and the masked text-edit tab still clips, with the images freed on tab switch.
This commit is contained in:
1 parent
f5864da3c4
commit
b3d3da5dab
10 files changed
+282
-241
No files matched your search
+13
-30
@@ -1,18 +1,17 @@
|
||||
use image::EncodableLayout;
|
||||
use wgpu::*;
|
||||
|
||||
use crate::GlyphAtlas;
|
||||
|
||||
use super::{
|
||||
atlas::PAGE,
|
||||
texture::{array_view, texture_group},
|
||||
texture::{array_view, texture_group, write_region},
|
||||
};
|
||||
|
||||
/// The glyph atlas on the GPU: one array texture whose layers are the pages
|
||||
/// `GlyphAtlas` packs.
|
||||
///
|
||||
/// An array rather than a `binding_array<texture_2d<f32>>` because a layer
|
||||
/// index is ordinary Vulkan 1.0 / GLES sampling, while a binding array needs
|
||||
/// One array rather than a texture per page because a layer index is ordinary
|
||||
/// Vulkan 1.0 / GLES sampling, where a `binding_array` would need
|
||||
/// `VK_EXT_descriptor_indexing`, which a real share of Android GPUs lack.
|
||||
pub struct GpuPages {
|
||||
device: Device,
|
||||
@@ -43,33 +42,17 @@ impl GpuPages {
|
||||
self.grow(atlas.page_count(), layout, sampler);
|
||||
}
|
||||
for (upload, page) in atlas.uploads() {
|
||||
let rect = upload.rect;
|
||||
// `write_texture` wants tightly packed rows; the page is wider.
|
||||
let sub =
|
||||
image::imageops::crop_imm(page, rect.x, rect.y, rect.width, rect.height).to_image();
|
||||
self.queue.write_texture(
|
||||
TexelCopyTextureInfo {
|
||||
texture: &self.texture,
|
||||
mip_level: 0,
|
||||
origin: Origin3d {
|
||||
x: rect.x,
|
||||
y: rect.y,
|
||||
z: upload.layer,
|
||||
},
|
||||
aspect: TextureAspect::All,
|
||||
let dst = TexelCopyTextureInfo {
|
||||
texture: &self.texture,
|
||||
mip_level: 0,
|
||||
origin: Origin3d {
|
||||
x: upload.rect.x,
|
||||
y: upload.rect.y,
|
||||
z: upload.layer,
|
||||
},
|
||||
sub.as_bytes(),
|
||||
TexelCopyBufferLayout {
|
||||
offset: 0,
|
||||
bytes_per_row: Some(rect.width * 4),
|
||||
rows_per_image: Some(rect.height),
|
||||
},
|
||||
Extent3d {
|
||||
width: rect.width,
|
||||
height: rect.height,
|
||||
depth_or_array_layers: 1,
|
||||
},
|
||||
);
|
||||
aspect: TextureAspect::All,
|
||||
};
|
||||
write_region(&self.queue, dst, page, upload.rect);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user