Checkpoint
This commit is contained in:
parent
dcaf4c905f
commit
12ba10bc2c
6 changed files with 196 additions and 24 deletions
|
@ -32,7 +32,7 @@ pub struct Text<S> {
|
||||||
|
|
||||||
impl<S: 'static> Element for Text<S> {
|
impl<S: 'static> Element for Text<S> {
|
||||||
type State = S;
|
type State = S;
|
||||||
type FrameState = Arc<Mutex<Option<TextLayout>>>;
|
type FrameState = Arc<Mutex<Option<TextFrameState>>>;
|
||||||
|
|
||||||
fn layout(
|
fn layout(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
@ -54,7 +54,6 @@ impl<S: 'static> Element for Text<S> {
|
||||||
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
||||||
let frame_state = paint_state.clone();
|
let frame_state = paint_state.clone();
|
||||||
move |_, _| {
|
move |_, _| {
|
||||||
dbg!("starting measurement");
|
|
||||||
let Some(line_layout) = text_system
|
let Some(line_layout) = text_system
|
||||||
.layout_line(
|
.layout_line(
|
||||||
text.as_ref(),
|
text.as_ref(),
|
||||||
|
@ -65,23 +64,21 @@ impl<S: 'static> Element for Text<S> {
|
||||||
else {
|
else {
|
||||||
return Size::default();
|
return Size::default();
|
||||||
};
|
};
|
||||||
dbg!("bbbb");
|
|
||||||
|
|
||||||
let size = Size {
|
let size = Size {
|
||||||
width: line_layout.width(),
|
width: line_layout.width(),
|
||||||
height: line_height,
|
height: line_height,
|
||||||
};
|
};
|
||||||
|
|
||||||
frame_state.lock().replace(TextLayout {
|
frame_state.lock().replace(TextFrameState {
|
||||||
line: Arc::new(line_layout),
|
line: Arc::new(line_layout),
|
||||||
line_height,
|
line_height,
|
||||||
});
|
});
|
||||||
|
|
||||||
dbg!(size)
|
size
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
dbg!("got to end of text layout");
|
|
||||||
Ok((layout_id?, paint_state))
|
Ok((layout_id?, paint_state))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -89,22 +86,20 @@ impl<S: 'static> Element for Text<S> {
|
||||||
&mut self,
|
&mut self,
|
||||||
layout: Layout,
|
layout: Layout,
|
||||||
_: &mut Self::State,
|
_: &mut Self::State,
|
||||||
paint_state: &mut Self::FrameState,
|
frame_state: &mut Self::FrameState,
|
||||||
cx: &mut ViewContext<S>,
|
cx: &mut ViewContext<S>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
let line;
|
let line;
|
||||||
let line_height;
|
let line_height;
|
||||||
{
|
{
|
||||||
let paint_state = paint_state.lock();
|
let frame_state = frame_state.lock();
|
||||||
let paint_state = paint_state
|
let frame_state = frame_state
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.expect("measurement has not been performed");
|
.expect("measurement has not been performed");
|
||||||
line = paint_state.line.clone();
|
line = frame_state.line.clone();
|
||||||
line_height = paint_state.line_height;
|
line_height = frame_state.line_height;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _text_style = cx.text_style();
|
|
||||||
|
|
||||||
// todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder.");
|
// todo!("We haven't added visible bounds to the new element system yet, so this is a placeholder.");
|
||||||
let visible_bounds = layout.bounds;
|
let visible_bounds = layout.bounds;
|
||||||
line.paint(&layout, visible_bounds, line_height, cx)?;
|
line.paint(&layout, visible_bounds, line_height, cx)?;
|
||||||
|
@ -113,7 +108,7 @@ impl<S: 'static> Element for Text<S> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct TextLayout {
|
pub struct TextFrameState {
|
||||||
line: Arc<Line>,
|
line: Arc<Line>,
|
||||||
line_height: Pixels,
|
line_height: Pixels,
|
||||||
}
|
}
|
||||||
|
|
|
@ -180,14 +180,30 @@ pub trait PlatformTextSystem: Send + Sync {
|
||||||
) -> Vec<usize>;
|
) -> Vec<usize>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait PlatformSpriteSystem<Key> {
|
pub trait PlatformAtlas<Key> {
|
||||||
fn get_or_insert_with(
|
fn get_or_insert_with(
|
||||||
&self,
|
&self,
|
||||||
key: Key,
|
key: Key,
|
||||||
build: impl FnOnce() -> (Size<DevicePixels>, Vec<u8>),
|
build: impl FnOnce() -> (Size<DevicePixels>, Vec<u8>),
|
||||||
) -> MonochromeSprite;
|
) -> AtlasTile;
|
||||||
|
|
||||||
|
fn clear(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AtlasTile {
|
||||||
|
pub(crate) texture_id: AtlasTextureId,
|
||||||
|
pub(crate) tile_id: TileId,
|
||||||
|
pub(crate) bounds_in_atlas: Bounds<DevicePixels>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug)]
|
||||||
|
#[repr(C)]
|
||||||
|
pub(crate) struct AtlasTextureId(pub(crate) usize);
|
||||||
|
|
||||||
|
pub(crate) type TileId = etagere::AllocId;
|
||||||
|
|
||||||
pub trait PlatformInputHandler {
|
pub trait PlatformInputHandler {
|
||||||
fn selected_text_range(&self) -> Option<Range<usize>>;
|
fn selected_text_range(&self) -> Option<Range<usize>>;
|
||||||
fn marked_text_range(&self) -> Option<Range<usize>>;
|
fn marked_text_range(&self) -> Option<Range<usize>>;
|
||||||
|
|
|
@ -2,11 +2,11 @@
|
||||||
///! an origin at the bottom left of the main display.
|
///! an origin at the bottom left of the main display.
|
||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
mod events;
|
mod events;
|
||||||
|
mod metal_atlas;
|
||||||
mod metal_renderer;
|
mod metal_renderer;
|
||||||
mod open_type;
|
mod open_type;
|
||||||
mod platform;
|
mod platform;
|
||||||
mod screen;
|
mod screen;
|
||||||
mod sprite;
|
|
||||||
mod text_system;
|
mod text_system;
|
||||||
mod window;
|
mod window;
|
||||||
mod window_appearence;
|
mod window_appearence;
|
||||||
|
@ -31,9 +31,9 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use dispatcher::*;
|
pub use dispatcher::*;
|
||||||
|
pub use metal_atlas::*;
|
||||||
pub use platform::*;
|
pub use platform::*;
|
||||||
pub use screen::*;
|
pub use screen::*;
|
||||||
pub use sprite::*;
|
|
||||||
pub use text_system::*;
|
pub use text_system::*;
|
||||||
pub use window::*;
|
pub use window::*;
|
||||||
|
|
||||||
|
|
164
crates/gpui3/src/platform/mac/metal_atlas.rs
Normal file
164
crates/gpui3/src/platform/mac/metal_atlas.rs
Normal file
|
@ -0,0 +1,164 @@
|
||||||
|
use crate::{AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size};
|
||||||
|
use collections::HashMap;
|
||||||
|
use etagere::BucketedAtlasAllocator;
|
||||||
|
use foreign_types::ForeignType;
|
||||||
|
use metal::{Device, TextureDescriptor, TextureDescriptorRef};
|
||||||
|
use objc::{msg_send, sel, sel_impl};
|
||||||
|
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||||
|
use std::hash::Hash;
|
||||||
|
|
||||||
|
pub struct MetalAtlas<Key>(RwLock<MetalAtlasState<Key>>);
|
||||||
|
|
||||||
|
struct MetalAtlasState<Key> {
|
||||||
|
device: Device,
|
||||||
|
texture_descriptor: TextureDescriptor,
|
||||||
|
textures: Vec<MetalAtlasTexture>,
|
||||||
|
tiles_by_key: HashMap<Key, AtlasTile>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Key> PlatformAtlas<Key> for MetalAtlas<Key>
|
||||||
|
where
|
||||||
|
Key: Eq + Hash,
|
||||||
|
{
|
||||||
|
fn get_or_insert_with(
|
||||||
|
&self,
|
||||||
|
key: Key,
|
||||||
|
build: impl FnOnce() -> (Size<DevicePixels>, Vec<u8>),
|
||||||
|
) -> AtlasTile {
|
||||||
|
let lock = self.0.upgradable_read();
|
||||||
|
if let Some(tile) = lock.tiles_by_key.get(&key) {
|
||||||
|
return tile.clone();
|
||||||
|
} else {
|
||||||
|
let mut lock = RwLockUpgradableReadGuard::upgrade(lock);
|
||||||
|
let (size, bytes) = build();
|
||||||
|
lock.textures
|
||||||
|
.iter_mut()
|
||||||
|
.rev()
|
||||||
|
.find_map(|texture| texture.allocate(size, &bytes))
|
||||||
|
.unwrap_or_else(|| {
|
||||||
|
let texture = lock.push_texture(size);
|
||||||
|
texture
|
||||||
|
.allocate(size, &bytes)
|
||||||
|
.expect("could not allocate a tile in new texture")
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&self) {
|
||||||
|
self.0.write().tiles_by_key.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<Key> MetalAtlasState<Key> {
|
||||||
|
fn push_texture(&mut self, min_size: Size<DevicePixels>) -> &mut MetalAtlasTexture {
|
||||||
|
let default_atlas_size = Size {
|
||||||
|
width: self.texture_descriptor.width().into(),
|
||||||
|
height: self.texture_descriptor.height().into(),
|
||||||
|
};
|
||||||
|
let size;
|
||||||
|
let metal_texture;
|
||||||
|
|
||||||
|
if min_size.width > default_atlas_size.width || min_size.height > default_atlas_size.height
|
||||||
|
{
|
||||||
|
let descriptor = unsafe {
|
||||||
|
let descriptor_ptr: *mut metal::MTLTextureDescriptor =
|
||||||
|
msg_send![self.texture_descriptor, copy];
|
||||||
|
metal::TextureDescriptor::from_ptr(descriptor_ptr)
|
||||||
|
};
|
||||||
|
descriptor.set_width(min_size.width.into());
|
||||||
|
descriptor.set_height(min_size.height.into());
|
||||||
|
|
||||||
|
size = min_size;
|
||||||
|
metal_texture = self.device.new_texture(&descriptor);
|
||||||
|
} else {
|
||||||
|
size = default_atlas_size;
|
||||||
|
metal_texture = self.device.new_texture(&self.texture_descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
let atlas_texture = MetalAtlasTexture {
|
||||||
|
id: AtlasTextureId(self.textures.len()),
|
||||||
|
allocator: etagere::BucketedAtlasAllocator::new(size.into()),
|
||||||
|
metal_texture,
|
||||||
|
};
|
||||||
|
self.textures.push(atlas_texture);
|
||||||
|
self.textures.last_mut().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct MetalAtlasTexture {
|
||||||
|
id: AtlasTextureId,
|
||||||
|
allocator: BucketedAtlasAllocator,
|
||||||
|
metal_texture: metal::Texture,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MetalAtlasTexture {
|
||||||
|
fn allocate(&mut self, size: Size<DevicePixels>, bytes: &[u8]) -> Option<AtlasTile> {
|
||||||
|
let size = size.into();
|
||||||
|
let allocation = self.allocator.allocate(size)?;
|
||||||
|
let tile = AtlasTile {
|
||||||
|
texture_id: self.id,
|
||||||
|
tile_id: allocation.id,
|
||||||
|
bounds_in_atlas: allocation.rectangle.into(),
|
||||||
|
};
|
||||||
|
let region = metal::MTLRegion::new_2d(
|
||||||
|
u32::from(tile.bounds_in_atlas.origin.x) as u64,
|
||||||
|
u32::from(tile.bounds_in_atlas.origin.y) as u64,
|
||||||
|
u32::from(tile.bounds_in_atlas.size.width) as u64,
|
||||||
|
u32::from(tile.bounds_in_atlas.size.height) as u64,
|
||||||
|
);
|
||||||
|
self.metal_texture.replace_region(
|
||||||
|
region,
|
||||||
|
0,
|
||||||
|
bytes.as_ptr() as *const _,
|
||||||
|
u32::from(
|
||||||
|
tile.bounds_in_atlas
|
||||||
|
.size
|
||||||
|
.width
|
||||||
|
.to_bytes(self.bytes_per_pixel()),
|
||||||
|
) as u64,
|
||||||
|
);
|
||||||
|
Some(tile)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bytes_per_pixel(&self) -> u8 {
|
||||||
|
use metal::MTLPixelFormat::*;
|
||||||
|
match self.metal_texture.pixel_format() {
|
||||||
|
A8Unorm | R8Unorm => 1,
|
||||||
|
RGBA8Unorm | BGRA8Unorm => 4,
|
||||||
|
_ => unimplemented!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Size<DevicePixels>> for etagere::Size {
|
||||||
|
fn from(size: Size<DevicePixels>) -> Self {
|
||||||
|
etagere::Size::new(u32::from(size.width) as i32, u32::from(size.width) as i32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<etagere::Point> for Point<DevicePixels> {
|
||||||
|
fn from(value: etagere::Point) -> Self {
|
||||||
|
Point {
|
||||||
|
x: DevicePixels::from(value.x as u32),
|
||||||
|
y: DevicePixels::from(value.y as u32),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<etagere::Size> for Size<DevicePixels> {
|
||||||
|
fn from(size: etagere::Size) -> Self {
|
||||||
|
Size {
|
||||||
|
width: DevicePixels::from(size.width as u32),
|
||||||
|
height: DevicePixels::from(size.height as u32),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<etagere::Rectangle> for Bounds<DevicePixels> {
|
||||||
|
fn from(rectangle: etagere::Rectangle) -> Self {
|
||||||
|
Bounds {
|
||||||
|
origin: rectangle.min.into(),
|
||||||
|
size: rectangle.size().into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1 +0,0 @@
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use std::{iter::Peekable, mem};
|
use std::{iter::Peekable, mem};
|
||||||
|
|
||||||
use super::{Bounds, Hsla, Pixels, Point};
|
use super::{Bounds, Hsla, Pixels, Point};
|
||||||
use crate::{Corners, DevicePixels, Edges};
|
use crate::{AtlasTile, Corners, DevicePixels, Edges};
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
|
||||||
// Exported to metal
|
// Exported to metal
|
||||||
|
@ -243,10 +243,8 @@ impl From<Quad> for Primitive {
|
||||||
pub struct MonochromeSprite {
|
pub struct MonochromeSprite {
|
||||||
pub order: u32,
|
pub order: u32,
|
||||||
pub bounds: Bounds<Pixels>,
|
pub bounds: Bounds<Pixels>,
|
||||||
pub atlas_id: AtlasId,
|
pub color: Hsla,
|
||||||
pub tile_id: TileId,
|
pub tile: AtlasTile,
|
||||||
pub bounds_in_atlas: Bounds<DevicePixels>,
|
|
||||||
pub color: Option<Hsla>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MonochromeSprite {
|
impl MonochromeSprite {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue