Checkpoint
This commit is contained in:
@@ -1,35 +1,54 @@
|
||||
use crate::{AtlasTextureId, AtlasTile, Bounds, DevicePixels, PlatformAtlas, Point, Size};
|
||||
use collections::HashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use etagere::BucketedAtlasAllocator;
|
||||
use foreign_types::ForeignType;
|
||||
use metal::{Device, TextureDescriptor, TextureDescriptorRef};
|
||||
use metal::{Device, TextureDescriptor};
|
||||
use objc::{msg_send, sel, sel_impl};
|
||||
use parking_lot::{RwLock, RwLockUpgradableReadGuard};
|
||||
use parking_lot::Mutex;
|
||||
use std::hash::Hash;
|
||||
|
||||
pub struct MetalAtlas<Key>(RwLock<MetalAtlasState<Key>>);
|
||||
pub struct MetalAtlas<Key>(Mutex<MetalAtlasState<Key>>);
|
||||
|
||||
impl<Key> MetalAtlas<Key> {
|
||||
pub fn new(
|
||||
size: Size<DevicePixels>,
|
||||
pixel_format: metal::MTLPixelFormat,
|
||||
device: Device,
|
||||
) -> Self {
|
||||
let texture_descriptor = metal::TextureDescriptor::new();
|
||||
texture_descriptor.set_pixel_format(pixel_format);
|
||||
texture_descriptor.set_width(size.width.into());
|
||||
texture_descriptor.set_height(size.height.into());
|
||||
MetalAtlas(Mutex::new(MetalAtlasState {
|
||||
device: AssertSend(device),
|
||||
texture_descriptor: AssertSend(texture_descriptor),
|
||||
textures: Default::default(),
|
||||
tiles_by_key: Default::default(),
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
struct MetalAtlasState<Key> {
|
||||
device: Device,
|
||||
texture_descriptor: TextureDescriptor,
|
||||
device: AssertSend<Device>,
|
||||
texture_descriptor: AssertSend<TextureDescriptor>,
|
||||
textures: Vec<MetalAtlasTexture>,
|
||||
tiles_by_key: HashMap<Key, AtlasTile>,
|
||||
}
|
||||
|
||||
impl<Key> PlatformAtlas<Key> for MetalAtlas<Key>
|
||||
where
|
||||
Key: Eq + Hash,
|
||||
Key: Eq + Hash + Send,
|
||||
{
|
||||
fn get_or_insert_with(
|
||||
&self,
|
||||
key: Key,
|
||||
build: impl FnOnce() -> (Size<DevicePixels>, Vec<u8>),
|
||||
build: &dyn Fn() -> (Size<DevicePixels>, Vec<u8>),
|
||||
) -> AtlasTile {
|
||||
let lock = self.0.upgradable_read();
|
||||
let mut lock = self.0.lock();
|
||||
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()
|
||||
@@ -45,7 +64,7 @@ where
|
||||
}
|
||||
|
||||
fn clear(&self) {
|
||||
self.0.write().tiles_by_key.clear();
|
||||
self.0.lock().tiles_by_key.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +81,7 @@ impl<Key> MetalAtlasState<Key> {
|
||||
{
|
||||
let descriptor = unsafe {
|
||||
let descriptor_ptr: *mut metal::MTLTextureDescriptor =
|
||||
msg_send![self.texture_descriptor, copy];
|
||||
msg_send![*self.texture_descriptor, copy];
|
||||
metal::TextureDescriptor::from_ptr(descriptor_ptr)
|
||||
};
|
||||
descriptor.set_width(min_size.width.into());
|
||||
@@ -78,7 +97,7 @@ impl<Key> MetalAtlasState<Key> {
|
||||
let atlas_texture = MetalAtlasTexture {
|
||||
id: AtlasTextureId(self.textures.len()),
|
||||
allocator: etagere::BucketedAtlasAllocator::new(size.into()),
|
||||
metal_texture,
|
||||
metal_texture: AssertSend(metal_texture),
|
||||
};
|
||||
self.textures.push(atlas_texture);
|
||||
self.textures.last_mut().unwrap()
|
||||
@@ -88,7 +107,7 @@ impl<Key> MetalAtlasState<Key> {
|
||||
struct MetalAtlasTexture {
|
||||
id: AtlasTextureId,
|
||||
allocator: BucketedAtlasAllocator,
|
||||
metal_texture: metal::Texture,
|
||||
metal_texture: AssertSend<metal::Texture>,
|
||||
}
|
||||
|
||||
impl MetalAtlasTexture {
|
||||
@@ -162,3 +181,8 @@ impl From<etagere::Rectangle> for Bounds<DevicePixels> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
struct AssertSend<T>(T);
|
||||
|
||||
unsafe impl<T> Send for AssertSend<T> {}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
use crate::{point, size, DevicePixels, MonochromeSprite, Quad, Scene, Size};
|
||||
use crate::{
|
||||
point, size, DevicePixels, MetalAtlas, MonochromeSprite, Quad, RasterizedGlyphId, Scene, Size,
|
||||
};
|
||||
use bytemuck::{Pod, Zeroable};
|
||||
use cocoa::{
|
||||
base::{NO, YES},
|
||||
@@ -7,7 +9,7 @@ use cocoa::{
|
||||
};
|
||||
use metal::{CommandQueue, MTLPixelFormat, MTLResourceOptions, NSRange};
|
||||
use objc::{self, msg_send, sel, sel_impl};
|
||||
use std::{ffi::c_void, mem, ptr};
|
||||
use std::{ffi::c_void, mem, ptr, sync::Arc};
|
||||
|
||||
const SHADERS_METALLIB: &[u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib"));
|
||||
const INSTANCE_BUFFER_SIZE: usize = 8192 * 1024; // This is an arbitrary decision. There's probably a more optimal value.
|
||||
@@ -19,6 +21,7 @@ pub struct MetalRenderer {
|
||||
quad_pipeline_state: metal::RenderPipelineState,
|
||||
unit_vertices: metal::Buffer,
|
||||
instances: metal::Buffer,
|
||||
glyph_atlas: Arc<MetalAtlas<RasterizedGlyphId>>,
|
||||
}
|
||||
|
||||
impl MetalRenderer {
|
||||
@@ -88,6 +91,15 @@ impl MetalRenderer {
|
||||
);
|
||||
|
||||
let command_queue = device.new_command_queue();
|
||||
let glyph_atlas = Arc::new(MetalAtlas::new(
|
||||
Size {
|
||||
width: DevicePixels(1024),
|
||||
height: DevicePixels(1024),
|
||||
},
|
||||
MTLPixelFormat::A8Unorm,
|
||||
device.clone(),
|
||||
));
|
||||
|
||||
Self {
|
||||
device,
|
||||
layer,
|
||||
@@ -95,6 +107,7 @@ impl MetalRenderer {
|
||||
quad_pipeline_state,
|
||||
unit_vertices,
|
||||
instances,
|
||||
glyph_atlas,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -102,6 +115,10 @@ impl MetalRenderer {
|
||||
&*self.layer
|
||||
}
|
||||
|
||||
pub fn glyph_atlas(&self) -> &Arc<MetalAtlas<RasterizedGlyphId>> {
|
||||
&self.glyph_atlas
|
||||
}
|
||||
|
||||
pub fn draw(&mut self, scene: &mut Scene) {
|
||||
let layer = self.layer.clone();
|
||||
let viewport_size = layer.drawable_size();
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
point, px, size, Bounds, Font, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight, Glyph,
|
||||
GlyphId, LineLayout, Pixels, PlatformTextSystem, Point, RasterizationOptions, Result, Run,
|
||||
SharedString, Size,
|
||||
point, px, size, Bounds, Font, FontFeatures, FontId, FontMetrics, FontStyle, FontWeight,
|
||||
GlyphId, Pixels, PlatformTextSystem, Point, RasterizationOptions, Result, ShapedGlyph,
|
||||
ShapedLine, ShapedRun, SharedString, Size,
|
||||
};
|
||||
use cocoa::appkit::{CGFloat, CGPoint};
|
||||
use collections::HashMap;
|
||||
@@ -161,7 +161,7 @@ impl PlatformTextSystem for MacTextSystem {
|
||||
text: &str,
|
||||
font_size: Pixels,
|
||||
font_runs: &[(usize, FontId)],
|
||||
) -> LineLayout {
|
||||
) -> ShapedLine {
|
||||
self.0.write().layout_line(text, font_size, font_runs)
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ impl MacTextSystemState {
|
||||
text: &str,
|
||||
font_size: Pixels,
|
||||
font_runs: &[(usize, FontId)],
|
||||
) -> LineLayout {
|
||||
) -> ShapedLine {
|
||||
// Construct the attributed string, converting UTF8 ranges to UTF16 ranges.
|
||||
let mut string = CFMutableAttributedString::new();
|
||||
{
|
||||
@@ -409,7 +409,7 @@ impl MacTextSystemState {
|
||||
{
|
||||
let glyph_utf16_ix = usize::try_from(*glyph_utf16_ix).unwrap();
|
||||
ix_converter.advance_to_utf16_ix(glyph_utf16_ix);
|
||||
glyphs.push(Glyph {
|
||||
glyphs.push(ShapedGlyph {
|
||||
id: (*glyph_id).into(),
|
||||
position: point(position.x as f32, position.y as f32).map(px),
|
||||
index: ix_converter.utf8_ix,
|
||||
@@ -417,11 +417,11 @@ impl MacTextSystemState {
|
||||
});
|
||||
}
|
||||
|
||||
runs.push(Run { font_id, glyphs })
|
||||
runs.push(ShapedRun { font_id, glyphs })
|
||||
}
|
||||
|
||||
let typographic_bounds = line.get_typographic_bounds();
|
||||
LineLayout {
|
||||
ShapedLine {
|
||||
width: typographic_bounds.width.into(),
|
||||
ascent: typographic_bounds.ascent.into(),
|
||||
descent: typographic_bounds.descent.into(),
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use super::{ns_string, MetalRenderer, NSRange};
|
||||
use crate::{
|
||||
point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, Modifiers,
|
||||
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt,
|
||||
Pixels, Platform, PlatformDispatcher, PlatformInputHandler, PlatformScreen, PlatformWindow,
|
||||
Point, Scene, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
|
||||
WindowPromptLevel,
|
||||
point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen,
|
||||
MetalAtlas, Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent,
|
||||
MouseUpEvent, NSRectExt, Pixels, Platform, PlatformAtlas, PlatformDispatcher,
|
||||
PlatformInputHandler, PlatformScreen, PlatformWindow, Point, RasterizedGlyphId, Scene, Size,
|
||||
Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions, WindowPromptLevel,
|
||||
};
|
||||
use block::ConcreteBlock;
|
||||
use cocoa::{
|
||||
@@ -20,6 +20,7 @@ use core_graphics::display::CGRect;
|
||||
use ctor::ctor;
|
||||
use foreign_types::ForeignTypeRef;
|
||||
use futures::channel::oneshot;
|
||||
use metal::{MTLPixelFormat, TextureDescriptor};
|
||||
use objc::{
|
||||
class,
|
||||
declare::ClassDecl,
|
||||
@@ -885,6 +886,10 @@ impl PlatformWindow for MacWindow {
|
||||
let _: () = msg_send![this.native_window.contentView(), setNeedsDisplay: YES];
|
||||
}
|
||||
}
|
||||
|
||||
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas<RasterizedGlyphId>> {
|
||||
self.0.lock().renderer.glyph_atlas().clone()
|
||||
}
|
||||
}
|
||||
|
||||
fn get_scale_factor(native_window: id) -> f32 {
|
||||
|
||||
Reference in New Issue
Block a user