diff --git a/gpui/src/platform/mac/atlas.rs b/gpui/src/platform/mac/atlas.rs index ecc2ddb6bf..dd2b837dfb 100644 --- a/gpui/src/platform/mac/atlas.rs +++ b/gpui/src/platform/mac/atlas.rs @@ -13,17 +13,18 @@ pub struct AtlasAllocator { impl AtlasAllocator { pub fn new(device: Device, texture_descriptor: TextureDescriptor) -> Self { - let me = Self { + let mut me = Self { device, texture_descriptor, atlasses: Vec::new(), free_atlasses: Vec::new(), }; - me.atlasses.push(me.new_atlas()); + let atlas = me.new_atlas(); + me.atlasses.push(atlas); me } - fn atlas_size(&self) -> Vector2I { + pub fn atlas_size(&self) -> Vector2I { vec2i( self.texture_descriptor.width() as i32, self.texture_descriptor.height() as i32, @@ -62,6 +63,10 @@ impl AtlasAllocator { self.free_atlasses.extend(self.atlasses.drain(1..)); } + pub fn texture(&self, atlas_id: usize) -> Option<&metal::TextureRef> { + self.atlasses.get(atlas_id).map(|a| a.texture.as_ref()) + } + fn new_atlas(&mut self) -> Atlas { self.free_atlasses.pop().unwrap_or_else(|| { Atlas::new( diff --git a/gpui/src/platform/mac/renderer.rs b/gpui/src/platform/mac/renderer.rs index 9829a7d0c3..cfd42228d9 100644 --- a/gpui/src/platform/mac/renderer.rs +++ b/gpui/src/platform/mac/renderer.rs @@ -21,7 +21,6 @@ const INSTANCE_BUFFER_SIZE: usize = 1024 * 1024; // This is an arbitrary decisio pub struct Renderer { device: metal::Device, - command_buffer: metal::CommandBuffer, sprite_cache: SpriteCache, path_stencils: AtlasAllocator, quad_pipeline_state: metal::RenderPipelineState, @@ -41,7 +40,6 @@ struct PathSprite { impl Renderer { pub fn new( device: metal::Device, - command_buffer: metal::CommandBuffer, pixel_format: metal::MTLPixelFormat, fonts: Arc, ) -> Result { @@ -75,52 +73,63 @@ impl Renderer { path_stencil_descriptor.set_usage(metal::MTLTextureUsage::RenderTarget); path_stencil_descriptor.set_storage_mode(metal::MTLStorageMode::Private); + let sprite_cache = SpriteCache::new(device.clone(), vec2i(1024, 768), fonts); + let path_stencils = AtlasAllocator::new(device.clone(), path_stencil_descriptor); + let quad_pipeline_state = build_pipeline_state( + &device, + &library, + "quad", + "quad_vertex", + "quad_fragment", + pixel_format, + )?; + let shadow_pipeline_state = build_pipeline_state( + &device, + &library, + "shadow", + "shadow_vertex", + "shadow_fragment", + pixel_format, + )?; + let sprite_pipeline_state = build_pipeline_state( + &device, + &library, + "sprite", + "sprite_vertex", + "sprite_fragment", + pixel_format, + )?; + let path_stencil_pipeline_state = build_stencil_pipeline_state( + &device, + &library, + "path_winding", + "path_winding_vertex", + "path_winding_fragment", + path_stencil_pixel_format, + )?; Ok(Self { device, - command_buffer, - sprite_cache: SpriteCache::new(device.clone(), vec2i(1024, 768), fonts), - path_stencils: AtlasAllocator::new(device.clone(), path_stencil_descriptor), - quad_pipeline_state: build_pipeline_state( - &device, - &library, - "quad", - "quad_vertex", - "quad_fragment", - pixel_format, - )?, - shadow_pipeline_state: build_pipeline_state( - &device, - &library, - "shadow", - "shadow_vertex", - "shadow_fragment", - pixel_format, - )?, - sprite_pipeline_state: build_pipeline_state( - &device, - &library, - "sprite", - "sprite_vertex", - "sprite_fragment", - pixel_format, - )?, - path_stencil_pipeline_state: build_stencil_pipeline_state( - &device, - &library, - "path_winding", - "path_winding_vertex", - "path_winding_fragment", - path_stencil_pixel_format, - )?, + sprite_cache, + path_stencils, + quad_pipeline_state, + shadow_pipeline_state, + sprite_pipeline_state, + path_stencil_pipeline_state, unit_vertices, instances, }) } - pub fn render(&mut self, scene: &Scene, drawable_size: Vector2F, output: &metal::TextureRef) { + pub fn render( + &mut self, + scene: &Scene, + drawable_size: Vector2F, + command_buffer: &metal::CommandBufferRef, + output: &metal::TextureRef, + ) { let mut offset = 0; - self.render_path_stencils(scene, &mut offset, drawable_size); - self.render_layers(scene, &mut offset, drawable_size, output); + self.render_path_stencils(scene, &mut offset, drawable_size, command_buffer); + self.render_layers(scene, &mut offset, drawable_size, command_buffer, output); } fn render_path_stencils( @@ -128,6 +137,7 @@ impl Renderer { scene: &Scene, offset: &mut usize, drawable_size: Vector2F, + command_buffer: &metal::CommandBufferRef, ) -> Vec { let mut stencils = Vec::new(); let mut vertices = Vec::::new(); @@ -150,11 +160,10 @@ impl Renderer { if current_atlas_id.map_or(false, |current_atlas_id| atlas_id != current_atlas_id) { self.render_path_stencils_for_atlas( - scene, offset, - drawable_size, - vertices.as_slice(), - self.path_stencils.texture(atlas_id).unwrap(), + &vertices, + atlas_id, + command_buffer, ); vertices.clear(); } @@ -163,19 +172,19 @@ impl Renderer { // Populate the vertices by translating them to their appropriate location in the atlas. for vertex in &path.vertices { - vertices.push(todo!()); + let xy_position = (vertex.xy_position - path.bounds.origin()) + * scene.scale_factor() + + atlas_origin.to_f32(); + vertices.push(shaders::GPUIPathVertex { + xy_position: xy_position.to_float2(), + st_position: vertex.st_position.to_float2(), + }); } } } if let Some(atlas_id) = current_atlas_id { - self.render_path_stencils_for_atlas( - scene, - offset, - drawable_size, - vertices.as_slice(), - self.path_stencils.texture(atlas_id).unwrap(), - ); + self.render_path_stencils_for_atlas(offset, &vertices, atlas_id, command_buffer); } stencils @@ -183,66 +192,73 @@ impl Renderer { fn render_path_stencils_for_atlas( &mut self, - scene: &Scene, offset: &mut usize, - drawable_size: Vector2F, vertices: &[shaders::GPUIPathVertex], - texture: &metal::TextureRef, + atlas_id: usize, + command_buffer: &metal::CommandBufferRef, ) { - // let render_pass_descriptor = metal::RenderPassDescriptor::new(); - // let stencil_attachment = render_pass_descriptor.stencil_attachment().unwrap(); - // stencil_attachment.set_texture(Some(&self.path_winding_texture)); - // stencil_attachment.set_load_action(metal::MTLLoadAction::Clear); - // stencil_attachment.set_store_action(metal::MTLStoreAction::Store); - // let winding_command_encoder = self - // .command_buffer - // .new_render_command_encoder(render_pass_descriptor); + align_offset(offset); + let next_offset = *offset + vertices.len() * mem::size_of::(); + assert!( + next_offset <= INSTANCE_BUFFER_SIZE, + "instance buffer exhausted" + ); - // Dubious shit that may be valuable: + let render_pass_descriptor = metal::RenderPassDescriptor::new(); - // for path in scene.paths() { - // winding_command_encoder.set_render_pipeline_state(&self.path_stencil_pipeline_state); - // winding_command_encoder.set_vertex_buffer( - // shaders::GPUIPathWindingVertexInputIndex_GPUIPathWindingVertexInputIndexVertices - // as u64, - // Some(&self.instances), - // *offset as u64, - // ); - // winding_command_encoder.set_vertex_bytes( - // shaders::GPUIPathWindingVertexInputIndex_GPUIPathWindingVertexInputIndexViewportSize - // as u64, - // mem::size_of::() as u64, - // [drawable_size.to_float2()].as_ptr() as *const c_void, - // ); + let stencil_attachment = render_pass_descriptor.stencil_attachment().unwrap(); + let stencil_texture = self.path_stencils.texture(atlas_id).unwrap(); + stencil_attachment.set_texture(Some(stencil_texture)); + stencil_attachment.set_load_action(metal::MTLLoadAction::Clear); + stencil_attachment.set_store_action(metal::MTLStoreAction::Store); - // let buffer_contents = unsafe { - // (self.instances.contents() as *mut u8).offset(*offset as isize) - // as *mut shaders::GPUIPathVertex - // }; + let stencil_descriptor = metal::DepthStencilDescriptor::new(); + let front_face_stencil = stencil_descriptor.front_face_stencil().unwrap(); + front_face_stencil.set_depth_stencil_pass_operation(metal::MTLStencilOperation::Invert); + front_face_stencil.set_depth_failure_operation(metal::MTLStencilOperation::Keep); + front_face_stencil.set_stencil_compare_function(metal::MTLCompareFunction::Always); + front_face_stencil.set_read_mask(0x1); + front_face_stencil.set_write_mask(0x1); + let depth_stencil_state = self.device.new_depth_stencil_state(&stencil_descriptor); - // for (ix, vertex) in paths.iter().flat_map(|p| &p.vertices).enumerate() { - // let shader_vertex = shaders::GPUIPathVertex { - // xy_position: vertex.xy_position.to_float2(), - // st_position: vertex.st_position.to_float2(), - // }; - // unsafe { - // *(buffer_contents.offset(ix as isize)) = shader_vertex; - // } - // } + let winding_command_encoder = + command_buffer.new_render_command_encoder(render_pass_descriptor); + winding_command_encoder.set_depth_stencil_state(&depth_stencil_state); + winding_command_encoder.set_render_pipeline_state(&self.path_stencil_pipeline_state); + winding_command_encoder.set_vertex_buffer( + shaders::GPUIPathWindingVertexInputIndex_GPUIPathWindingVertexInputIndexVertices as u64, + Some(&self.instances), + *offset as u64, + ); + winding_command_encoder.set_vertex_bytes( + shaders::GPUIPathWindingVertexInputIndex_GPUIPathWindingVertexInputIndexAtlasSize + as u64, + mem::size_of::() as u64, + [self.path_stencils.atlas_size().to_float2()].as_ptr() as *const c_void, + ); - // self.instances.did_modify_range(NSRange { - // location: *offset as u64, - // length: (next_offset - *offset) as u64, - // }); - // *offset = next_offset; + let buffer_contents = unsafe { + (self.instances.contents() as *mut u8).add(*offset) as *mut shaders::GPUIPathVertex + }; - // winding_command_encoder.draw_primitives( - // metal::MTLPrimitiveType::Triangle, - // 0, - // vertex_count as u64, - // ); - // winding_command_encoder.end_encoding(); - // } + for (ix, vertex) in vertices.iter().enumerate() { + unsafe { + *buffer_contents.add(ix) = *vertex; + } + } + + self.instances.did_modify_range(NSRange { + location: *offset as u64, + length: (next_offset - *offset) as u64, + }); + *offset = next_offset; + + winding_command_encoder.draw_primitives( + metal::MTLPrimitiveType::Triangle, + 0, + vertices.len() as u64, + ); + winding_command_encoder.end_encoding(); } fn render_layers( @@ -250,6 +266,7 @@ impl Renderer { scene: &Scene, offset: &mut usize, drawable_size: Vector2F, + command_buffer: &metal::CommandBufferRef, output: &metal::TextureRef, ) { let render_pass_descriptor = metal::RenderPassDescriptor::new(); @@ -261,9 +278,7 @@ impl Renderer { color_attachment.set_load_action(metal::MTLLoadAction::Clear); color_attachment.set_store_action(metal::MTLStoreAction::Store); color_attachment.set_clear_color(metal::MTLClearColor::new(0., 0., 0., 1.)); - let command_encoder = self - .command_buffer - .new_render_command_encoder(render_pass_descriptor); + let command_encoder = command_buffer.new_render_command_encoder(render_pass_descriptor); command_encoder.set_viewport(metal::MTLViewport { originX: 0.0, @@ -276,9 +291,9 @@ impl Renderer { for layer in scene.layers() { self.clip(scene, layer, drawable_size, command_encoder); - self.render_shadows(scene, layer, &mut offset, drawable_size, command_encoder); - self.render_quads(scene, layer, &mut offset, drawable_size, command_encoder); - self.render_sprites(scene, layer, &mut offset, drawable_size, command_encoder); + self.render_shadows(scene, layer, offset, drawable_size, command_encoder); + self.render_quads(scene, layer, offset, drawable_size, command_encoder); + self.render_sprites(scene, layer, offset, drawable_size, command_encoder); } command_encoder.end_encoding(); diff --git a/gpui/src/platform/mac/shaders/shaders.h b/gpui/src/platform/mac/shaders/shaders.h index 74883948bb..dd0ae6b2e8 100644 --- a/gpui/src/platform/mac/shaders/shaders.h +++ b/gpui/src/platform/mac/shaders/shaders.h @@ -56,7 +56,7 @@ typedef struct { typedef enum { GPUIPathWindingVertexInputIndexVertices = 0, - GPUIPathWindingVertexInputIndexViewportSize = 1, + GPUIPathWindingVertexInputIndexAtlasSize = 1, } GPUIPathWindingVertexInputIndex; typedef struct { diff --git a/gpui/src/platform/mac/shaders/shaders.metal b/gpui/src/platform/mac/shaders/shaders.metal index fec7e09106..b79cccb949 100644 --- a/gpui/src/platform/mac/shaders/shaders.metal +++ b/gpui/src/platform/mac/shaders/shaders.metal @@ -210,10 +210,10 @@ struct PathWindingFragmentInput { vertex PathWindingFragmentInput path_winding_vertex( uint vertex_id [[vertex_id]], constant GPUIPathVertex *vertices [[buffer(GPUIPathWindingVertexInputIndexVertices)]], - constant float2 *viewport_size [[buffer(GPUIPathWindingVertexInputIndexViewportSize)]] + constant float2 *atlas_size [[buffer(GPUIPathWindingVertexInputIndexAtlasSize)]] ) { GPUIPathVertex v = vertices[vertex_id]; - float4 device_position = to_device_position(v.xy_position, *viewport_size); + float4 device_position = to_device_position(v.xy_position, *atlas_size); return PathWindingFragmentInput { device_position, v.st_position, @@ -223,9 +223,9 @@ vertex PathWindingFragmentInput path_winding_vertex( fragment float4 path_winding_fragment( PathWindingFragmentInput input [[stage_in]] ) { - if (input.st_position.x * input.st_position.x - input.st_position.y > 0.0) { - return float4(0.0); + if (input.st_position.x * input.st_position.x - input.st_position.y > 0.) { + return float4(0.); } else { - return float4(float3(0.0), 1.0 / 255.0); + return float4(1.); } -} \ No newline at end of file +} diff --git a/gpui/src/platform/mac/window.rs b/gpui/src/platform/mac/window.rs index 28a1c04060..0ed1abc212 100644 --- a/gpui/src/platform/mac/window.rs +++ b/gpui/src/platform/mac/window.rs @@ -431,7 +431,6 @@ extern "C" fn display_layer(this: &Object, _: Sel, _: id) { window_state.renderer.render( &scene, size * scale_factor, - &device, command_buffer, drawable.texture(), ); diff --git a/zed/src/editor/buffer_element.rs b/zed/src/editor/buffer_element.rs index 53deb39568..506695f4b7 100644 --- a/zed/src/editor/buffer_element.rs +++ b/zed/src/editor/buffer_element.rs @@ -637,7 +637,7 @@ impl Selection { ); path.line_to(vec2f(first_line.end_x - corner_radius, start_y)); - scene.push_path(ColorU::from_u32(0xff0000ff), path.build()); + scene.push_path(path.build(ColorU::from_u32(0xff0000ff))); // rounded_corner(&mut path, corner, corner_radius, Right, Down);