mirror of
https://github.com/penpot/penpot.git
synced 2026-08-05 12:29:00 +00:00
wip
This commit is contained in:
parent
bfef6ea089
commit
4ad31a2b8d
@ -42,6 +42,7 @@ pub use images::*;
|
||||
|
||||
type ClipStack = Vec<(Rect, Option<Corners>, Matrix)>;
|
||||
|
||||
#[cfg_attr(feature = "profile-macros", derive(Debug))]
|
||||
#[repr(u8)]
|
||||
pub enum FrameType {
|
||||
None = 0,
|
||||
@ -877,6 +878,7 @@ impl RenderState {
|
||||
/// on top of Target, then present. Backbuffer is left clean so it can be reused
|
||||
/// as-is across interactive-transform frames without stale overlay pixels.
|
||||
pub fn present_frame(&mut self, tree: ShapesPoolRef) {
|
||||
performance::begin_measure!("present_frame");
|
||||
// Viewer masked passes render a partial scene onto a transparent backbuffer.
|
||||
// SrcOver would keep pass-1 pixels wherever the backbuffer stays transparent.
|
||||
if self.viewer_masked_pass() {
|
||||
@ -892,7 +894,10 @@ impl RenderState {
|
||||
}
|
||||
ui::render(self, tree);
|
||||
debug::render_wasm_label(self);
|
||||
performance::begin_measure!("present_frame:flush_submit");
|
||||
self.surfaces.flush_and_submit(SurfaceId::Target);
|
||||
performance::end_measure!("present_frame:flush_submit");
|
||||
performance::end_measure!("present_frame");
|
||||
}
|
||||
|
||||
/// Renders only the canvas background and UI surface (rulers/frame), without
|
||||
@ -2346,11 +2351,37 @@ impl RenderState {
|
||||
self.render_shape_tree_partial(base_object, tree, timestamp, allow_stop)?;
|
||||
|
||||
if !self.options.is_interactive_transform() {
|
||||
performance::begin_measure!("atlas_to_backbuffer");
|
||||
self.surfaces.draw_tile_atlas_to_backbuffer(
|
||||
&self.viewbox,
|
||||
&self.tile_viewbox,
|
||||
self.background_color,
|
||||
);
|
||||
performance::end_measure!("atlas_to_backbuffer");
|
||||
}
|
||||
|
||||
#[cfg(feature = "profile-macros")]
|
||||
{
|
||||
let usage = get_gpu_state().context.resource_cache_usage();
|
||||
let limit_mb = get_gpu_state().context.resource_cache_limit() as f64 / 1_048_576.0;
|
||||
let mts = get_gpu_state().max_texture_size();
|
||||
let atlas_mb = (mts as f64 * mts as f64 * 4.0) / 1_048_576.0;
|
||||
let cdim = self.surfaces.cache_dimensions();
|
||||
let cache_mb = (cdim.width as f64 * cdim.height as f64 * 4.0) / 1_048_576.0;
|
||||
crate::console_log!(
|
||||
"[GPU] frame={:?} interactive={} fast={} rcache_mb={:.1} limit_mb={:.1} rcache_n={} cache={}x{} cache_mb={:.1} max_tex={} atlas_mb={:.1}",
|
||||
frame_type,
|
||||
self.options.is_interactive_transform(),
|
||||
self.options.is_fast_mode(),
|
||||
usage.resource_bytes as f64 / 1_048_576.0,
|
||||
limit_mb,
|
||||
usage.resource_count,
|
||||
cdim.width,
|
||||
cdim.height,
|
||||
cache_mb,
|
||||
mts,
|
||||
atlas_mb
|
||||
);
|
||||
}
|
||||
|
||||
match frame_type {
|
||||
|
||||
@ -6,7 +6,7 @@ use skia_safe::gpu::{
|
||||
use skia_safe::{self as skia, ISize};
|
||||
|
||||
const MIN_MAX_TEXTURE_SIZE: i32 = 512;
|
||||
const MAX_MAX_TEXTURE_SIZE: i32 = 8192 * 2;
|
||||
const MAX_MAX_TEXTURE_SIZE: i32 = 4096 * 2;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct GpuState {
|
||||
|
||||
@ -532,7 +532,16 @@ impl Surfaces {
|
||||
) {
|
||||
self.tiles.update(viewbox, tile_viewbox);
|
||||
if self.tiles.needs_snapshot() || self.tile_atlas_image.is_none() {
|
||||
self.tile_atlas_image = Some(self.tile_atlas.image_snapshot());
|
||||
// Snapshot only the occupied sub-region (origin stays at 0,0 so the
|
||||
// `textures` atlas coordinates remain valid) instead of the whole
|
||||
// max_texture_size² atlas — avoids a full-atlas COW copy each settle.
|
||||
let snap = match self.tiles.used_bounds() {
|
||||
Some(bounds) => self.tile_atlas.image_snapshot_with_bounds(bounds),
|
||||
None => Some(self.tile_atlas.image_snapshot()),
|
||||
};
|
||||
if let Some(image) = snap {
|
||||
self.tile_atlas_image = Some(image);
|
||||
}
|
||||
self.tiles.snapshot();
|
||||
}
|
||||
let Some(atlas_image) = self.tile_atlas_image.as_ref() else {
|
||||
@ -1579,6 +1588,35 @@ impl TileTextureCache {
|
||||
self.is_updated = false;
|
||||
}
|
||||
|
||||
/// Bounding box (from the atlas origin) of the slots actually sampled this
|
||||
/// frame. Slots are allocated row-major from index 0 and freed slots are
|
||||
/// reused first, so occupied slots cluster near (0,0): snapshotting only
|
||||
/// `(0,0)..(max_right,max_bottom)` keeps the `textures`/`transforms`
|
||||
/// coordinates valid (origin stays 0) while avoiding a full-atlas
|
||||
/// `image_snapshot` (1GB→content-sized). `None` when nothing is in use.
|
||||
pub fn used_bounds(&self) -> Option<skia::IRect> {
|
||||
let mut max_right = 0.0f32;
|
||||
let mut max_bottom = 0.0f32;
|
||||
let mut any = false;
|
||||
for r in self.textures.iter() {
|
||||
if r.is_empty() {
|
||||
continue;
|
||||
}
|
||||
any = true;
|
||||
max_right = max_right.max(r.right);
|
||||
max_bottom = max_bottom.max(r.bottom);
|
||||
}
|
||||
if !any {
|
||||
return None;
|
||||
}
|
||||
Some(skia::IRect::new(
|
||||
0,
|
||||
0,
|
||||
max_right.ceil() as i32,
|
||||
max_bottom.ceil() as i32,
|
||||
))
|
||||
}
|
||||
|
||||
fn gc_non_visible(&mut self, tile_viewbox: &TileViewbox) {
|
||||
let marked: Vec<_> = self
|
||||
.grid
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user