mirror of
https://github.com/storytold/deckcraft.git
synced 2026-11-10 20:39:36 -06:00
Compare commits
2
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
af08436f98 | ||
|
|
17f9f40ede |
@@ -777,14 +777,6 @@ fn decode_frame(job: &FrameJob, pool: &Pool, stats: &mut DecodeStats) -> Result<
|
|||||||
Ok((rf, pic))
|
Ok((rf, pic))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bytes all parallel tile states may hold of whole-frame CDEF and restoration metadata; past it
|
|
||||||
/// the tiles decode one after another on the frame's own metadata.
|
|
||||||
const TILE_METADATA_BUDGET: usize = 256 << 20;
|
|
||||||
|
|
||||||
fn tile_metadata_fits(tiles: usize, per_tile: usize) -> bool {
|
|
||||||
tiles.checked_mul(per_tile).is_some_and(|n| n <= TILE_METADATA_BUDGET)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Decode the tiles of a frame (tile number, data), in parallel when several; returns the final
|
/// Decode the tiles of a frame (tile number, data), in parallel when several; returns the final
|
||||||
/// CDFs of tile context_update_tile_id.
|
/// CDFs of tile context_update_tile_id.
|
||||||
fn decode_tiles(pool: &Pool, fs: &mut FrameState, cdfs: &Cdfs, tiles: &[(usize, Vec<u8>)]) -> Result<Option<Box<Cdfs>>> {
|
fn decode_tiles(pool: &Pool, fs: &mut FrameState, cdfs: &Cdfs, tiles: &[(usize, Vec<u8>)]) -> Result<Option<Box<Cdfs>>> {
|
||||||
@@ -798,7 +790,7 @@ fn decode_tiles(pool: &Pool, fs: &mut FrameState, cdfs: &Cdfs, tiles: &[(usize,
|
|||||||
};
|
};
|
||||||
// Intra block copy reads the current frame through the tile's own buffer: keep whole-frame
|
// Intra block copy reads the current frame through the tile's own buffer: keep whole-frame
|
||||||
// buffers (tiles one after another) for it.
|
// buffers (tiles one after another) for it.
|
||||||
if tiles.len() > 1 && pool.is_parallel() && !fs.fh.allow_intrabc && tile_metadata_fits(tiles.len(), fs.tile_metadata_bytes()) {
|
if tiles.len() > 1 && pool.is_parallel() && !fs.fh.allow_intrabc {
|
||||||
let mut states: Vec<TileState> = tiles
|
let mut states: Vec<TileState> = tiles
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(num, _)| {
|
.map(|(num, _)| {
|
||||||
@@ -1083,14 +1075,6 @@ mod guard_tests {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod budget_tests {
|
mod budget_tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn tile_metadata_copies_are_budgeted() {
|
|
||||||
assert!(tile_metadata_fits(64, 1 << 20));
|
|
||||||
assert!(!tile_metadata_fits(4096, 1 << 20));
|
|
||||||
assert!(!tile_metadata_fits(usize::MAX, 2));
|
|
||||||
}
|
|
||||||
|
|
||||||
use deckcraft_bitstream::budget::DECODE_MEMORY_BUDGET;
|
use deckcraft_bitstream::budget::DECODE_MEMORY_BUDGET;
|
||||||
|
|
||||||
fn color(mono: bool) -> crate::header::ColorConfig {
|
fn color(mono: bool) -> crate::header::ColorConfig {
|
||||||
|
|||||||
@@ -253,13 +253,6 @@ impl FrameState {
|
|||||||
self.lr = t.lr;
|
self.lr = t.lr;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bytes of CDEF and loop-restoration metadata each parallel tile state copies whole.
|
|
||||||
pub fn tile_metadata_bytes(&self) -> usize {
|
|
||||||
let lr = &self.lr;
|
|
||||||
// 1 (type) + 6 (Wiener) + 1 (SGR set) + 2 (SGR weights) bytes per unit.
|
|
||||||
self.cdef.len() + lr.lr_type.iter().map(|v| v.len() * 10).sum::<usize>()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Private buffers for the tile covering mode info rows [r0, r1) x columns [c0, c1); tiles
|
/// Private buffers for the tile covering mode info rows [r0, r1) x columns [c0, c1); tiles
|
||||||
/// on the right / bottom frame edge also cover the allocation margins.
|
/// on the right / bottom frame edge also cover the allocation margins.
|
||||||
pub fn tile_state(&self, r0: usize, r1: usize, c0: usize, c1: usize) -> TileState {
|
pub fn tile_state(&self, r0: usize, r1: usize, c0: usize, c1: usize) -> TileState {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ use std::sync::Arc;
|
|||||||
|
|
||||||
use deckcraft_model::edit;
|
use deckcraft_model::edit;
|
||||||
use deckcraft_model::text::{Bullet, Paragraph, RunProps, Strike, TextBody};
|
use deckcraft_model::text::{Bullet, Paragraph, RunProps, Strike, TextBody};
|
||||||
use egui::text::{CCursor, Galley, LayoutJob, TextFormat};
|
use egui::text::{Galley, LayoutJob, TextFormat};
|
||||||
use egui::{Align2, Color32, Stroke, Ui, vec2};
|
use egui::{Align2, Color32, Stroke, Ui, vec2};
|
||||||
|
|
||||||
use crate::theme;
|
use crate::theme;
|
||||||
@@ -210,16 +210,30 @@ pub fn editor(
|
|||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The (min y, max y) of the row holding char index `at`; `walk` (row index, chars through that
|
||||||
|
/// row) carries over between calls, so successive non-decreasing `at`s cost one pass in all.
|
||||||
|
fn row_span_at(galley: &Galley, walk: &mut (usize, usize), at: usize) -> (f32, f32) {
|
||||||
|
while walk.0 + 1 < galley.rows.len() && (walk.1 < at || (walk.1 == at && galley.rows[walk.0].char_count_including_newline().0 > 0)) {
|
||||||
|
walk.0 += 1;
|
||||||
|
walk.1 += galley.rows[walk.0].char_count_including_newline().0;
|
||||||
|
}
|
||||||
|
galley.rows.get(walk.0).map_or((0.0, 0.0), |r| (r.min_y(), r.max_y()))
|
||||||
|
}
|
||||||
|
|
||||||
/// Bullets and numbers at the start of each paragraph's first line of `galley` (laid out from
|
/// Bullets and numbers at the start of each paragraph's first line of `galley` (laid out from
|
||||||
/// `body`), drawn at `origin`.
|
/// `body`), drawn at `origin`.
|
||||||
fn paint_bullets(painter: &egui::Painter, body: &TextBody, galley: &Galley, origin: egui::Pos2, size: f32, color: Color32) {
|
fn paint_bullets(painter: &egui::Painter, body: &TextBody, galley: &Galley, origin: egui::Pos2, size: f32, color: Color32) {
|
||||||
let k = size / 12.0;
|
let k = size / 12.0;
|
||||||
let mut at = 0usize;
|
let mut at = 0usize;
|
||||||
|
// Paragraph starts only grow, so one forward walk over the rows finds each start's row
|
||||||
|
// (`pos_from_cursor` would rescan from the top for every bullet).
|
||||||
|
let mut walk = (0usize, galley.rows.first().map_or(0, |r| r.char_count_including_newline().0));
|
||||||
for (p, bullet) in body.paragraphs.iter().zip(bullets(body)) {
|
for (p, bullet) in body.paragraphs.iter().zip(bullets(body)) {
|
||||||
if let Some(b) = bullet {
|
if let Some(b) = bullet {
|
||||||
let row = galley.pos_from_cursor(CCursor::new(at));
|
let (min_y, max_y) = row_span_at(galley, &mut walk, at);
|
||||||
let pos = origin + vec2(px(indents(p).0, k), row.center().y);
|
let (center_y, height) = ((min_y + max_y) / 2.0, max_y - min_y);
|
||||||
let font = theme::font(row.height().clamp(size * 0.75, size * 2.0) * 0.8);
|
let pos = origin + vec2(px(indents(p).0, k), center_y);
|
||||||
|
let font = theme::font(height.clamp(size * 0.75, size * 2.0) * 0.8);
|
||||||
painter.text(pos, Align2::LEFT_CENTER, b, font, color);
|
painter.text(pos, Align2::LEFT_CENTER, b, font, color);
|
||||||
}
|
}
|
||||||
at += p.char_len() + 1;
|
at += p.char_len() + 1;
|
||||||
@@ -241,6 +255,7 @@ mod tests {
|
|||||||
#![allow(clippy::unwrap_used, clippy::expect_used)]
|
#![allow(clippy::unwrap_used, clippy::expect_used)]
|
||||||
|
|
||||||
use deckcraft_model::text::{ParaProps, Run};
|
use deckcraft_model::text::{ParaProps, Run};
|
||||||
|
use egui::text::CCursor;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
@@ -317,6 +332,23 @@ mod tests {
|
|||||||
assert!(wrapped.iter().all(|r| (r.pos.x - 22.5).abs() < 1.0), "wrapped lines align with the text");
|
assert!(wrapped.iter().all(|r| (r.pos.x - 22.5).abs() < 1.0), "wrapped lines align with the text");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn row_walk_matches_cursor_lookup_at_paragraph_starts() {
|
||||||
|
let ctx = egui::Context::default();
|
||||||
|
let body = notes();
|
||||||
|
let mut laid = None;
|
||||||
|
let mut out = ctx.run_ui(Default::default(), |ui| laid = Some(galley(ui, &body, 12.0, Color32::BLACK, 300.0)));
|
||||||
|
out.textures_delta.clear();
|
||||||
|
let g = laid.unwrap();
|
||||||
|
let mut walk = (0usize, g.rows.first().map_or(0, |r| r.char_count_including_newline().0));
|
||||||
|
let mut at = 0usize;
|
||||||
|
for p in &body.paragraphs {
|
||||||
|
let want = g.pos_from_cursor(CCursor::new(at));
|
||||||
|
assert_eq!(row_span_at(&g, &mut walk, at), (want.min.y, want.max.y), "paragraph at char {at}");
|
||||||
|
at += p.char_len() + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn typing_keeps_the_formatting_around_it() {
|
fn typing_keeps_the_formatting_around_it() {
|
||||||
let mut d = Draft::new(¬es());
|
let mut d = Draft::new(¬es());
|
||||||
|
|||||||
Reference in New Issue
Block a user