Support sharing Pipeline state between TextAtlas (#95)

* Support sharing `Pipeline` state between `TextAtlas`

* Keep using `Vec` for pipeline cache

* Use `OnceCell` to keep `Pipeline` private

* Revert "Use `OnceCell` to keep `Pipeline` private"

This reverts commit 4112732b1734a3bb6b915d2103e699ef549b77c1.

* Rename `Pipeline` type to `Cache`
This commit is contained in:
Héctor Ramón 2024-05-08 15:39:19 +02:00 committed by GitHub
parent 670140e2a1
commit 5aed9e1477
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 295 additions and 237 deletions

View file

@ -1,6 +1,6 @@
use glyphon::{ use glyphon::{
Attrs, Buffer, Color, Family, FontSystem, Metrics, Resolution, Shaping, SwashCache, TextArea, Attrs, Buffer, Cache, Color, Family, FontSystem, Metrics, Resolution, Shaping, SwashCache,
TextAtlas, TextBounds, TextRenderer, TextArea, TextAtlas, TextBounds, TextRenderer,
}; };
use wgpu::{ use wgpu::{
CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance, CommandEncoderDescriptor, CompositeAlphaMode, DeviceDescriptor, Features, Instance,
@ -71,8 +71,9 @@ async fn run() {
// Set up text renderer // Set up text renderer
let mut font_system = FontSystem::new(); let mut font_system = FontSystem::new();
let mut cache = SwashCache::new(); let mut swash_cache = SwashCache::new();
let mut atlas = TextAtlas::new(&device, &queue, swapchain_format); let cache = Cache::new(&device);
let mut atlas = TextAtlas::new(&device, &queue, &cache, swapchain_format);
let mut text_renderer = let mut text_renderer =
TextRenderer::new(&mut atlas, &device, MultisampleState::default(), None); TextRenderer::new(&mut atlas, &device, MultisampleState::default(), None);
let mut buffer = Buffer::new(&mut font_system, Metrics::new(30.0, 42.0)); let mut buffer = Buffer::new(&mut font_system, Metrics::new(30.0, 42.0));
@ -122,7 +123,7 @@ async fn run() {
}, },
default_color: Color::rgb(255, 255, 255), default_color: Color::rgb(255, 255, 255),
}], }],
&mut cache, &mut swash_cache,
) )
.unwrap(); .unwrap();

247
src/cache.rs Normal file
View file

@ -0,0 +1,247 @@
use crate::{GlyphToRender, Params};
use wgpu::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutEntry,
BindingResource, BindingType, BlendState, Buffer, BufferBindingType, ColorTargetState,
ColorWrites, DepthStencilState, Device, FilterMode, FragmentState, MultisampleState,
PipelineCompilationOptions, PipelineLayout, PipelineLayoutDescriptor, PrimitiveState,
RenderPipeline, RenderPipelineDescriptor, Sampler, SamplerBindingType, SamplerDescriptor,
ShaderModule, ShaderModuleDescriptor, ShaderSource, ShaderStages, TextureFormat,
TextureSampleType, TextureView, TextureViewDimension, VertexFormat, VertexState,
};
use std::borrow::Cow;
use std::mem;
use std::num::NonZeroU64;
use std::ops::Deref;
use std::sync::{Arc, RwLock};
#[derive(Debug, Clone)]
pub struct Cache(Arc<Inner>);
#[derive(Debug)]
struct Inner {
sampler: Sampler,
shader: ShaderModule,
vertex_buffers: [wgpu::VertexBufferLayout<'static>; 1],
atlas_layout: BindGroupLayout,
uniforms_layout: BindGroupLayout,
pipeline_layout: PipelineLayout,
cache: RwLock<
Vec<(
TextureFormat,
MultisampleState,
Option<DepthStencilState>,
Arc<RenderPipeline>,
)>,
>,
}
impl Cache {
pub fn new(device: &Device) -> Self {
let sampler = device.create_sampler(&SamplerDescriptor {
label: Some("glyphon sampler"),
min_filter: FilterMode::Nearest,
mag_filter: FilterMode::Nearest,
mipmap_filter: FilterMode::Nearest,
lod_min_clamp: 0f32,
lod_max_clamp: 0f32,
..Default::default()
});
let shader = device.create_shader_module(ShaderModuleDescriptor {
label: Some("glyphon shader"),
source: ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
});
let vertex_buffer_layout = wgpu::VertexBufferLayout {
array_stride: mem::size_of::<GlyphToRender>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
format: VertexFormat::Sint32x2,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: mem::size_of::<u32>() as u64 * 2,
shader_location: 1,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: mem::size_of::<u32>() as u64 * 3,
shader_location: 2,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: mem::size_of::<u32>() as u64 * 4,
shader_location: 3,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: mem::size_of::<u32>() as u64 * 5,
shader_location: 4,
},
wgpu::VertexAttribute {
format: VertexFormat::Float32,
offset: mem::size_of::<u32>() as u64 * 6,
shader_location: 5,
},
],
};
let atlas_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled: false,
view_dimension: TextureViewDimension::D2,
sample_type: TextureSampleType::Float { filterable: true },
},
count: None,
},
BindGroupLayoutEntry {
binding: 1,
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled: false,
view_dimension: TextureViewDimension::D2,
sample_type: TextureSampleType::Float { filterable: true },
},
count: None,
},
BindGroupLayoutEntry {
binding: 2,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
],
label: Some("glyphon atlas bind group layout"),
});
let uniforms_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::VERTEX,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: NonZeroU64::new(mem::size_of::<Params>() as u64),
},
count: None,
}],
label: Some("glyphon uniforms bind group layout"),
});
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[&atlas_layout, &uniforms_layout],
push_constant_ranges: &[],
});
Self(Arc::new(Inner {
sampler,
shader,
vertex_buffers: [vertex_buffer_layout],
uniforms_layout,
atlas_layout,
pipeline_layout,
cache: RwLock::new(Vec::new()),
}))
}
pub(crate) fn create_atlas_bind_group(
&self,
device: &Device,
color_atlas: &TextureView,
mask_atlas: &TextureView,
) -> BindGroup {
device.create_bind_group(&BindGroupDescriptor {
layout: &self.0.atlas_layout,
entries: &[
BindGroupEntry {
binding: 0,
resource: BindingResource::TextureView(color_atlas),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::TextureView(mask_atlas),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::Sampler(&self.0.sampler),
},
],
label: Some("glyphon atlas bind group"),
})
}
pub(crate) fn create_uniforms_bind_group(&self, device: &Device, buffer: &Buffer) -> BindGroup {
device.create_bind_group(&BindGroupDescriptor {
layout: &self.0.uniforms_layout,
entries: &[BindGroupEntry {
binding: 0,
resource: buffer.as_entire_binding(),
}],
label: Some("glyphon uniforms bind group"),
})
}
pub(crate) fn get_or_create_pipeline(
&self,
device: &Device,
format: TextureFormat,
multisample: MultisampleState,
depth_stencil: Option<DepthStencilState>,
) -> Arc<RenderPipeline> {
let Inner {
cache,
pipeline_layout,
shader,
vertex_buffers,
..
} = self.0.deref();
let mut cache = cache.write().expect("Write pipeline cache");
cache
.iter()
.find(|(fmt, ms, ds, _)| fmt == &format && ms == &multisample && ds == &depth_stencil)
.map(|(_, _, _, p)| Arc::clone(p))
.unwrap_or_else(|| {
let pipeline = Arc::new(device.create_render_pipeline(&RenderPipelineDescriptor {
label: Some("glyphon pipeline"),
layout: Some(pipeline_layout),
vertex: VertexState {
module: shader,
entry_point: "vs_main",
buffers: vertex_buffers,
compilation_options: PipelineCompilationOptions::default(),
},
fragment: Some(FragmentState {
module: shader,
entry_point: "fs_main",
targets: &[Some(ColorTargetState {
format,
blend: Some(BlendState::ALPHA_BLENDING),
write_mask: ColorWrites::default(),
})],
compilation_options: PipelineCompilationOptions::default(),
}),
primitive: PrimitiveState::default(),
depth_stencil: depth_stencil.clone(),
multisample,
multiview: None,
}));
cache.push((format, multisample, depth_stencil, pipeline.clone()));
pipeline
})
.clone()
}
}

