From 247afa166654a178f1ec03007360994d84a31912 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 23 Mar 2021 09:13:35 -0600 Subject: [PATCH] WIP --- gpui/src/platform/mac/renderer.rs | 49 +++++++++++------ gpui/src/platform/mac/shaders/shaders.h | 4 +- gpui/src/platform/mac/sprite_cache.rs | 72 ++++++++++++++++++++++--- gpui/src/platform/mac/window.rs | 2 +- 4 files changed, 101 insertions(+), 26 deletions(-) diff --git a/gpui/src/platform/mac/renderer.rs b/gpui/src/platform/mac/renderer.rs index a741f5fb869fe6815d7235fb04588c62eab905ef..ad01acca7b9858b3101eceaa6983fefc044da998 100644 --- a/gpui/src/platform/mac/renderer.rs +++ b/gpui/src/platform/mac/renderer.rs @@ -1,28 +1,31 @@ -use std::{collections::HashMap, ffi::c_void, mem}; - -use self::shaders::ToUchar4; - -use super::window::RenderContext; -use crate::{color::ColorU, scene::Layer, Scene}; +use super::{sprite_cache::SpriteCache, window::RenderContext}; +use crate::{ + color::ColorU, + geometry::vector::{vec2i, Vector2I}, + scene::Layer, + Scene, +}; use anyhow::{anyhow, Result}; use metal::{MTLResourceOptions, NSRange}; -use shaders::ToFloat2 as _; +use shaders::{ToFloat2 as _, ToUchar4 as _, ToUint2 as _}; +use std::{collections::HashMap, ffi::c_void, mem}; const SHADERS_METALLIB: &'static [u8] = include_bytes!(concat!(env!("OUT_DIR"), "/shaders.metallib")); const INSTANCE_BUFFER_SIZE: usize = 1024 * 1024; // This is an arbitrary decision. There's probably a more optimal value. +const ATLAS_SIZE: Vector2I = vec2i(1024, 768); pub struct Renderer { + sprite_cache: SpriteCache, quad_pipeline_state: metal::RenderPipelineState, shadow_pipeline_state: metal::RenderPipelineState, sprite_pipeline_state: metal::RenderPipelineState, unit_vertices: metal::Buffer, instances: metal::Buffer, - sprite_cache: SpriteCache, } impl Renderer { - pub fn new(device: &metal::DeviceRef, pixel_format: metal::MTLPixelFormat) -> Result { + pub fn new(device: metal::Device, pixel_format: metal::MTLPixelFormat) -> Result { let library = device .new_library_with_data(SHADERS_METALLIB) .map_err(|message| anyhow!("error building metal library: {}", message))?; @@ -46,8 +49,9 @@ impl Renderer { ); Ok(Self { + sprite_cache: SpriteCache::new(device, ATLAS_SIZE), quad_pipeline_state: build_pipeline_state( - device, + &device, &library, "quad", "quad_vertex", @@ -55,7 +59,7 @@ impl Renderer { pixel_format, )?, shadow_pipeline_state: build_pipeline_state( - device, + &device, &library, "shadow", "shadow_vertex", @@ -63,7 +67,7 @@ impl Renderer { pixel_format, )?, sprite_pipeline_state: build_pipeline_state( - device, + &device, &library, "sprite", "sprite_vertex", @@ -268,14 +272,14 @@ impl Renderer { for glyph in layer.glyphs() { let (atlas, bounds) = self.sprite_cache - .rasterize_glyph(glyph.font_id, glyph.font_size, glyph.glyph_id); + .render_glyph(glyph.font_id, glyph.font_size, glyph.glyph_id); sprites .entry(atlas) .or_insert_with(Vec::new) .push(shaders::GPUISprite { origin: glyph.origin.to_float2(), - size: bounds.size().to_float2(), - atlas_origin: bounds.origin().to_float2(), + size: bounds.size().to_uint2(), + atlas_origin: bounds.origin().to_uint2(), color: glyph.color.to_uchar4(), }); } @@ -358,6 +362,8 @@ mod shaders { #![allow(non_camel_case_types)] #![allow(non_snake_case)] + use pathfinder_geometry::vector::Vector2I; + use crate::{color::ColorU, geometry::vector::Vector2F}; use std::mem; @@ -371,6 +377,10 @@ mod shaders { fn to_uchar4(&self) -> vector_uchar4; } + pub trait ToUint2 { + fn to_uint2(&self) -> vector_uint2; + } + impl ToFloat2 for (f32, f32) { fn to_float2(&self) -> vector_float2 { unsafe { @@ -405,4 +415,13 @@ mod shaders { vec } } + + impl ToUint2 for Vector2I { + fn to_uint2(&self) -> vector_uint2 { + let mut output = self.y() as vector_uint2; + output <<= 32; + output |= self.x() as vector_uint2; + output + } + } } diff --git a/gpui/src/platform/mac/shaders/shaders.h b/gpui/src/platform/mac/shaders/shaders.h index 50f6d52f1db9d3990eaf0c2726e521993188a135..44bbf07220fff2797fa3c363238ea40d17ead124 100644 --- a/gpui/src/platform/mac/shaders/shaders.h +++ b/gpui/src/platform/mac/shaders/shaders.h @@ -44,7 +44,7 @@ typedef enum { typedef struct { vector_float2 origin; - vector_float2 size; - vector_float2 atlas_origin; + vector_uint2 size; + vector_uint2 atlas_origin; vector_uchar4 color; } GPUISprite; diff --git a/gpui/src/platform/mac/sprite_cache.rs b/gpui/src/platform/mac/sprite_cache.rs index 8745aae4ee795298e4a65fd535cf2ff8754a7b1a..186f0eb1984bc522b9cff3296a4cdae3062ea718 100644 --- a/gpui/src/platform/mac/sprite_cache.rs +++ b/gpui/src/platform/mac/sprite_cache.rs @@ -1,19 +1,75 @@ -use crate::geometry::vector::Vector2I; +use std::{collections::HashMap, sync::Arc}; + +use crate::{ + fonts::{FontId, GlyphId}, + geometry::{rect::RectI, vector::Vector2I}, + FontCache, +}; use etagere::BucketedAtlasAllocator; +use metal::{MTLPixelFormat, TextureDescriptor}; +use ordered_float::OrderedFloat; + +#[derive(Hash, Eq, PartialEq)] +struct GlyphDescriptor { + font_id: FontId, + font_size: OrderedFloat, + glyph_id: GlyphId, +} -struct SpriteCache { - atlasses: Vec, +pub struct SpriteCache { + font_cache: Arc, + device: metal::Device, + size: Vector2I, + atlasses: Vec, + glyphs: HashMap, } impl SpriteCache { - fn new(size: Vector2I) -> Self { - let size = etagere::Size::new(size.x(), size.y()); + pub fn new(device: metal::Device, size: Vector2I) -> Self { Self { - atlasses: vec![BucketedAtlasAllocator::new(size)], + device, + size, + atlasses: vec![Atlas::new(&device, size)], + glyphs: Default::default(), } } - fn render_glyph(&mut self) { - self.atlasses.last().unwrap() + pub fn render_glyph( + &mut self, + font_id: FontId, + font_size: f32, + glyph_id: GlyphId, + ) -> (usize, RectI) { + self.glyphs + .entry(GlyphDescriptor { + font_id, + font_size: OrderedFloat(font_size), + glyph_id, + }) + .or_insert_with(|| { + let rendered_glyph = self.font_cache.render_glyph(font_id, font_size, glyph_id); + // let atlas = self.atlasses.last_mut().unwrap(); + todo!() + }) + .clone() + } +} + +struct Atlas { + allocator: BucketedAtlasAllocator, + texture: metal::Texture, +} + +impl Atlas { + fn new(device: &metal::DeviceRef, size: Vector2I) -> Self { + let descriptor = TextureDescriptor::new(); + descriptor.set_pixel_format(MTLPixelFormat::A8Unorm); + descriptor.set_width(size.x() as u64); + descriptor.set_height(size.y() as u64); + + Self { + allocator: BucketedAtlasAllocator::new(etagere::Size::new(size.x(), size.y())), + texture: device.new_texture(&descriptor), + } } } diff --git a/gpui/src/platform/mac/window.rs b/gpui/src/platform/mac/window.rs index d41694784db6c49723bb1ac4b6013b55523e4279..3ccc8d3eb3940d2a1f3f61e48ad703d1e109bcf4 100644 --- a/gpui/src/platform/mac/window.rs +++ b/gpui/src/platform/mac/window.rs @@ -192,7 +192,7 @@ impl Window { synthetic_drag_counter: 0, executor, scene_to_render: Default::default(), - renderer: Renderer::new(&device, PIXEL_FORMAT)?, + renderer: Renderer::new(device, PIXEL_FORMAT)?, command_queue: device.new_command_queue(), device, layer,