Skip to content

Commit db07b9b

Browse files
authored
Merge pull request iced-rs#2425 from iced-rs/fix/image-cache-fighting
Fix windows fighting over shared `image::Cache`
2 parents a94984d + ea64e4f commit db07b9b

File tree

8 files changed

+80
-70
lines changed

8 files changed

+80
-70
lines changed

benches/wgpu.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,8 @@ fn benchmark(
7070
Some(Antialiasing::MSAAx4),
7171
);
7272

73-
let mut renderer = Renderer::new(&engine, Font::DEFAULT, Pixels::from(16));
73+
let mut renderer =
74+
Renderer::new(&device, &engine, Font::DEFAULT, Pixels::from(16));
7475

7576
let viewport =
7677
graphics::Viewport::with_physical_size(Size::new(3840, 2160), 2.0);

examples/integration/src/main.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -157,7 +157,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
157157
let mut debug = Debug::new();
158158
let mut engine = Engine::new(&adapter, &device, &queue, format, None);
159159
let mut renderer =
160-
Renderer::new(&engine, Font::default(), Pixels::from(16));
160+
Renderer::new(&device, &engine, Font::default(), Pixels::from(16));
161161

162162
let mut state = program::State::new(
163163
controls,

wgpu/src/engine.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -59,8 +59,11 @@ impl Engine {
5959
}
6060

6161
#[cfg(any(feature = "image", feature = "svg"))]
62-
pub fn image_cache(&self) -> &crate::image::cache::Shared {
63-
self.image_pipeline.cache()
62+
pub fn create_image_cache(
63+
&self,
64+
device: &wgpu::Device,
65+
) -> crate::image::Cache {
66+
self.image_pipeline.create_cache(device)
6467
}
6568

6669
pub fn submit(

wgpu/src/image/atlas.rs

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,23 @@ pub const SIZE: u32 = 2048;
1515
use crate::core::Size;
1616
use crate::graphics::color;
1717

18+
use std::sync::Arc;
19+
1820
#[derive(Debug)]
1921
pub struct Atlas {
2022
texture: wgpu::Texture,
2123
texture_view: wgpu::TextureView,
24+
texture_bind_group: wgpu::BindGroup,
25+
texture_layout: Arc<wgpu::BindGroupLayout>,
2226
layers: Vec<Layer>,
2327
}
2428

2529
impl Atlas {
26-
pub fn new(device: &wgpu::Device, backend: wgpu::Backend) -> Self {
30+
pub fn new(
31+
device: &wgpu::Device,
32+
backend: wgpu::Backend,
33+
texture_layout: Arc<wgpu::BindGroupLayout>,
34+
) -> Self {
2735
let layers = match backend {
2836
// On the GL backend we start with 2 layers, to help wgpu figure
2937
// out that this texture is `GL_TEXTURE_2D_ARRAY` rather than `GL_TEXTURE_2D`
@@ -60,15 +68,27 @@ impl Atlas {
6068
..Default::default()
6169
});
6270

71+
let texture_bind_group =
72+
device.create_bind_group(&wgpu::BindGroupDescriptor {
73+
label: Some("iced_wgpu::image texture atlas bind group"),
74+
layout: &texture_layout,
75+
entries: &[wgpu::BindGroupEntry {
76+
binding: 0,
77+
resource: wgpu::BindingResource::TextureView(&texture_view),
78+
}],
79+
});
80+
6381
Atlas {
6482
texture,
6583
texture_view,
84+
texture_bind_group,
85+
texture_layout,
6686
layers,
6787
}
6888
}
6989

70-
pub fn view(&self) -> &wgpu::TextureView {
71-
&self.texture_view
90+
pub fn bind_group(&self) -> &wgpu::BindGroup {
91+
&self.texture_bind_group
7292
}
7393

7494
pub fn layer_count(&self) -> usize {
@@ -421,5 +441,17 @@ impl Atlas {
421441
dimension: Some(wgpu::TextureViewDimension::D2Array),
422442
..Default::default()
423443
});
444+
445+
self.texture_bind_group =
446+
device.create_bind_group(&wgpu::BindGroupDescriptor {
447+
label: Some("iced_wgpu::image texture atlas bind group"),
448+
layout: &self.texture_layout,
449+
entries: &[wgpu::BindGroupEntry {
450+
binding: 0,
451+
resource: wgpu::BindingResource::TextureView(
452+
&self.texture_view,
453+
),
454+
}],
455+
});
424456
}
425457
}

wgpu/src/image/cache.rs

Lines changed: 11 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use crate::core::{self, Size};
22
use crate::image::atlas::{self, Atlas};
33

4-
use std::cell::{RefCell, RefMut};
5-
use std::rc::Rc;
4+
use std::sync::Arc;
65

76
#[derive(Debug)]
87
pub struct Cache {
@@ -14,16 +13,24 @@ pub struct Cache {
1413
}
1514

1615
impl Cache {
17-
pub fn new(device: &wgpu::Device, backend: wgpu::Backend) -> Self {
16+
pub fn new(
17+
device: &wgpu::Device,
18+
backend: wgpu::Backend,
19+
layout: Arc<wgpu::BindGroupLayout>,
20+
) -> Self {
1821
Self {
19-
atlas: Atlas::new(device, backend),
22+
atlas: Atlas::new(device, backend, layout),
2023
#[cfg(feature = "image")]
2124
raster: crate::image::raster::Cache::default(),
2225
#[cfg(feature = "svg")]
2326
vector: crate::image::vector::Cache::default(),
2427
}
2528
}
2629

30+
pub fn bind_group(&self) -> &wgpu::BindGroup {
31+
self.atlas.bind_group()
32+
}
33+
2734
pub fn layer_count(&self) -> usize {
2835
self.atlas.layer_count()
2936
}
@@ -69,21 +76,6 @@ impl Cache {
6976
)
7077
}
7178

72-
pub fn create_bind_group(
73-
&self,
74-
device: &wgpu::Device,
75-
layout: &wgpu::BindGroupLayout,
76-
) -> wgpu::BindGroup {
77-
device.create_bind_group(&wgpu::BindGroupDescriptor {
78-
label: Some("iced_wgpu::image texture atlas bind group"),
79-
layout,
80-
entries: &[wgpu::BindGroupEntry {
81-
binding: 0,
82-
resource: wgpu::BindingResource::TextureView(self.atlas.view()),
83-
}],
84-
})
85-
}
86-
8779
pub fn trim(&mut self) {
8880
#[cfg(feature = "image")]
8981
self.raster.trim(&mut self.atlas);
@@ -92,16 +84,3 @@ impl Cache {
9284
self.vector.trim(&mut self.atlas);
9385
}
9486
}
95-
96-
#[derive(Debug, Clone)]
97-
pub struct Shared(Rc<RefCell<Cache>>);
98-
99-
impl Shared {
100-
pub fn new(cache: Cache) -> Self {
101-
Self(Rc::new(RefCell::new(cache)))
102-
}
103-
104-
pub fn lock(&self) -> RefMut<'_, Cache> {
105-
self.0.borrow_mut()
106-
}
107-
}

wgpu/src/image/mod.rs

Lines changed: 11 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,9 @@ use crate::core::{Rectangle, Size, Transformation};
1313
use crate::Buffer;
1414

1515
use bytemuck::{Pod, Zeroable};
16+
1617
use std::mem;
18+
use std::sync::Arc;
1719

1820
pub use crate::graphics::Image;
1921

@@ -22,13 +24,11 @@ pub type Batch = Vec<Image>;
2224
#[derive(Debug)]
2325
pub struct Pipeline {
2426
pipeline: wgpu::RenderPipeline,
27+
backend: wgpu::Backend,
2528
nearest_sampler: wgpu::Sampler,
2629
linear_sampler: wgpu::Sampler,
27-
texture: wgpu::BindGroup,
28-
texture_version: usize,
29-
texture_layout: wgpu::BindGroupLayout,
30+
texture_layout: Arc<wgpu::BindGroupLayout>,
3031
constant_layout: wgpu::BindGroupLayout,
31-
cache: cache::Shared,
3232
layers: Vec<Layer>,
3333
prepare_layer: usize,
3434
}
@@ -186,32 +186,28 @@ impl Pipeline {
186186
multiview: None,
187187
});
188188

189-
let cache = Cache::new(device, backend);
190-
let texture = cache.create_bind_group(device, &texture_layout);
191-
192189
Pipeline {
193190
pipeline,
191+
backend,
194192
nearest_sampler,
195193
linear_sampler,
196-
texture,
197-
texture_version: cache.layer_count(),
198-
texture_layout,
194+
texture_layout: Arc::new(texture_layout),
199195
constant_layout,
200-
cache: cache::Shared::new(cache),
201196
layers: Vec::new(),
202197
prepare_layer: 0,
203198
}
204199
}
205200

206-
pub fn cache(&self) -> &cache::Shared {
207-
&self.cache
201+
pub fn create_cache(&self, device: &wgpu::Device) -> Cache {
202+
Cache::new(device, self.backend, self.texture_layout.clone())
208203
}
209204

210205
pub fn prepare(
211206
&mut self,
212207
device: &wgpu::Device,
213208
encoder: &mut wgpu::CommandEncoder,
214209
belt: &mut wgpu::util::StagingBelt,
210+
cache: &mut Cache,
215211
images: &Batch,
216212
transformation: Transformation,
217213
scale: f32,
@@ -221,8 +217,6 @@ impl Pipeline {
221217
let nearest_instances: &mut Vec<Instance> = &mut Vec::new();
222218
let linear_instances: &mut Vec<Instance> = &mut Vec::new();
223219

224-
let mut cache = self.cache.lock();
225-
226220
for image in images {
227221
match &image {
228222
#[cfg(feature = "image")]
@@ -288,16 +282,6 @@ impl Pipeline {
288282
return;
289283
}
290284

291-
let texture_version = cache.layer_count();
292-
293-
if self.texture_version != texture_version {
294-
log::debug!("Atlas has grown. Recreating bind group...");
295-
296-
self.texture =
297-
cache.create_bind_group(device, &self.texture_layout);
298-
self.texture_version = texture_version;
299-
}
300-
301285
if self.layers.len() <= self.prepare_layer {
302286
self.layers.push(Layer::new(
303287
device,
@@ -323,6 +307,7 @@ impl Pipeline {
323307

324308
pub fn render<'a>(
325309
&'a self,
310+
cache: &'a Cache,
326311
layer: usize,
327312
bounds: Rectangle<u32>,
328313
render_pass: &mut wgpu::RenderPass<'a>,
@@ -337,14 +322,13 @@ impl Pipeline {
337322
bounds.height,
338323
);
339324

340-
render_pass.set_bind_group(1, &self.texture, &[]);
325+
render_pass.set_bind_group(1, cache.bind_group(), &[]);
341326

342327
layer.render(render_pass);
343328
}
344329
}
345330

346331
pub fn end_frame(&mut self) {
347-
self.cache.lock().trim();
348332
self.prepare_layer = 0;
349333
}
350334
}

wgpu/src/lib.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,8 @@ use crate::core::{
6767
use crate::graphics::text::{Editor, Paragraph};
6868
use crate::graphics::Viewport;
6969

70+
use std::cell::RefCell;
71+
7072
/// A [`wgpu`] graphics renderer for [`iced`].
7173
///
7274
/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
@@ -82,11 +84,12 @@ pub struct Renderer {
8284

8385
// TODO: Centralize all the image feature handling
8486
#[cfg(any(feature = "svg", feature = "image"))]
85-
image_cache: image::cache::Shared,
87+
image_cache: RefCell<image::Cache>,
8688
}
8789

8890
impl Renderer {
8991
pub fn new(
92+
_device: &wgpu::Device,
9093
_engine: &Engine,
9194
default_font: Font,
9295
default_text_size: Pixels,
@@ -100,7 +103,7 @@ impl Renderer {
100103
text_storage: text::Storage::new(),
101104

102105
#[cfg(any(feature = "svg", feature = "image"))]
103-
image_cache: _engine.image_cache().clone(),
106+
image_cache: RefCell::new(_engine.create_image_cache(_device)),
104107
}
105108
}
106109

@@ -122,6 +125,9 @@ impl Renderer {
122125

123126
self.triangle_storage.trim();
124127
self.text_storage.trim();
128+
129+
#[cfg(any(feature = "svg", feature = "image"))]
130+
self.image_cache.borrow_mut().trim();
125131
}
126132

127133
fn prepare(
@@ -191,6 +197,7 @@ impl Renderer {
191197
device,
192198
encoder,
193199
&mut engine.staging_belt,
200+
&mut self.image_cache.borrow_mut(),
194201
&layer.images,
195202
viewport.projection(),
196203
scale_factor,
@@ -246,6 +253,8 @@ impl Renderer {
246253

247254
#[cfg(any(feature = "svg", feature = "image"))]
248255
let mut image_layer = 0;
256+
#[cfg(any(feature = "svg", feature = "image"))]
257+
let image_cache = self.image_cache.borrow();
249258

250259
let scale_factor = viewport.scale_factor() as f32;
251260
let physical_bounds = Rectangle::<f32>::from(Rectangle::with_size(
@@ -359,6 +368,7 @@ impl Renderer {
359368
#[cfg(any(feature = "svg", feature = "image"))]
360369
if !layer.images.is_empty() {
361370
engine.image_pipeline.render(
371+
&image_cache,
362372
image_layer,
363373
scissor_rect,
364374
&mut render_pass,
@@ -509,7 +519,7 @@ impl core::image::Renderer for Renderer {
509519
type Handle = core::image::Handle;
510520

511521
fn measure_image(&self, handle: &Self::Handle) -> Size<u32> {
512-
self.image_cache.lock().measure_image(handle)
522+
self.image_cache.borrow_mut().measure_image(handle)
513523
}
514524

515525
fn draw_image(
@@ -535,7 +545,7 @@ impl core::image::Renderer for Renderer {
535545
#[cfg(feature = "svg")]
536546
impl core::svg::Renderer for Renderer {
537547
fn measure_svg(&self, handle: &core::svg::Handle) -> Size<u32> {
538-
self.image_cache.lock().measure_svg(handle)
548+
self.image_cache.borrow_mut().measure_svg(handle)
539549
}
540550

541551
fn draw_svg(

wgpu/src/window/compositor.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,7 @@ impl graphics::Compositor for Compositor {
290290

291291
fn create_renderer(&self) -> Self::Renderer {
292292
Renderer::new(
293+
&self.device,
293294
&self.engine,
294295
self.settings.default_font,
295296
self.settings.default_text_size,

0 commit comments

Comments
 (0)