View file

@ -4,10 +4,12 @@
//! [cosmic-text]: https://github.com/pop-os/cosmic-text //! [cosmic-text]: https://github.com/pop-os/cosmic-text
//! [etagere]: https://github.com/nical/etagere //! [etagere]: https://github.com/nical/etagere
mod cache;
mod error; mod error;
mod text_atlas; mod text_atlas;
mod text_render; mod text_render;
pub use cache::Cache;
pub use error::{PrepareError, RenderError}; pub use error::{PrepareError, RenderError};
pub use text_atlas::{ColorMode, TextAtlas}; pub use text_atlas::{ColorMode, TextAtlas};
pub use text_render::TextRenderer; pub use text_render::TextRenderer;

View file

@ -21,17 +21,17 @@ struct Params {
}; };
@group(0) @binding(0) @group(0) @binding(0)
var<uniform> params: Params;
@group(1) @binding(0)
var color_atlas_texture: texture_2d<f32>; var color_atlas_texture: texture_2d<f32>;
@group(1) @binding(1) @group(0) @binding(1)
var mask_atlas_texture: texture_2d<f32>; var mask_atlas_texture: texture_2d<f32>;
@group(1) @binding(2) @group(0) @binding(2)
var atlas_sampler: sampler; var atlas_sampler: sampler;
@group(1) @binding(0)
var<uniform> params: Params;
fn srgb_to_linear(c: f32) -> f32 { fn srgb_to_linear(c: f32) -> f32 {
if c <= 0.04045 { if c <= 0.04045 {
return c / 12.92; return c / 12.92;

View file

@ -1,24 +1,14 @@
use crate::{ use crate::{
text_render::ContentType, CacheKey, FontSystem, GlyphDetails, GlyphToRender, GpuCacheStatus, text_render::ContentType, Cache, CacheKey, FontSystem, GlyphDetails, GpuCacheStatus, SwashCache,
Params, SwashCache,
}; };
use etagere::{size2, Allocation, BucketedAtlasAllocator}; use etagere::{size2, Allocation, BucketedAtlasAllocator};
use lru::LruCache; use lru::LruCache;
use rustc_hash::FxHasher; use rustc_hash::FxHasher;
use std::{ use std::{collections::HashSet, hash::BuildHasherDefault, sync::Arc};
borrow::Cow, collections::HashSet, hash::BuildHasherDefault, mem::size_of, num::NonZeroU64,
sync::Arc,
};
use wgpu::{ use wgpu::{
BindGroup, BindGroupDescriptor, BindGroupEntry, BindGroupLayout, BindGroupLayoutEntry, BindGroup, Buffer, DepthStencilState, Device, Extent3d, ImageCopyTexture, ImageDataLayout,
BindingResource, BindingType, BlendState, BufferBindingType, ColorTargetState, ColorWrites, MultisampleState, Origin3d, Queue, RenderPipeline, Texture, TextureAspect, TextureDescriptor,
DepthStencilState, Device, Extent3d, FilterMode, FragmentState, ImageCopyTexture, TextureDimension, TextureFormat, TextureUsages, TextureView, TextureViewDescriptor,
ImageDataLayout, MultisampleState, Origin3d, PipelineCompilationOptions, PipelineLayout,
PipelineLayoutDescriptor, PrimitiveState, Queue, RenderPipeline, RenderPipelineDescriptor,
Sampler, SamplerBindingType, SamplerDescriptor, ShaderModule, ShaderModuleDescriptor,
ShaderSource, ShaderStages, Texture, TextureAspect, TextureDescriptor, TextureDimension,
TextureFormat, TextureSampleType, TextureUsages, TextureView, TextureViewDescriptor,
TextureViewDimension, VertexFormat, VertexState,
}; };
type Hasher = BuildHasherDefault<FxHasher>; type Hasher = BuildHasherDefault<FxHasher>;
@ -261,137 +251,28 @@ pub enum ColorMode {
/// An atlas containing a cache of rasterized glyphs that can be rendered. /// An atlas containing a cache of rasterized glyphs that can be rendered.
pub struct TextAtlas { pub struct TextAtlas {
pub(crate) cached_pipelines: Vec<( cache: Cache,
MultisampleState, pub(crate) bind_group: BindGroup,
Option<DepthStencilState>,
Arc<RenderPipeline>,
)>,
pub(crate) bind_group: Arc<BindGroup>,
pub(crate) bind_group_layout: BindGroupLayout,
pub(crate) text_render_bind_group_layout: BindGroupLayout,
pub(crate) sampler: Sampler,
pub(crate) color_atlas: InnerAtlas, pub(crate) color_atlas: InnerAtlas,
pub(crate) mask_atlas: InnerAtlas, pub(crate) mask_atlas: InnerAtlas,
pub(crate) pipeline_layout: PipelineLayout,
pub(crate) shader: ShaderModule,
pub(crate) vertex_buffers: [wgpu::VertexBufferLayout<'static>; 1],
pub(crate) format: TextureFormat, pub(crate) format: TextureFormat,
pub(crate) color_mode: ColorMode, pub(crate) color_mode: ColorMode,
} }
impl TextAtlas { impl TextAtlas {
/// Creates a new [`TextAtlas`]. /// Creates a new [`TextAtlas`].
pub fn new(device: &Device, queue: &Queue, format: TextureFormat) -> Self { pub fn new(device: &Device, queue: &Queue, cache: &Cache, format: TextureFormat) -> Self {
Self::with_color_mode(device, queue, format, ColorMode::Accurate) Self::with_color_mode(device, queue, cache, format, ColorMode::Accurate)
} }
/// Creates a new [`TextAtlas`] with the given [`ColorMode`]. /// Creates a new [`TextAtlas`] with the given [`ColorMode`].
pub fn with_color_mode( pub fn with_color_mode(
device: &Device, device: &Device,
queue: &Queue, queue: &Queue,
cache: &Cache,
format: TextureFormat, format: TextureFormat,
color_mode: ColorMode, color_mode: ColorMode,
) -> Self { ) -> Self {
let sampler = device.create_sampler(&SamplerDescriptor {
label: Some("glyphon sampler"),
min_filter: FilterMode::Nearest,
mag_filter: FilterMode::Nearest,
mipmap_filter: FilterMode::Nearest,
lod_min_clamp: 0f32,
lod_max_clamp: 0f32,
..Default::default()
});
// Create a render pipeline to use for rendering later
let shader = device.create_shader_module(ShaderModuleDescriptor {
label: Some("glyphon shader"),
source: ShaderSource::Wgsl(Cow::Borrowed(include_str!("shader.wgsl"))),
});
let vertex_buffers = [wgpu::VertexBufferLayout {
array_stride: size_of::<GlyphToRender>() as wgpu::BufferAddress,
step_mode: wgpu::VertexStepMode::Vertex,
attributes: &[
wgpu::VertexAttribute {
format: VertexFormat::Sint32x2,
offset: 0,
shader_location: 0,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: size_of::<u32>() as u64 * 2,
shader_location: 1,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: size_of::<u32>() as u64 * 3,
shader_location: 2,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: size_of::<u32>() as u64 * 4,
shader_location: 3,
},
wgpu::VertexAttribute {
format: VertexFormat::Uint32,
offset: size_of::<u32>() as u64 * 5,
shader_location: 4,
},
wgpu::VertexAttribute {
format: VertexFormat::Float32,
offset: size_of::<u32>() as u64 * 6,
shader_location: 5,
},
],
}];
let text_render_bind_group_layout =
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::VERTEX,
ty: BindingType::Buffer {
ty: BufferBindingType::Uniform,
has_dynamic_offset: false,
min_binding_size: NonZeroU64::new(size_of::<Params>() as u64),
},
count: None,
}],
label: Some("glyphon text render bind group layout"),
});
let bind_group_layout = device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
entries: &[
BindGroupLayoutEntry {
binding: 0,
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled: false,
view_dimension: TextureViewDimension::D2,
sample_type: TextureSampleType::Float { filterable: true },
},
count: None,
},
BindGroupLayoutEntry {
binding: 1,
visibility: ShaderStages::VERTEX | ShaderStages::FRAGMENT,
ty: BindingType::Texture {
multisampled: false,
view_dimension: TextureViewDimension::D2,
sample_type: TextureSampleType::Float { filterable: true },
},
count: None,
},
BindGroupLayoutEntry {
binding: 2,
visibility: ShaderStages::FRAGMENT,
ty: BindingType::Sampler(SamplerBindingType::Filtering),
count: None,
},
],
label: Some("glyphon text atlas bind group layout"),
});
let color_atlas = InnerAtlas::new( let color_atlas = InnerAtlas::new(
device, device,
queue, queue,
@ -404,42 +285,17 @@ impl TextAtlas {
); );
let mask_atlas = InnerAtlas::new(device, queue, Kind::Mask); let mask_atlas = InnerAtlas::new(device, queue, Kind::Mask);
let bind_group = Arc::new(device.create_bind_group(&BindGroupDescriptor { let bind_group = cache.create_atlas_bind_group(
layout: &bind_group_layout, device,
entries: &[ &color_atlas.texture_view,
BindGroupEntry { &mask_atlas.texture_view,
binding: 0, );
resource: BindingResource::TextureView(&color_atlas.texture_view),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::TextureView(&mask_atlas.texture_view),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::Sampler(&sampler),
},
],
label: Some("glyphon text atlas bind group"),
}));
let pipeline_layout = device.create_pipeline_layout(&PipelineLayoutDescriptor {
label: None,
bind_group_layouts: &[&text_render_bind_group_layout, &bind_group_layout],
push_constant_ranges: &[],
});
Self { Self {
cached_pipelines: Vec::new(), cache: cache.clone(),
text_render_bind_group_layout,
bind_group, bind_group,
bind_group_layout,
sampler,
color_atlas, color_atlas,
mask_atlas, mask_atlas,
pipeline_layout,
shader,
vertex_buffers,
format, format,
color_mode, color_mode,
} }
@ -485,65 +341,24 @@ impl TextAtlas {
} }
pub(crate) fn get_or_create_pipeline( pub(crate) fn get_or_create_pipeline(
&mut self, &self,
device: &Device, device: &Device,
multisample: MultisampleState, multisample: MultisampleState,
depth_stencil: Option<DepthStencilState>, depth_stencil: Option<DepthStencilState>,
) -> Arc<RenderPipeline> { ) -> Arc<RenderPipeline> {
self.cached_pipelines self.cache
.iter() .get_or_create_pipeline(device, self.format, multisample, depth_stencil)
.find(|(ms, ds, _)| ms == &multisample && ds == &depth_stencil) }
.map(|(_, _, p)| Arc::clone(p))
.unwrap_or_else(|| {
let pipeline = Arc::new(device.create_render_pipeline(&RenderPipelineDescriptor {
label: Some("glyphon pipeline"),
layout: Some(&self.pipeline_layout),
vertex: VertexState {
module: &self.shader,
entry_point: "vs_main",
buffers: &self.vertex_buffers,
compilation_options: PipelineCompilationOptions::default(),
},
fragment: Some(FragmentState {
module: &self.shader,
entry_point: "fs_main",
targets: &[Some(ColorTargetState {
format: self.format,
blend: Some(BlendState::ALPHA_BLENDING),
write_mask: ColorWrites::default(),
})],
compilation_options: PipelineCompilationOptions::default(),
}),
primitive: PrimitiveState::default(),
depth_stencil: depth_stencil.clone(),
multisample,
multiview: None,
}));
self.cached_pipelines pub(crate) fn create_uniforms_bind_group(&self, device: &Device, buffer: &Buffer) -> BindGroup {
.push((multisample, depth_stencil, pipeline.clone())); self.cache.create_uniforms_bind_group(device, buffer)
pipeline
})
} }
fn rebind(&mut self, device: &wgpu::Device) { fn rebind(&mut self, device: &wgpu::Device) {
self.bind_group = Arc::new(device.create_bind_group(&BindGroupDescriptor { self.bind_group = self.cache.create_atlas_bind_group(
layout: &self.bind_group_layout, device,
entries: &[ &self.color_atlas.texture_view,
BindGroupEntry { &self.mask_atlas.texture_view,
binding: 0, );
resource: BindingResource::TextureView(&self.color_atlas.texture_view),
},
BindGroupEntry {
binding: 1,
resource: BindingResource::TextureView(&self.mask_atlas.texture_view),
},
BindGroupEntry {
binding: 2,
resource: BindingResource::Sampler(&self.sampler),
},
],
label: Some("glyphon bind group"),
}));
} }
} }

View file

@ -4,9 +4,9 @@ use crate::{
}; };
use std::{iter, mem::size_of, slice, sync::Arc}; use std::{iter, mem::size_of, slice, sync::Arc};
use wgpu::{ use wgpu::{
BindGroupDescriptor, BindGroupEntry, Buffer, BufferDescriptor, BufferUsages, DepthStencilState, Buffer, BufferDescriptor, BufferUsages, DepthStencilState, Device, Extent3d, ImageCopyTexture,
Device, Extent3d, ImageCopyTexture, ImageDataLayout, IndexFormat, MultisampleState, Origin3d, ImageDataLayout, IndexFormat, MultisampleState, Origin3d, Queue, RenderPass, RenderPipeline,
Queue, RenderPass, RenderPipeline, TextureAspect, COPY_BUFFER_ALIGNMENT, TextureAspect, COPY_BUFFER_ALIGNMENT,
}; };
/// A text renderer that uses cached glyphs to render text into an existing render pass. /// A text renderer that uses cached glyphs to render text into an existing render pass.
@ -48,8 +48,6 @@ impl TextRenderer {
mapped_at_creation: false, mapped_at_creation: false,
}); });
let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil);
let params = Params { let params = Params {
screen_resolution: Resolution { screen_resolution: Resolution {
width: 0, width: 0,
@ -65,14 +63,8 @@ impl TextRenderer {
mapped_at_creation: false, mapped_at_creation: false,
}); });
let bind_group = device.create_bind_group(&BindGroupDescriptor { let pipeline = atlas.get_or_create_pipeline(device, multisample, depth_stencil);
layout: &atlas.text_render_bind_group_layout, let bind_group = atlas.create_uniforms_bind_group(device, &params_buffer);
entries: &[BindGroupEntry {
binding: 0,
resource: params_buffer.as_entire_binding(),
}],
label: Some("glyphon text render bind group"),
});
Self { Self {
params, params,
@ -103,6 +95,7 @@ impl TextRenderer {
) -> Result<(), PrepareError> { ) -> Result<(), PrepareError> {
if self.params.screen_resolution != screen_resolution { if self.params.screen_resolution != screen_resolution {
self.params.screen_resolution = screen_resolution; self.params.screen_resolution = screen_resolution;
queue.write_buffer(&self.params_buffer, 0, unsafe { queue.write_buffer(&self.params_buffer, 0, unsafe {
slice::from_raw_parts( slice::from_raw_parts(
&self.params as *const Params as *const u8, &self.params as *const Params as *const u8,
@ -420,8 +413,8 @@ impl TextRenderer {
} }
pass.set_pipeline(&self.pipeline); pass.set_pipeline(&self.pipeline);
pass.set_bind_group(0, &self.bind_group, &[]); pass.set_bind_group(0, &atlas.bind_group, &[]);
pass.set_bind_group(1, &atlas.bind_group, &[]); pass.set_bind_group(1, &self.bind_group, &[]);
pass.set_vertex_buffer(0, self.vertex_buffer.slice(..)); pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
pass.set_index_buffer(self.index_buffer.slice(..), IndexFormat::Uint32); pass.set_index_buffer(self.index_buffer.slice(..), IndexFormat::Uint32);
pass.draw_indexed(0..self.vertices_to_render, 0, 0..1); pass.draw_indexed(0..self.vertices_to_render, 0, 0..1);