Checkpoint

This commit is contained in:
Nathan Sobo
2023-10-03 13:03:29 -06:00
parent 3698e89b88
commit a8c1958c75
13 changed files with 248 additions and 186 deletions
+13 -9
View File
@@ -28,6 +28,10 @@ impl<Key> MetalAtlas<Key> {
tiles_by_key: Default::default(),
}))
}
pub(crate) fn texture(&self, id: AtlasTextureId) -> metal::Texture {
self.0.lock().textures[id.0 as usize].metal_texture.clone()
}
}
struct MetalAtlasState<Key> {
@@ -123,10 +127,10 @@ impl MetalAtlasTexture {
bounds: allocation.rectangle.into(),
};
let region = metal::MTLRegion::new_2d(
u32::from(tile.bounds.origin.x) as u64,
u32::from(tile.bounds.origin.y) as u64,
u32::from(tile.bounds.size.width) as u64,
u32::from(tile.bounds.size.height) as u64,
tile.bounds.origin.x.into(),
tile.bounds.origin.y.into(),
tile.bounds.size.width.into(),
tile.bounds.size.height.into(),
);
self.metal_texture.replace_region(
region,
@@ -149,15 +153,15 @@ impl MetalAtlasTexture {
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)
etagere::Size::new(size.width.into(), size.width.into())
}
}
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),
x: DevicePixels::from(value.x),
y: DevicePixels::from(value.y),
}
}
}
@@ -165,8 +169,8 @@ impl From<etagere::Point> for Point<DevicePixels> {
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),
width: DevicePixels::from(size.width),
height: DevicePixels::from(size.height),
}
}
}
+93 -17
View File
@@ -1,6 +1,6 @@
use crate::{
point, size, AtlasTextureId, DevicePixels, MetalAtlas, MonochromeSprite, Quad,
RasterizedGlyphId, Scene, Size,
RasterizeGlyphParams, Scene, Size,
};
use cocoa::{
base::{NO, YES},
@@ -18,10 +18,11 @@ pub struct MetalRenderer {
device: metal::Device,
layer: metal::MetalLayer,
command_queue: CommandQueue,
quad_pipeline_state: metal::RenderPipelineState,
quads_pipeline_state: metal::RenderPipelineState,
sprites_pipeline_state: metal::RenderPipelineState,
unit_vertices: metal::Buffer,
instances: metal::Buffer,
glyph_atlas: Arc<MetalAtlas<RasterizedGlyphId>>,
glyph_atlas: Arc<MetalAtlas<RasterizeGlyphParams>>,
}
impl MetalRenderer {
@@ -81,15 +82,24 @@ impl MetalRenderer {
MTLResourceOptions::StorageModeManaged,
);
let quad_pipeline_state = build_pipeline_state(
let quads_pipeline_state = build_pipeline_state(
&device,
&library,
"quad",
"quads",
"quad_vertex",
"quad_fragment",
PIXEL_FORMAT,
);
let sprites_pipeline_state = build_pipeline_state(
&device,
&library,
"sprites",
"monochrome_sprite_vertex",
"monochrome_sprite_fragment",
PIXEL_FORMAT,
);
let command_queue = device.new_command_queue();
let glyph_atlas = Arc::new(MetalAtlas::new(
Size {
@@ -104,7 +114,8 @@ impl MetalRenderer {
device,
layer,
command_queue,
quad_pipeline_state,
quads_pipeline_state,
sprites_pipeline_state,
unit_vertices,
instances,
glyph_atlas,
@@ -115,7 +126,7 @@ impl MetalRenderer {
&*self.layer
}
pub fn glyph_atlas(&self) -> &Arc<MetalAtlas<RasterizedGlyphId>> {
pub fn glyph_atlas(&self) -> &Arc<MetalAtlas<RasterizeGlyphParams>> {
&self.glyph_atlas
}
@@ -123,8 +134,8 @@ impl MetalRenderer {
let layer = self.layer.clone();
let viewport_size = layer.drawable_size();
let viewport_size: Size<DevicePixels> = size(
(viewport_size.width.ceil() as u32).into(),
(viewport_size.height.ceil() as u32).into(),
(viewport_size.width.ceil() as i32).into(),
(viewport_size.height.ceil() as i32).into(),
);
let drawable = if let Some(drawable) = layer.next_drawable() {
drawable
@@ -144,8 +155,8 @@ impl MetalRenderer {
depth_texture_desc.set_pixel_format(metal::MTLPixelFormat::Depth32Float);
depth_texture_desc.set_storage_mode(metal::MTLStorageMode::Private);
depth_texture_desc.set_usage(metal::MTLTextureUsage::RenderTarget);
depth_texture_desc.set_width(u32::from(viewport_size.width) as u64);
depth_texture_desc.set_height(u32::from(viewport_size.height) as u64);
depth_texture_desc.set_width(i32::from(viewport_size.width) as u64);
depth_texture_desc.set_height(i32::from(viewport_size.height) as u64);
let depth_texture = self.device.new_texture(&depth_texture_desc);
let depth_attachment = render_pass_descriptor.depth_attachment().unwrap();
@@ -168,8 +179,8 @@ impl MetalRenderer {
command_encoder.set_viewport(metal::MTLViewport {
originX: 0.0,
originY: 0.0,
width: u32::from(viewport_size.width) as f64,
height: u32::from(viewport_size.height) as f64,
width: i32::from(viewport_size.width) as f64,
height: i32::from(viewport_size.height) as f64,
znear: 0.0,
zfar: 1.0,
});
@@ -226,7 +237,7 @@ impl MetalRenderer {
}
align_offset(offset);
command_encoder.set_render_pipeline_state(&self.quad_pipeline_state);
command_encoder.set_render_pipeline_state(&self.quads_pipeline_state);
command_encoder.set_vertex_buffer(
QuadInputIndex::Vertices as u64,
Some(&self.unit_vertices),
@@ -273,12 +284,77 @@ impl MetalRenderer {
fn draw_monochrome_sprites(
&mut self,
texture_id: AtlasTextureId,
monochrome: &[MonochromeSprite],
sprites: &[MonochromeSprite],
offset: &mut usize,
viewport_size: Size<DevicePixels>,
command_encoder: &metal::RenderCommandEncoderRef,
) {
// todo!()
// dbg!(sprites);
if sprites.is_empty() {
return;
}
align_offset(offset);
let texture = self.glyph_atlas.texture(texture_id);
let texture_size = size(
DevicePixels(texture.width() as i32),
DevicePixels(texture.height() as i32),
);
command_encoder.set_render_pipeline_state(&self.sprites_pipeline_state);
command_encoder.set_vertex_buffer(
MonochromeSpriteInputIndex::Vertices as u64,
Some(&self.unit_vertices),
0,
);
command_encoder.set_vertex_buffer(
MonochromeSpriteInputIndex::Sprites as u64,
Some(&self.instances),
*offset as u64,
);
command_encoder.set_vertex_bytes(
MonochromeSpriteInputIndex::ViewportSize as u64,
mem::size_of_val(&viewport_size) as u64,
&viewport_size as *const Size<DevicePixels> as *const _,
);
command_encoder.set_vertex_bytes(
MonochromeSpriteInputIndex::AtlasTextureSize as u64,
mem::size_of_val(&texture_size) as u64,
&texture_size as *const Size<DevicePixels> as *const _,
);
command_encoder.set_fragment_buffer(
MonochromeSpriteInputIndex::Sprites as u64,
Some(&self.instances),
*offset as u64,
);
command_encoder.set_fragment_texture(
MonochromeSpriteInputIndex::AtlasTexture as u64,
Some(&texture),
);
let sprite_bytes_len = mem::size_of::<MonochromeSprite>() * sprites.len();
let buffer_contents = unsafe { (self.instances.contents() as *mut u8).add(*offset) };
unsafe {
ptr::copy_nonoverlapping(
sprites.as_ptr() as *const u8,
buffer_contents,
sprite_bytes_len,
);
}
let next_offset = *offset + sprite_bytes_len;
assert!(
next_offset <= INSTANCE_BUFFER_SIZE,
"instance buffer exhausted"
);
command_encoder.draw_primitives_instanced(
metal::MTLPrimitiveType::Triangle,
0,
6,
sprites.len() as u64,
);
*offset = next_offset;
}
}
@@ -334,6 +410,6 @@ enum MonochromeSpriteInputIndex {
Vertices = 0,
Sprites = 1,
ViewportSize = 2,
AtlasSize = 3,
AtlasTextureSize = 3,
AtlasTexture = 4,
}
+6 -53
View File
@@ -126,7 +126,7 @@ vertex MonochromeSpriteVertexOutput monochrome_sprite_vertex(
constant Size_DevicePixels *viewport_size
[[buffer(MonochromeSpriteInputIndex_ViewportSize)]],
constant Size_DevicePixels *atlas_size
[[buffer(MonochromeSpriteInputIndex_AtlasSize)]]) {
[[buffer(MonochromeSpriteInputIndex_AtlasTextureSize)]]) {
float2 unit_vertex = unit_vertices[unit_vertex_id];
MonochromeSprite sprite = sprites[sprite_id];
@@ -149,11 +149,13 @@ fragment float4 monochrome_sprite_fragment(
MonochromeSpriteVertexOutput input [[stage_in]],
constant MonochromeSprite *sprites
[[buffer(MonochromeSpriteInputIndex_Sprites)]],
texture2d<float> atlas
texture2d<float> atlas_texture
[[texture(MonochromeSpriteInputIndex_AtlasTexture)]]) {
MonochromeSprite sprite = sprites[input.sprite_id];
constexpr sampler atlas_sampler(mag_filter::linear, min_filter::linear);
float4 sample = atlas.sample(atlas_sampler, input.tile_position);
constexpr sampler atlas_texture_sampler(mag_filter::linear,
min_filter::linear);
float4 sample =
atlas_texture.sample(atlas_texture_sampler, input.tile_position);
float clip_distance =
quad_sdf(input.position.xy, sprite.clip_bounds, sprite.clip_corner_radii);
float4 color = input.color;
@@ -256,52 +258,3 @@ float quad_sdf(float2 point, Bounds_Pixels bounds,
return distance;
}
// struct SpriteFragmentInput {
// float4 position [[position]];
// float2 atlas_position;
// float4 color [[flat]];
// uchar compute_winding [[flat]];
// };
// vertex SpriteFragmentInput sprite_vertex(
// uint unit_vertex_id [[vertex_id]],
// uint sprite_id [[instance_id]],
// constant float2 *unit_vertices
// [[buffer(GPUISpriteVertexInputIndexVertices)]], constant GPUISprite
// *sprites [[buffer(GPUISpriteVertexInputIndexSprites)]], constant float2
// *viewport_size [[buffer(GPUISpriteVertexInputIndexViewportSize)]],
// constant float2 *atlas_size
// [[buffer(GPUISpriteVertexInputIndexAtlasSize)]]
// ) {
// float2 unit_vertex = unit_vertices[unit_vertex_id];
// GPUISprite sprite = sprites[sprite_id];
// float2 position = unit_vertex * sprite.target_size + sprite.origin;
// float4 device_position = to_device_position(position, *viewport_size);
// float2 atlas_position = (unit_vertex * sprite.source_size +
// sprite.atlas_origin) / *atlas_size;
// return SpriteFragmentInput {
// device_position,
// atlas_position,
// coloru_to_colorf(sprite.color),
// sprite.compute_winding
// };
// }
// fragment float4 sprite_fragment(
// SpriteFragmentInput input [[stage_in]],
// texture2d<float> atlas [[ texture(GPUISpriteFragmentInputIndexAtlas) ]]
// ) {
// constexpr sampler atlas_sampler(mag_filter::linear, min_filter::linear);
// float4 color = input.color;
// float4 sample = atlas.sample(atlas_sampler, input.atlas_position);
// float mask;
// if (input.compute_winding) {
// mask = 1. - abs(1. - fmod(sample.r, 2.));
// } else {
// mask = sample.a;
// }
// color.a *= mask;
// return color;
// }
+29 -23
View File
@@ -1,7 +1,7 @@
use crate::{
point, px, size, Bounds, DevicePixels, Font, FontFeatures, FontId, FontMetrics, FontStyle,
FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RasterizedGlyphId, Result, ShapedGlyph,
ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS,
FontWeight, GlyphId, Pixels, PlatformTextSystem, Point, RasterizeGlyphParams, Result,
ShapedGlyph, ShapedLine, ShapedRun, SharedString, Size, SUBPIXEL_VARIANTS,
};
use anyhow::anyhow;
use cocoa::appkit::{CGFloat, CGPoint};
@@ -136,8 +136,8 @@ impl PlatformTextSystem for MacTextSystem {
fn rasterize_glyph(
&self,
glyph_id: &RasterizedGlyphId,
) -> Result<(Bounds<DevicePixels>, Vec<u8>)> {
glyph_id: &RasterizeGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)> {
self.0.read().rasterize_glyph(glyph_id)
}
@@ -232,8 +232,8 @@ impl MacTextSystemState {
fn rasterize_glyph(
&self,
glyph_id: &RasterizedGlyphId,
) -> Result<(Bounds<DevicePixels>, Vec<u8>)> {
glyph_id: &RasterizeGlyphParams,
) -> Result<(Size<DevicePixels>, Vec<u8>)> {
let font = &self.fonts[glyph_id.font_id.0];
let scale = Transform2F::from_scale(glyph_id.scale_factor);
let glyph_bounds = font.raster_bounds(
@@ -252,18 +252,15 @@ impl MacTextSystemState {
glyph_id.subpixel_variant.x.min(1) as i32,
glyph_id.subpixel_variant.y.min(1) as i32,
);
let cx_bounds = RectI::new(
glyph_bounds.origin(),
glyph_bounds.size() + subpixel_padding,
);
let bitmap_size = glyph_bounds.size() + subpixel_padding;
let mut bytes = vec![0; cx_bounds.width() as usize * cx_bounds.height() as usize];
let mut bytes = vec![0; bitmap_size.x() as usize * bitmap_size.y() as usize];
let cx = CGContext::create_bitmap_context(
Some(bytes.as_mut_ptr() as *mut _),
cx_bounds.width() as usize,
cx_bounds.height() as usize,
bitmap_size.x() as usize,
bitmap_size.y() as usize,
8,
cx_bounds.width() as usize,
bitmap_size.x() as usize,
&CGColorSpace::create_device_gray(),
kCGImageAlphaOnly,
);
@@ -298,7 +295,7 @@ impl MacTextSystemState {
cx,
);
Ok((cx_bounds.into(), bytes))
Ok((bitmap_size.into(), bytes))
}
}
@@ -511,14 +508,23 @@ impl From<RectF> for Bounds<f32> {
impl From<RectI> for Bounds<DevicePixels> {
fn from(rect: RectI) -> Self {
Bounds {
origin: point(
DevicePixels(rect.origin_x() as u32),
DevicePixels(rect.origin_y() as u32),
),
size: size(
DevicePixels(rect.width() as u32),
DevicePixels(rect.height() as u32),
),
origin: point(DevicePixels(rect.origin_x()), DevicePixels(rect.origin_y())),
size: size(DevicePixels(rect.width()), DevicePixels(rect.height())),
}
}
}
impl From<Vector2I> for Size<DevicePixels> {
fn from(value: Vector2I) -> Self {
size(value.x().into(), value.y().into())
}
}
impl From<RectI> for Bounds<i32> {
fn from(rect: RectI) -> Self {
Bounds {
origin: point(rect.origin_x(), rect.origin_y()),
size: size(rect.width(), rect.height()),
}
}
}
+3 -3
View File
@@ -3,8 +3,8 @@ use crate::{
point, px, size, AnyWindowHandle, Bounds, Event, KeyDownEvent, Keystroke, MacScreen, Modifiers,
ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMovedEvent, MouseUpEvent, NSRectExt,
Pixels, Platform, PlatformAtlas, PlatformDispatcher, PlatformInputHandler, PlatformScreen,
PlatformWindow, Point, RasterizedGlyphId, Scene, Size, Timer, WindowAppearance, WindowBounds,
WindowKind, WindowOptions, WindowPromptLevel,
PlatformWindow, Point, RasterizeGlyphParams, Scene, Size, Timer, WindowAppearance,
WindowBounds, WindowKind, WindowOptions, WindowPromptLevel,
};
use block::ConcreteBlock;
use cocoa::{
@@ -886,7 +886,7 @@ impl PlatformWindow for MacWindow {
}
}
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas<RasterizedGlyphId>> {
fn glyph_atlas(&self) -> Arc<dyn PlatformAtlas<RasterizeGlyphParams>> {
self.0.lock().renderer.glyph_atlas().clone()
}
}