1390 lines · 48.5 KB · Rust
RawDownload
use crate::{WgpuAtlas, WgpuContext};use bytemuck::{Pod, Zeroable};use gpui::{    AtlasTextureId, Background, Bounds, DevicePixels, GpuSpecs, MonochromeSprite, Path, Point,    PolychromeSprite, PrimitiveBatch, Quad, ScaledPixels, Scene, Shadow, Size, SubpixelSprite,    Underline, get_gamma_correction_ratios,};use raw_window_handle::{HasDisplayHandle, HasWindowHandle};use std::num::NonZeroU64;use std::sync::Arc; #[repr(C)]#[derive(Clone, Copy, Pod, Zeroable)]struct GlobalParams {    viewport_size: [f32; 2],    premultiplied_alpha: u32,    pad: u32,} #[repr(C)]#[derive(Clone, Copy, Pod, Zeroable)]struct PodBounds {    origin: [f32; 2],    size: [f32; 2],} impl From<Bounds<ScaledPixels>> for PodBounds {    fn from(bounds: Bounds<ScaledPixels>) -> Self {        Self {            origin: [bounds.origin.x.0, bounds.origin.y.0],            size: [bounds.size.width.0, bounds.size.height.0],        }    }} #[repr(C)]#[derive(Clone, Copy, Pod, Zeroable)]struct SurfaceParams {    bounds: PodBounds,    content_mask: PodBounds,} #[repr(C)]#[derive(Clone, Copy, Pod, Zeroable)]struct GammaParams {    gamma_ratios: [f32; 4],    grayscale_enhanced_contrast: f32,    subpixel_enhanced_contrast: f32,    _pad: [f32; 2],} #[derive(Clone, Debug)]#[repr(C)]struct PathSprite {    bounds: Bounds<ScaledPixels>,} #[derive(Clone, Debug)]#[repr(C)]struct PathRasterizationVertex {    xy_position: Point<ScaledPixels>,    st_position: Point<f32>,    color: Background,    bounds: Bounds<ScaledPixels>,} pub struct WgpuSurfaceConfig {    pub size: Size<DevicePixels>,    pub transparent: bool,} struct WgpuPipelines {    quads: wgpu::RenderPipeline,    shadows: wgpu::RenderPipeline,    path_rasterization: wgpu::RenderPipeline,    paths: wgpu::RenderPipeline,    underlines: wgpu::RenderPipeline,    mono_sprites: wgpu::RenderPipeline,    subpixel_sprites: Option<wgpu::RenderPipeline>,    poly_sprites: wgpu::RenderPipeline,    #[allow(dead_code)]    surfaces: wgpu::RenderPipeline,} struct WgpuBindGroupLayouts {    globals: wgpu::BindGroupLayout,    instances: wgpu::BindGroupLayout,    instances_with_texture: wgpu::BindGroupLayout,    surfaces: wgpu::BindGroupLayout,} pub struct WgpuRenderer {    device: Arc<wgpu::Device>,    queue: Arc<wgpu::Queue>,    surface: wgpu::Surface<'static>,    surface_config: wgpu::SurfaceConfiguration,    pipelines: WgpuPipelines,    bind_group_layouts: WgpuBindGroupLayouts,    atlas: Arc<WgpuAtlas>,    atlas_sampler: wgpu::Sampler,    globals_buffer: wgpu::Buffer,    path_globals_offset: u64,    gamma_offset: u64,    globals_bind_group: wgpu::BindGroup,    path_globals_bind_group: wgpu::BindGroup,    instance_buffer: wgpu::Buffer,    instance_buffer_capacity: u64,    storage_buffer_alignment: u64,    path_intermediate_texture: wgpu::Texture,    path_intermediate_view: wgpu::TextureView,    path_msaa_texture: Option<wgpu::Texture>,    path_msaa_view: Option<wgpu::TextureView>,    rendering_params: RenderingParameters,    dual_source_blending: bool,    adapter_info: wgpu::AdapterInfo,    transparent_alpha_mode: wgpu::CompositeAlphaMode,    opaque_alpha_mode: wgpu::CompositeAlphaMode,} impl WgpuRenderer {    /// Creates a new WgpuRenderer from raw window handles.    ///    /// # Safety    /// The caller must ensure that the window handle remains valid for the lifetime    /// of the returned renderer.    pub fn new<W: HasWindowHandle + HasDisplayHandle>(        context: &WgpuContext,        window: &W,        config: WgpuSurfaceConfig,    ) -> anyhow::Result<Self> {        let window_handle = window            .window_handle()            .map_err(|e| anyhow::anyhow!("Failed to get window handle: {e}"))?;        let display_handle = window            .display_handle()            .map_err(|e| anyhow::anyhow!("Failed to get display handle: {e}"))?;         let target = wgpu::SurfaceTargetUnsafe::RawHandle {            raw_display_handle: display_handle.as_raw(),            raw_window_handle: window_handle.as_raw(),        };         // Safety: The caller guarantees that the window handle is valid for the        // lifetime of this renderer. In practice, the RawWindow struct is created        // from the native window handles and the surface is dropped before the window.        let surface = unsafe {            context                .instance                .create_surface_unsafe(target)                .map_err(|e| anyhow::anyhow!("Failed to create surface: {e}"))?        };         let surface_caps = surface.get_capabilities(&context.adapter);        // Prefer standard 8-bit non-sRGB formats that don't require special features.        // Other formats like Rgba16Unorm require TEXTURE_FORMAT_16BIT_NORM which may        // not be available on all devices.        let preferred_formats = [            wgpu::TextureFormat::Bgra8Unorm,            wgpu::TextureFormat::Rgba8Unorm,        ];        let surface_format = preferred_formats            .iter()            .find(|f| surface_caps.formats.contains(f))            .copied()            .or_else(|| surface_caps.formats.iter().find(|f| !f.is_srgb()).copied())            .unwrap_or(surface_caps.formats[0]);         let pick_alpha_mode =            |preferences: &[wgpu::CompositeAlphaMode]| -> wgpu::CompositeAlphaMode {                preferences                    .iter()                    .find(|p| surface_caps.alpha_modes.contains(p))                    .copied()                    .unwrap_or(surface_caps.alpha_modes[0])            };         let transparent_alpha_mode = pick_alpha_mode(&[            wgpu::CompositeAlphaMode::PreMultiplied,            wgpu::CompositeAlphaMode::Inherit,        ]);         let opaque_alpha_mode = pick_alpha_mode(&[            wgpu::CompositeAlphaMode::Opaque,            wgpu::CompositeAlphaMode::Inherit,        ]);         let alpha_mode = if config.transparent {            transparent_alpha_mode        } else {            opaque_alpha_mode        };         let surface_config = wgpu::SurfaceConfiguration {            usage: wgpu::TextureUsages::RENDER_ATTACHMENT,            format: surface_format,            width: config.size.width.0 as u32,            height: config.size.height.0 as u32,            present_mode: wgpu::PresentMode::Fifo,            desired_maximum_frame_latency: 2,            alpha_mode,            view_formats: vec![],        };        surface.configure(&context.device, &surface_config);         let device = Arc::clone(&context.device);        let queue = Arc::clone(&context.queue);        let dual_source_blending = context.supports_dual_source_blending();         let rendering_params = RenderingParameters::new(&context.adapter, surface_format);        let bind_group_layouts = Self::create_bind_group_layouts(&device);        let pipelines = Self::create_pipelines(            &device,            &bind_group_layouts,            surface_format,            alpha_mode,            rendering_params.path_sample_count,            dual_source_blending,        );         let atlas = Arc::new(WgpuAtlas::new(Arc::clone(&device), Arc::clone(&queue)));        let atlas_sampler = device.create_sampler(&wgpu::SamplerDescriptor {            label: Some("atlas_sampler"),            mag_filter: wgpu::FilterMode::Linear,            min_filter: wgpu::FilterMode::Linear,            ..Default::default()        });         let uniform_alignment = device.limits().min_uniform_buffer_offset_alignment as u64;        let globals_size = std::mem::size_of::<GlobalParams>() as u64;        let gamma_size = std::mem::size_of::<GammaParams>() as u64;        let path_globals_offset = globals_size.next_multiple_of(uniform_alignment);        let gamma_offset = (path_globals_offset + globals_size).next_multiple_of(uniform_alignment);         let globals_buffer = device.create_buffer(&wgpu::BufferDescriptor {            label: Some("globals_buffer"),            size: gamma_offset + gamma_size,            usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,            mapped_at_creation: false,        });         let storage_buffer_alignment = device.limits().min_storage_buffer_offset_alignment as u64;        let initial_instance_buffer_capacity = 2 * 1024 * 1024;        let instance_buffer = device.create_buffer(&wgpu::BufferDescriptor {            label: Some("instance_buffer"),            size: initial_instance_buffer_capacity,            usage: wgpu::BufferUsages::STORAGE | wgpu::BufferUsages::COPY_DST,            mapped_at_creation: false,        });         let (path_intermediate_texture, path_intermediate_view) = Self::create_path_intermediate(            &device,            surface_format,            config.size.width.0 as u32,            config.size.height.0 as u32,        );         let (path_msaa_texture, path_msaa_view) = Self::create_msaa_if_needed(            &device,            surface_format,            config.size.width.0 as u32,            config.size.height.0 as u32,            rendering_params.path_sample_count,        )        .map(|(t, v)| (Some(t), Some(v)))        .unwrap_or((None, None));         let globals_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {            label: Some("globals_bind_group"),            layout: &bind_group_layouts.globals,            entries: &[                wgpu::BindGroupEntry {                    binding: 0,                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {                        buffer: &globals_buffer,                        offset: 0,                        size: Some(NonZeroU64::new(globals_size).unwrap()),                    }),                },                wgpu::BindGroupEntry {                    binding: 1,                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {                        buffer: &globals_buffer,                        offset: gamma_offset,                        size: Some(NonZeroU64::new(gamma_size).unwrap()),                    }),                },            ],        });         let path_globals_bind_group = device.create_bind_group(&wgpu::BindGroupDescriptor {            label: Some("path_globals_bind_group"),            layout: &bind_group_layouts.globals,            entries: &[                wgpu::BindGroupEntry {                    binding: 0,                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {                        buffer: &globals_buffer,                        offset: path_globals_offset,                        size: Some(NonZeroU64::new(globals_size).unwrap()),                    }),                },                wgpu::BindGroupEntry {                    binding: 1,                    resource: wgpu::BindingResource::Buffer(wgpu::BufferBinding {                        buffer: &globals_buffer,                        offset: gamma_offset,                        size: Some(NonZeroU64::new(gamma_size).unwrap()),                    }),                },            ],        });         let adapter_info = context.adapter.get_info();         Ok(Self {            device,            queue,            surface,            surface_config,            pipelines,            bind_group_layouts,            atlas,            atlas_sampler,            globals_buffer,            path_globals_offset,            gamma_offset,            globals_bind_group,            path_globals_bind_group,            instance_buffer,            instance_buffer_capacity: initial_instance_buffer_capacity,            storage_buffer_alignment,            path_intermediate_texture,            path_intermediate_view,            path_msaa_texture,            path_msaa_view,            rendering_params,            dual_source_blending,            adapter_info,            transparent_alpha_mode,            opaque_alpha_mode,        })    }     fn create_bind_group_layouts(device: &wgpu::Device) -> WgpuBindGroupLayouts {        let globals =            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {                label: Some("globals_layout"),                entries: &[                    wgpu::BindGroupLayoutEntry {                        binding: 0,                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,                        ty: wgpu::BindingType::Buffer {                            ty: wgpu::BufferBindingType::Uniform,                            has_dynamic_offset: false,                            min_binding_size: NonZeroU64::new(                                std::mem::size_of::<GlobalParams>() as u64                            ),                        },                        count: None,                    },                    wgpu::BindGroupLayoutEntry {                        binding: 1,                        visibility: wgpu::ShaderStages::FRAGMENT,                        ty: wgpu::BindingType::Buffer {                            ty: wgpu::BufferBindingType::Uniform,                            has_dynamic_offset: false,                            min_binding_size: NonZeroU64::new(                                std::mem::size_of::<GammaParams>() as u64                            ),                        },                        count: None,                    },                ],            });         let storage_buffer_entry = |binding: u32| wgpu::BindGroupLayoutEntry {            binding,            visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,            ty: wgpu::BindingType::Buffer {                ty: wgpu::BufferBindingType::Storage { read_only: true },                has_dynamic_offset: false,                min_binding_size: None,            },            count: None,        };         let instances = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {            label: Some("instances_layout"),            entries: &[storage_buffer_entry(0)],        });         let instances_with_texture =            device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {                label: Some("instances_with_texture_layout"),                entries: &[                    storage_buffer_entry(0),                    wgpu::BindGroupLayoutEntry {                        binding: 1,                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,                        ty: wgpu::BindingType::Texture {                            sample_type: wgpu::TextureSampleType::Float { filterable: true },                            view_dimension: wgpu::TextureViewDimension::D2,                            multisampled: false,                        },                        count: None,                    },                    wgpu::BindGroupLayoutEntry {                        binding: 2,                        visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,                        ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),                        count: None,                    },                ],            });         let surfaces = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {            label: Some("surfaces_layout"),            entries: &[                wgpu::BindGroupLayoutEntry {                    binding: 0,                    visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,                    ty: wgpu::BindingType::Buffer {                        ty: wgpu::BufferBindingType::Uniform,                        has_dynamic_offset: false,                        min_binding_size: NonZeroU64::new(                            std::mem::size_of::<SurfaceParams>() as u64                        ),                    },                    count: None,                },                wgpu::BindGroupLayoutEntry {                    binding: 1,                    visibility: wgpu::ShaderStages::FRAGMENT,                    ty: wgpu::BindingType::Texture {                        sample_type: wgpu::TextureSampleType::Float { filterable: true },                        view_dimension: wgpu::TextureViewDimension::D2,                        multisampled: false,                    },                    count: None,                },                wgpu::BindGroupLayoutEntry {                    binding: 2,                    visibility: wgpu::ShaderStages::FRAGMENT,                    ty: wgpu::BindingType::Texture {                        sample_type: wgpu::TextureSampleType::Float { filterable: true },                        view_dimension: wgpu::TextureViewDimension::D2,                        multisampled: false,                    },                    count: None,                },                wgpu::BindGroupLayoutEntry {                    binding: 3,                    visibility: wgpu::ShaderStages::FRAGMENT,                    ty: wgpu::BindingType::Sampler(wgpu::SamplerBindingType::Filtering),                    count: None,                },            ],        });         WgpuBindGroupLayouts {            globals,            instances,            instances_with_texture,            surfaces,        }    }     fn create_pipelines(        device: &wgpu::Device,        layouts: &WgpuBindGroupLayouts,        surface_format: wgpu::TextureFormat,        alpha_mode: wgpu::CompositeAlphaMode,        path_sample_count: u32,        dual_source_blending: bool,    ) -> WgpuPipelines {        let shader_source = include_str!("shaders.wgsl");        let shader_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {            label: Some("gpui_shaders"),            source: wgpu::ShaderSource::Wgsl(shader_source.into()),        });         let blend_mode = match alpha_mode {            wgpu::CompositeAlphaMode::PreMultiplied => {                wgpu::BlendState::PREMULTIPLIED_ALPHA_BLENDING            }            _ => wgpu::BlendState::ALPHA_BLENDING,        };         let color_target = wgpu::ColorTargetState {            format: surface_format,            blend: Some(blend_mode),            write_mask: wgpu::ColorWrites::ALL,        };         let create_pipeline = |name: &str,                               vs_entry: &str,                               fs_entry: &str,                               globals_layout: &wgpu::BindGroupLayout,                               data_layout: &wgpu::BindGroupLayout,                               topology: wgpu::PrimitiveTopology,

Lines 1–500 of 1390.