308 lines
12 KiB
Rust
308 lines
12 KiB
Rust
//! GPU data structures for terminal rendering.
|
|
//!
|
|
//! Contains vertex formats, uniform structures, and constants for wgpu rendering.
|
|
//! All structures use `#[repr(C)]` and implement `bytemuck::Pod` for GPU compatibility.
|
|
|
|
use bytemuck::{Pod, Zeroable};
|
|
use std::sync::atomic::{AtomicU64, Ordering};
|
|
|
|
/// Unique identifier for a pane.
|
|
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
|
pub struct PaneId(pub u64);
|
|
|
|
impl PaneId {
|
|
/// Generate a new unique pane ID.
|
|
pub fn new() -> Self {
|
|
static COUNTER: std::sync::atomic::AtomicU64 =
|
|
std::sync::atomic::AtomicU64::new(0);
|
|
Self(COUNTER.fetch_add(1, std::sync::atomic::Ordering::SeqCst))
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
// CONSTANTS
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
|
|
/// Size of the glyph atlas texture (like Kitty's max_texture_size).
|
|
/// 8192x8192 provides massive capacity before needing additional layers.
|
|
pub const ATLAS_SIZE: u32 = 8192;
|
|
|
|
/// Maximum number of atlas layers (like Kitty's max_array_len).
|
|
/// With 8192x8192 per layer, this provides virtually unlimited glyph storage.
|
|
pub const MAX_ATLAS_LAYERS: u32 = 64;
|
|
|
|
/// Bytes per pixel in the RGBA atlas (4 for RGBA8).
|
|
pub const ATLAS_BPP: u32 = 4;
|
|
|
|
/// Maximum number of simultaneous edge glows.
|
|
pub const MAX_EDGE_GLOWS: usize = 16;
|
|
|
|
/// Color type constants for packed color encoding.
|
|
pub const COLOR_TYPE_DEFAULT: u32 = 0;
|
|
pub const COLOR_TYPE_INDEXED: u32 = 1;
|
|
pub const COLOR_TYPE_RGB: u32 = 2;
|
|
|
|
/// Attribute bit flags.
|
|
pub const ATTR_BOLD: u32 = 0x8;
|
|
pub const ATTR_ITALIC: u32 = 0x10;
|
|
pub const ATTR_REVERSE: u32 = 0x20;
|
|
pub const ATTR_STRIKE: u32 = 0x40;
|
|
pub const ATTR_DIM: u32 = 0x80;
|
|
pub const ATTR_UNDERLINE: u32 = 0x1; // Part of decoration mask
|
|
pub const ATTR_SELECTED: u32 = 0x100; // Cell is selected (for selection highlighting)
|
|
|
|
/// Flag for colored glyphs (emoji).
|
|
pub const COLORED_GLYPH_FLAG: u32 = 0x80000000;
|
|
|
|
/// Pre-rendered cursor sprite indices (like Kitty's cursor_shape_map).
|
|
/// These sprites are created at fixed indices in the sprite array after initialization.
|
|
/// Index 0 is reserved for "no glyph" (empty cell).
|
|
pub const CURSOR_SPRITE_BEAM: u32 = 1; // Bar/beam cursor (vertical line on left)
|
|
pub const CURSOR_SPRITE_UNDERLINE: u32 = 2; // Underline cursor (horizontal line at bottom)
|
|
pub const CURSOR_SPRITE_HOLLOW: u32 = 3; // Hollow/unfocused cursor (outline rectangle)
|
|
|
|
/// Pre-rendered decoration sprite indices (like Kitty's decoration sprites).
|
|
/// These are created after cursor sprites and used for text decorations.
|
|
/// The shader uses these to render underlines, strikethrough, etc.
|
|
pub const DECORATION_SPRITE_STRIKETHROUGH: u32 = 4; // Strikethrough line
|
|
pub const DECORATION_SPRITE_UNDERLINE: u32 = 5; // Single underline
|
|
pub const DECORATION_SPRITE_DOUBLE_UNDERLINE: u32 = 6; // Double underline
|
|
pub const DECORATION_SPRITE_UNDERCURL: u32 = 7; // Wavy/curly underline
|
|
pub const DECORATION_SPRITE_DOTTED: u32 = 8; // Dotted underline
|
|
pub const DECORATION_SPRITE_DASHED: u32 = 9; // Dashed underline
|
|
|
|
/// First available sprite index for regular glyphs (after reserved cursor and decoration sprites)
|
|
pub const FIRST_GLYPH_SPRITE: u32 = 10;
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
// VERTEX STRUCTURES
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
|
|
/// Vertex for rendering textured quads.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
pub struct GlyphVertex {
|
|
pub position: [f32; 2],
|
|
pub uv: [f32; 2],
|
|
pub color: [f32; 4],
|
|
pub bg_color: [f32; 4],
|
|
}
|
|
|
|
impl GlyphVertex {
|
|
pub const ATTRIBS: [wgpu::VertexAttribute; 4] = wgpu::vertex_attr_array![
|
|
0 => Float32x2, // position
|
|
1 => Float32x2, // uv
|
|
2 => Float32x4, // color (fg)
|
|
3 => Float32x4, // bg_color
|
|
];
|
|
|
|
pub fn desc() -> wgpu::VertexBufferLayout<'static> {
|
|
wgpu::VertexBufferLayout {
|
|
array_stride: std::mem::size_of::<GlyphVertex>()
|
|
as wgpu::BufferAddress,
|
|
step_mode: wgpu::VertexStepMode::Vertex,
|
|
attributes: &Self::ATTRIBS,
|
|
}
|
|
}
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
// EDGE GLOW STRUCTURES
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
|
|
/// Per-glow instance data (48 bytes, aligned to 16 bytes).
|
|
/// Must match GlowInstance in shader.wgsl exactly.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
pub struct GlowInstance {
|
|
pub direction: u32,
|
|
pub progress: f32,
|
|
pub color_r: f32,
|
|
pub color_g: f32,
|
|
pub color_b: f32,
|
|
// Pane bounds in pixels
|
|
pub pane_x: f32,
|
|
pub pane_y: f32,
|
|
pub pane_width: f32,
|
|
pub pane_height: f32,
|
|
pub _padding1: f32,
|
|
pub _padding2: f32,
|
|
pub _padding3: f32,
|
|
}
|
|
|
|
/// GPU-compatible edge glow uniform data.
|
|
/// Must match the layout in shader.wgsl exactly.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
pub struct EdgeGlowUniforms {
|
|
pub screen_width: f32,
|
|
pub screen_height: f32,
|
|
pub terminal_y_offset: f32,
|
|
pub glow_intensity: f32,
|
|
pub glow_count: u32,
|
|
pub _padding: [u32; 3], // Pad to 16-byte alignment before array
|
|
pub glows: [GlowInstance; MAX_EDGE_GLOWS],
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
// IMAGE STRUCTURES
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
|
|
/// GPU-compatible image uniform data.
|
|
/// Must match the layout in image_shader.wgsl exactly.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
pub struct ImageUniforms {
|
|
pub screen_width: f32,
|
|
pub screen_height: f32,
|
|
pub pos_x: f32,
|
|
pub pos_y: f32,
|
|
pub display_width: f32,
|
|
pub display_height: f32,
|
|
pub src_x: f32,
|
|
pub src_y: f32,
|
|
pub src_width: f32,
|
|
pub src_height: f32,
|
|
pub dim_factor: f32,
|
|
pub _padding1: f32,
|
|
}
|
|
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
// INSTANCED CELL RENDERING STRUCTURES
|
|
// ═══════════════════════════════════════════════════════════════════════════════
|
|
|
|
/// GPU cell data for instanced rendering.
|
|
/// Matches GPUCell in glyph_shader.wgsl exactly.
|
|
///
|
|
/// Like Kitty, we store a sprite_idx that references pre-rendered glyphs in the atlas.
|
|
/// This allows us to update GPU buffers with a simple memcpy when content changes,
|
|
/// rather than rebuilding vertex buffers every frame.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
|
pub struct GPUCell {
|
|
/// Foreground color (packed: type in low byte, then RGB or index)
|
|
pub fg: u32,
|
|
/// Background color (packed: type in low byte, then RGB or index)
|
|
pub bg: u32,
|
|
/// Decoration foreground color (for underlines, etc.)
|
|
pub decoration_fg: u32,
|
|
/// Sprite index in the sprite info array. High bit set = colored glyph.
|
|
/// 0 = no glyph (space or empty)
|
|
pub sprite_idx: u32,
|
|
/// Cell attributes (bold, italic, reverse, etc.)
|
|
pub attrs: u32,
|
|
}
|
|
|
|
/// Sprite info for glyph positioning.
|
|
/// Matches SpriteInfo in glyph_shader.wgsl exactly.
|
|
///
|
|
/// In Kitty's model, sprites are always cell-sized and glyphs are pre-positioned
|
|
/// within the sprite at the correct baseline. The shader just maps the sprite
|
|
/// to the cell 1:1, with no offset math needed.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
|
pub struct SpriteInfo {
|
|
/// UV coordinates in atlas (x, y, width, height) - normalized 0-1
|
|
pub uv: [f32; 4],
|
|
/// Atlas layer index (z-coordinate for texture array) and padding
|
|
/// layer is the first f32, second f32 is unused padding
|
|
pub layer: f32,
|
|
pub _padding: f32,
|
|
/// Size in pixels (width, height) - always matches cell dimensions
|
|
pub size: [f32; 2],
|
|
}
|
|
|
|
/// Font cell metrics with integer dimensions (like Kitty's FontCellMetrics).
|
|
/// Using integers ensures pixel-perfect alignment and avoids floating-point precision issues.
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub struct FontCellMetrics {
|
|
/// Cell width in pixels (computed using ceil from font advance).
|
|
pub cell_width: u32,
|
|
/// Cell height in pixels (computed using ceil from font height).
|
|
pub cell_height: u32,
|
|
/// Baseline offset from top of cell in pixels.
|
|
pub baseline: u32,
|
|
/// Y position for underline (from top of cell, in pixels).
|
|
/// Computed from font metrics: ascender - underline_position.
|
|
pub underline_position: u32,
|
|
/// Thickness of underline in pixels.
|
|
pub underline_thickness: u32,
|
|
/// Y position for strikethrough (from top of cell, in pixels).
|
|
/// Typically around 65% of baseline from top.
|
|
pub strikethrough_position: u32,
|
|
/// Thickness of strikethrough in pixels.
|
|
pub strikethrough_thickness: u32,
|
|
}
|
|
|
|
/// Grid parameters uniform for instanced rendering.
|
|
/// Matches GridParams in glyph_shader.wgsl exactly.
|
|
/// Uses Kitty-style NDC positioning: viewport is set per-pane, so shader
|
|
/// works in pure NDC space without needing pixel offsets.
|
|
/// Cell dimensions are integers like Kitty for pixel-perfect rendering.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Pod, Zeroable)]
|
|
pub struct GridParams {
|
|
pub cols: u32,
|
|
pub rows: u32,
|
|
pub cell_width: u32,
|
|
pub cell_height: u32,
|
|
pub cursor_col: i32,
|
|
pub cursor_row: i32,
|
|
pub cursor_style: u32,
|
|
pub background_opacity: f32,
|
|
// Selection range (-1 values mean no selection)
|
|
pub selection_start_col: i32,
|
|
pub selection_start_row: i32,
|
|
pub selection_end_col: i32,
|
|
pub selection_end_row: i32,
|
|
pub selection_row_max_col: [i32; 256],
|
|
}
|
|
|
|
/// GPU quad instance for instanced rectangle rendering.
|
|
/// Matches Quad in glyph_shader.wgsl exactly.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
|
pub struct Quad {
|
|
/// X position in pixels
|
|
pub x: f32,
|
|
/// Y position in pixels
|
|
pub y: f32,
|
|
/// Width in pixels
|
|
pub width: f32,
|
|
/// Height in pixels
|
|
pub height: f32,
|
|
/// Color (linear RGBA)
|
|
pub color: [f32; 4],
|
|
}
|
|
|
|
/// Parameters for quad rendering.
|
|
/// Matches QuadParams in glyph_shader.wgsl exactly.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
|
pub struct QuadParams {
|
|
pub screen_width: f32,
|
|
pub screen_height: f32,
|
|
pub _padding: [f32; 2],
|
|
}
|
|
|
|
/// Parameters for statusline rendering.
|
|
/// Matches StatuslineParams in statusline_shader.wgsl exactly.
|
|
#[repr(C)]
|
|
#[derive(Copy, Clone, Debug, Default, Pod, Zeroable)]
|
|
pub struct StatuslineParams {
|
|
/// Number of characters in statusline
|
|
pub char_count: u32,
|
|
/// Cell width in pixels
|
|
pub cell_width: f32,
|
|
/// Cell height in pixels
|
|
pub cell_height: f32,
|
|
/// Screen width in pixels
|
|
pub screen_width: f32,
|
|
/// Screen height in pixels
|
|
pub screen_height: f32,
|
|
/// Y offset from top of screen in pixels
|
|
pub y_offset: f32,
|
|
/// Padding for alignment (to match shader struct layout)
|
|
pub _padding: [f32; 2],
|
|
}
|