Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion crates/buiy_core/src/render/atlas/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ mod atlas;
pub use atlas::BuiyAtlas;

mod primitive;
pub use primitive::{GLYPH_ALPHA_INSTANCE_STRIDE_BYTES, GlyphAlphaInstance, IconInstance};
pub use primitive::{
GLYPH_ALPHA_FLOAT_OFFSET, GLYPH_ALPHA_INSTANCE_STRIDE_BYTES, GlyphAlphaInstance, IconInstance,
};

mod warmup;
pub use warmup::{AtlasWarmupQueue, AtlasWarmupRequest};
Expand Down
24 changes: 24 additions & 0 deletions crates/buiy_core/src/render/atlas/primitive.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,30 @@ use bytemuck::{Pod, Zeroable};
/// `coverage.wgsl`'s instance `@location`s read. `[f32;4]×4 + u32 = 68`.
pub const GLYPH_ALPHA_INSTANCE_STRIDE_BYTES: usize = 68;

/// Float index of the per-glyph straight-alpha (`color[3]`) when a
/// [`GlyphAlphaInstance`] is viewed as a flat `[f32]` raw record. The fields
/// pack `rect[4] ++ uv[4] ++ color[4] ++ clip[4] ++ page` (contiguous `#[repr(C)]`,
/// no pad before `page`), so `color` is the **3rd** `[f32;4]` block and its
/// alpha lands at float index `8 + 3 = 11`. This is the GLYPH mirror of the
/// quad-tier `ALPHA_FLOAT_OFFSET` (= 7, a DIFFERENT offset on the `[f32;17]`
/// quad record): R2's degraded-group forward-composite re-tints glyph alpha,
/// and using the quad offset 7 on a glyph record would corrupt `uv[3]` (a
/// silent wrong-pixel bug). NAMED + compile-asserted so the offset is never a
/// literal `11` at the use site (R1's discipline). The fold itself writes the
/// typed `color[3]` field; this const documents the raw-view parity for the
/// spec and any byte-level reader.
///
/// [`ALPHA_FLOAT_OFFSET`]: crate::render::instance::ALPHA_FLOAT_OFFSET
pub const GLYPH_ALPHA_FLOAT_OFFSET: usize = 11;

// Tie `GLYPH_ALPHA_FLOAT_OFFSET` to the layout: `color` is the 3rd `[f32;4]`
// block (`rect`, `uv`, `color`), so its alpha (`color[3]`) is at float index
// `8 + 3`. A field reorder that moved `color` would fail this.
const _: () = assert!(
GLYPH_ALPHA_FLOAT_OFFSET == 8 + 3,
"GLYPH_ALPHA_FLOAT_OFFSET must index color[3] = the 3rd vec4 block's alpha"
);

/// One instance per visible glyph (or any single-channel coverage quad, e.g.
/// a generated mask stamp). The **alpha-as-color** primitive: the atlas
/// stores `R8` coverage and color is applied per-instance, so one resident
Expand Down
35 changes: 25 additions & 10 deletions crates/buiy_core/src/render/buckets.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,13 @@ impl Ord for PrimitiveBatchKey {
/// [`PackedInstance`].
#[derive(Default)]
pub struct InstanceBuckets {
batches: BTreeMap<PrimitiveBatchKey, Vec<[f32; 13]>>,
batches: BTreeMap<PrimitiveBatchKey, Vec<[f32; 17]>>,
}

impl InstanceBuckets {
/// Push one packed instance (as raw `[f32; 13]` =
/// pos2+size2+color4+radius1+clip_min2+clip_max2) into its batch.
pub fn push(&mut self, key: PrimitiveBatchKey, instance: [f32; 13]) {
/// Push one packed instance (as raw `[f32; 17]` =
/// pos2+size2+color4+radius1+clip_min2+clip_max2+affine4) into its batch.
pub fn push(&mut self, key: PrimitiveBatchKey, instance: [f32; 17]) {
self.batches.entry(key).or_default().push(instance);
}

Expand All @@ -110,20 +110,30 @@ impl InstanceBuckets {
}

/// Iterate batches in draw order (`(layer, primitive paint order)`).
pub fn batches(&self) -> impl Iterator<Item = (&PrimitiveBatchKey, &Vec<[f32; 13]>)> {
pub fn batches(&self) -> impl Iterator<Item = (&PrimitiveBatchKey, &Vec<[f32; 17]>)> {
self.batches.iter()
}
}

/// Flatten a [`PackedInstance`] into the raw `[f32; 13]` the bucket store holds.
/// Flatten a [`PackedInstance`] into the raw `[f32; 17]` the bucket store holds.
/// Keeps the bucket store decoupled from the concrete instance struct while
/// the stride is asserted equal in tests.
pub fn packed_to_raw(p: &PackedInstance) -> [f32; 13] {
///
/// LAYOUT INVARIANT (R1 / R2 dependency): indices `0..13` are byte-identical to
/// the pre-R1 layout — color is at [`COLOR_FLOAT_OFFSET`]`..+4` and alpha at
/// [`ALPHA_FLOAT_OFFSET`] (R2's degraded-group re-tint reads alpha there). The
/// 2D affine basis appends at `[13..17]` (`[m00, m10, m01, m11]`); identity
/// `[1, 0, 0, 1]` paints axis-aligned.
///
/// [`COLOR_FLOAT_OFFSET`]: crate::render::instance::COLOR_FLOAT_OFFSET
/// [`ALPHA_FLOAT_OFFSET`]: crate::render::instance::ALPHA_FLOAT_OFFSET
pub fn packed_to_raw(p: &PackedInstance) -> [f32; 17] {
[
p.rect_pos[0],
p.rect_pos[1],
p.rect_size[0],
p.rect_size[1],
// color@COLOR_FLOAT_OFFSET (4..8); alpha@ALPHA_FLOAT_OFFSET (7).
p.color[0],
p.color[1],
p.color[2],
Expand All @@ -133,6 +143,11 @@ pub fn packed_to_raw(p: &PackedInstance) -> [f32; 13] {
p.clip_min[1],
p.clip_max[0],
p.clip_max[1],
// The 2D affine basis APPENDED after index 13 (offsets 0..13 unchanged).
p.affine[0],
p.affine[1],
p.affine[2],
p.affine[3],
]
}

Expand Down Expand Up @@ -197,7 +212,7 @@ pub fn pack_view(nodes: &[ExtractedNode]) -> InstanceBuckets {
pub struct PackedPartition {
/// The full flat quad blob (every instance, in paint order) — identical to
/// `pack_view`'s single `(Quad, 0)` batch flattened.
pub instances: Vec<[f32; 13]>,
pub instances: Vec<[f32; 17]>,
/// `group_ranges[g]` = the `[start, end)` instance range of group `g`'s
/// members (empty range if the group has no opaque member).
pub group_ranges: Vec<std::ops::Range<u32>>,
Expand Down Expand Up @@ -276,7 +291,7 @@ pub fn pack_view_partitioned(
/// per-group contiguous ranges (with the contiguity tripwire) and the
/// complement flat runs.
struct Partitioner {
instances: Vec<[f32; 13]>,
instances: Vec<[f32; 17]>,
ranges: RangePartitioner,
}

Expand All @@ -290,7 +305,7 @@ impl Partitioner {

/// Append one instance under group `g` (already bounds-filtered by the
/// caller), extending or starting the group/flat run it belongs to.
fn push(&mut self, instance: [f32; 13], g: Option<usize>) {
fn push(&mut self, instance: [f32; 17], g: Option<usize>) {
self.instances.push(instance);
self.ranges.push(g);
}
Expand Down
Loading
Loading