mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 02:46:43 +00:00
WIP: atlas perf improv
This commit is contained in:
parent
51127460b2
commit
7299e8d09d
6 changed files with 92 additions and 104 deletions
33
crates/gpui/src/atlas.rs
Normal file
33
crates/gpui/src/atlas.rs
Normal file
|
@ -0,0 +1,33 @@
|
|||
use crate::{AtlasKey, AtlasTile, DevicePixels, PlatformAtlas, Size};
|
||||
use anyhow::Result;
|
||||
use collections::FxHashMap;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
pub struct Atlas {
|
||||
platform_atlas: Arc<dyn PlatformAtlas>,
|
||||
tiles: FxHashMap<AtlasKey, AtlasTile>,
|
||||
}
|
||||
|
||||
impl Atlas {
|
||||
pub fn new(platform_atlas: Arc<dyn PlatformAtlas>) -> Self {
|
||||
Self {
|
||||
platform_atlas,
|
||||
tiles: FxHashMap::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_or_insert_with<'a>(
|
||||
&mut self,
|
||||
key: &AtlasKey,
|
||||
build: impl FnOnce() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
|
||||
) -> Result<AtlasTile> {
|
||||
if let Some(tile) = self.tiles.get(key) {
|
||||
Ok(tile.clone())
|
||||
} else {
|
||||
let (size, bytes) = build()?;
|
||||
let tile = self.platform_atlas.insert(key, size, bytes);
|
||||
self.tiles.insert(key.clone(), tile.clone());
|
||||
Ok(tile)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -4,6 +4,7 @@ mod app;
|
|||
|
||||
mod arena;
|
||||
mod assets;
|
||||
mod atlas;
|
||||
mod color;
|
||||
mod element;
|
||||
mod elements;
|
||||
|
@ -51,6 +52,7 @@ pub use anyhow::Result;
|
|||
pub use app::*;
|
||||
pub(crate) use arena::*;
|
||||
pub use assets::*;
|
||||
pub(crate) use atlas::*;
|
||||
pub use color::*;
|
||||
pub use ctor::ctor;
|
||||
pub use element::*;
|
||||
|
|
|
@ -263,13 +263,7 @@ impl From<RenderImageParams> for AtlasKey {
|
|||
}
|
||||
|
||||
pub trait PlatformAtlas: Send + Sync {
|
||||
fn get_or_insert_with<'a>(
|
||||
&self,
|
||||
key: &AtlasKey,
|
||||
build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
|
||||
) -> Result<AtlasTile>;
|
||||
|
||||
fn clear(&self);
|
||||
fn insert(&self, key: &AtlasKey, size: Size<DevicePixels>, bytes: Cow<[u8]>) -> AtlasTile;
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
|
|
@ -2,8 +2,6 @@ use crate::{
|
|||
AtlasKey, AtlasTextureId, AtlasTextureKind, AtlasTile, Bounds, DevicePixels, PlatformAtlas,
|
||||
Point, Size,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use collections::FxHashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use etagere::BucketedAtlasAllocator;
|
||||
use metal::Device;
|
||||
|
@ -19,7 +17,6 @@ impl MetalAtlas {
|
|||
monochrome_textures: Default::default(),
|
||||
polychrome_textures: Default::default(),
|
||||
path_textures: Default::default(),
|
||||
tiles_by_key: Default::default(),
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -53,41 +50,29 @@ struct MetalAtlasState {
|
|||
monochrome_textures: Vec<MetalAtlasTexture>,
|
||||
polychrome_textures: Vec<MetalAtlasTexture>,
|
||||
path_textures: Vec<MetalAtlasTexture>,
|
||||
tiles_by_key: FxHashMap<AtlasKey, AtlasTile>,
|
||||
}
|
||||
|
||||
impl PlatformAtlas for MetalAtlas {
|
||||
fn get_or_insert_with<'a>(
|
||||
&self,
|
||||
key: &AtlasKey,
|
||||
build: &mut dyn FnMut() -> Result<(Size<DevicePixels>, Cow<'a, [u8]>)>,
|
||||
) -> Result<AtlasTile> {
|
||||
fn insert(&self, key: &AtlasKey, size: Size<DevicePixels>, bytes: Cow<[u8]>) -> AtlasTile {
|
||||
let mut lock = self.0.lock();
|
||||
if let Some(tile) = lock.tiles_by_key.get(key) {
|
||||
Ok(tile.clone())
|
||||
} else {
|
||||
let (size, bytes) = build()?;
|
||||
let tile = lock.allocate(size, key.texture_kind());
|
||||
let texture = lock.texture(tile.texture_id);
|
||||
texture.upload(tile.bounds, &bytes);
|
||||
lock.tiles_by_key.insert(key.clone(), tile.clone());
|
||||
Ok(tile)
|
||||
}
|
||||
let tile = lock.allocate(size, key.texture_kind());
|
||||
let texture = lock.texture(tile.texture_id);
|
||||
texture.upload(tile.bounds, &bytes);
|
||||
tile
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
let mut lock = self.0.lock();
|
||||
lock.tiles_by_key.clear();
|
||||
for texture in &mut lock.monochrome_textures {
|
||||
texture.clear();
|
||||
}
|
||||
for texture in &mut lock.polychrome_textures {
|
||||
texture.clear();
|
||||
}
|
||||
for texture in &mut lock.path_textures {
|
||||
texture.clear();
|
||||
}
|
||||
}
|
||||
// fn clear(&self) {
|
||||
// let mut lock = self.0.lock();
|
||||
// for texture in &mut lock.monochrome_textures {
|
||||
// texture.clear();
|
||||
// }
|
||||
// for texture in &mut lock.polychrome_textures {
|
||||
// texture.clear();
|
||||
// }
|
||||
// for texture in &mut lock.path_textures {
|
||||
// texture.clear();
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
impl MetalAtlasState {
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use crate::{
|
||||
px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, InputEvent, KeyDownEvent,
|
||||
Keystroke, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
||||
Size, TestPlatform, TileId, WindowAppearance, WindowBounds, WindowOptions,
|
||||
px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, DevicePixels, InputEvent,
|
||||
KeyDownEvent, Keystroke, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler,
|
||||
PlatformWindow, Point, Size, TestPlatform, TileId, WindowAppearance, WindowBounds,
|
||||
WindowOptions,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use std::{
|
||||
borrow::Cow,
|
||||
rc::{Rc, Weak},
|
||||
sync::{self, Arc},
|
||||
};
|
||||
|
@ -271,64 +272,35 @@ impl PlatformWindow for TestWindow {
|
|||
|
||||
pub struct TestAtlasState {
|
||||
next_id: u32,
|
||||
tiles: HashMap<AtlasKey, AtlasTile>,
|
||||
}
|
||||
|
||||
pub struct TestAtlas(Mutex<TestAtlasState>);
|
||||
|
||||
impl TestAtlas {
|
||||
pub fn new() -> Self {
|
||||
TestAtlas(Mutex::new(TestAtlasState {
|
||||
next_id: 0,
|
||||
tiles: HashMap::default(),
|
||||
}))
|
||||
TestAtlas(Mutex::new(TestAtlasState { next_id: 0 }))
|
||||
}
|
||||
}
|
||||
|
||||
impl PlatformAtlas for TestAtlas {
|
||||
fn get_or_insert_with<'a>(
|
||||
&self,
|
||||
key: &crate::AtlasKey,
|
||||
build: &mut dyn FnMut() -> anyhow::Result<(
|
||||
Size<crate::DevicePixels>,
|
||||
std::borrow::Cow<'a, [u8]>,
|
||||
)>,
|
||||
) -> anyhow::Result<crate::AtlasTile> {
|
||||
fn insert(&self, _key: &AtlasKey, size: Size<DevicePixels>, _bytes: Cow<[u8]>) -> AtlasTile {
|
||||
let mut state = self.0.lock();
|
||||
if let Some(tile) = state.tiles.get(key) {
|
||||
return Ok(tile.clone());
|
||||
}
|
||||
|
||||
state.next_id += 1;
|
||||
let texture_id = state.next_id;
|
||||
state.next_id += 1;
|
||||
let tile_id = state.next_id;
|
||||
|
||||
drop(state);
|
||||
let (size, _) = build()?;
|
||||
let mut state = self.0.lock();
|
||||
|
||||
state.tiles.insert(
|
||||
key.clone(),
|
||||
crate::AtlasTile {
|
||||
texture_id: AtlasTextureId {
|
||||
index: texture_id,
|
||||
kind: crate::AtlasTextureKind::Path,
|
||||
},
|
||||
tile_id: TileId(tile_id),
|
||||
bounds: crate::Bounds {
|
||||
origin: Point::default(),
|
||||
size,
|
||||
},
|
||||
AtlasTile {
|
||||
texture_id: AtlasTextureId {
|
||||
index: texture_id,
|
||||
kind: crate::AtlasTextureKind::Path,
|
||||
},
|
||||
);
|
||||
|
||||
Ok(state.tiles[key].clone())
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
let mut state = self.0.lock();
|
||||
state.tiles = HashMap::default();
|
||||
state.next_id = 0;
|
||||
tile_id: TileId(tile_id),
|
||||
bounds: Bounds {
|
||||
origin: Point::default(),
|
||||
size,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
|
||||
use crate::{
|
||||
px, size, transparent_black, Action, AnyDrag, AnyTooltip, AnyView, AppContext, Arena,
|
||||
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
|
||||
AsyncWindowContext, Atlas, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
|
||||
DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
|
||||
Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
|
||||
ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId,
|
||||
Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent,
|
||||
Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
||||
PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams,
|
||||
RenderSvgParams, ScaledPixels, Scene, Shadow, SharedString, Size, Style, SubscriberSet,
|
||||
Subscription, Surface, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext,
|
||||
WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
Path, Pixels, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite,
|
||||
PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
|
||||
Scene, Shadow, SharedString, Size, Style, SubscriberSet, Subscription, Surface,
|
||||
TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
|
||||
WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
|
||||
};
|
||||
use anyhow::{anyhow, Context as _, Result};
|
||||
use collections::{FxHashMap, FxHashSet};
|
||||
|
@ -258,7 +258,7 @@ pub struct Window {
|
|||
pub(crate) removed: bool,
|
||||
pub(crate) platform_window: Box<dyn PlatformWindow>,
|
||||
display_id: DisplayId,
|
||||
sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||
sprite_atlas: Atlas,
|
||||
rem_size: Pixels,
|
||||
viewport_size: Size<Pixels>,
|
||||
layout_engine: Option<TaffyLayoutEngine>,
|
||||
|
@ -414,7 +414,7 @@ impl Window {
|
|||
) -> Self {
|
||||
let platform_window = cx.platform.open_window(handle, options);
|
||||
let display_id = platform_window.display().id();
|
||||
let sprite_atlas = platform_window.sprite_atlas();
|
||||
let sprite_atlas = Atlas::new(platform_window.sprite_atlas());
|
||||
let mouse_position = platform_window.mouse_position();
|
||||
let modifiers = platform_window.modifiers();
|
||||
let content_size = platform_window.content_size();
|
||||
|
@ -424,7 +424,9 @@ impl Window {
|
|||
platform_window.on_request_frame(Box::new({
|
||||
let mut cx = cx.to_async();
|
||||
move || {
|
||||
let t0 = std::time::Instant::now();
|
||||
handle.update(&mut cx, |_, cx| cx.draw()).log_err();
|
||||
dbg!(t0.elapsed());
|
||||
}
|
||||
}));
|
||||
platform_window.on_resize(Box::new({
|
||||
|
@ -1255,8 +1257,8 @@ impl<'a> WindowContext<'a> {
|
|||
let tile =
|
||||
self.window
|
||||
.sprite_atlas
|
||||
.get_or_insert_with(¶ms.clone().into(), &mut || {
|
||||
let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
|
||||
.get_or_insert_with(¶ms.clone().into(), || {
|
||||
let (size, bytes) = self.app.text_system().rasterize_glyph(¶ms)?;
|
||||
Ok((size, Cow::Owned(bytes)))
|
||||
})?;
|
||||
let bounds = Bounds {
|
||||
|
@ -1308,8 +1310,8 @@ impl<'a> WindowContext<'a> {
|
|||
let tile =
|
||||
self.window
|
||||
.sprite_atlas
|
||||
.get_or_insert_with(¶ms.clone().into(), &mut || {
|
||||
let (size, bytes) = self.text_system().rasterize_glyph(¶ms)?;
|
||||
.get_or_insert_with(¶ms.clone().into(), || {
|
||||
let (size, bytes) = self.app.text_system().rasterize_glyph(¶ms)?;
|
||||
Ok((size, Cow::Owned(bytes)))
|
||||
})?;
|
||||
let bounds = Bounds {
|
||||
|
@ -1354,13 +1356,13 @@ impl<'a> WindowContext<'a> {
|
|||
.map(|pixels| DevicePixels::from((pixels.0 * 2.).ceil() as i32)),
|
||||
};
|
||||
|
||||
let tile =
|
||||
self.window
|
||||
.sprite_atlas
|
||||
.get_or_insert_with(¶ms.clone().into(), &mut || {
|
||||
let bytes = self.svg_renderer.render(¶ms)?;
|
||||
Ok((params.size, Cow::Owned(bytes)))
|
||||
})?;
|
||||
let tile = self
|
||||
.window
|
||||
.sprite_atlas
|
||||
.get_or_insert_with(¶ms.clone().into(), || {
|
||||
let bytes = self.app.svg_renderer.render(¶ms)?;
|
||||
Ok((params.size, Cow::Owned(bytes)))
|
||||
})?;
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
let view_id = self.parent_view_id();
|
||||
|
||||
|
@ -1396,7 +1398,7 @@ impl<'a> WindowContext<'a> {
|
|||
let tile = self
|
||||
.window
|
||||
.sprite_atlas
|
||||
.get_or_insert_with(¶ms.clone().into(), &mut || {
|
||||
.get_or_insert_with(¶ms.clone().into(), || {
|
||||
Ok((data.size(), Cow::Borrowed(data.as_bytes())))
|
||||
})?;
|
||||
let content_mask = self.content_mask().scale(scale_factor);
|
||||
|
|
Loading…
Reference in a new issue