Skip to content

Commit

Permalink
Merge pull request #2425 from iced-rs/fix/image-cache-fighting
Browse files Browse the repository at this point in the history
Fix windows fighting over shared `image::Cache`
  • Loading branch information
hecrj authored May 6, 2024
2 parents a94984d + ea64e4f commit db07b9b
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 70 deletions.
3 changes: 2 additions & 1 deletion benches/wgpu.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,8 @@ fn benchmark(
Some(Antialiasing::MSAAx4),
);

let mut renderer = Renderer::new(&engine, Font::DEFAULT, Pixels::from(16));
let mut renderer =
Renderer::new(&device, &engine, Font::DEFAULT, Pixels::from(16));

let viewport =
graphics::Viewport::with_physical_size(Size::new(3840, 2160), 2.0);
Expand Down
2 changes: 1 addition & 1 deletion examples/integration/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut debug = Debug::new();
let mut engine = Engine::new(&adapter, &device, &queue, format, None);
let mut renderer =
Renderer::new(&engine, Font::default(), Pixels::from(16));
Renderer::new(&device, &engine, Font::default(), Pixels::from(16));

let mut state = program::State::new(
controls,
Expand Down
7 changes: 5 additions & 2 deletions wgpu/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,8 +59,11 @@ impl Engine {
}

#[cfg(any(feature = "image", feature = "svg"))]
pub fn image_cache(&self) -> &crate::image::cache::Shared {
self.image_pipeline.cache()
pub fn create_image_cache(
&self,
device: &wgpu::Device,
) -> crate::image::Cache {
self.image_pipeline.create_cache(device)
}

pub fn submit(
Expand Down
38 changes: 35 additions & 3 deletions wgpu/src/image/atlas.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,23 @@ pub const SIZE: u32 = 2048;
use crate::core::Size;
use crate::graphics::color;

use std::sync::Arc;

#[derive(Debug)]
pub struct Atlas {
texture: wgpu::Texture,
texture_view: wgpu::TextureView,
texture_bind_group: wgpu::BindGroup,
texture_layout: Arc<wgpu::BindGroupLayout>,
layers: Vec<Layer>,
}

impl Atlas {
pub fn new(device: &wgpu::Device, backend: wgpu::Backend) -> Self {
pub fn new(
device: &wgpu::Device,
backend: wgpu::Backend,
texture_layout: Arc<wgpu::BindGroupLayout>,
) -> Self {
let layers = match backend {
// On the GL backend we start with 2 layers, to help wgpu figure
// out that this texture is `GL_TEXTURE_2D_ARRAY` rather than `GL_TEXTURE_2D`
Expand Down Expand Up @@ -60,15 +68,27 @@ impl Atlas {
..Default::default()
});

let texture_bind_group =
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("iced_wgpu::image texture atlas bind group"),
layout: &texture_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(&texture_view),
}],
});

Atlas {
texture,
texture_view,
texture_bind_group,
texture_layout,
layers,
}
}

pub fn view(&self) -> &wgpu::TextureView {
&self.texture_view
pub fn bind_group(&self) -> &wgpu::BindGroup {
&self.texture_bind_group
}

pub fn layer_count(&self) -> usize {
Expand Down Expand Up @@ -421,5 +441,17 @@ impl Atlas {
dimension: Some(wgpu::TextureViewDimension::D2Array),
..Default::default()
});

self.texture_bind_group =
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("iced_wgpu::image texture atlas bind group"),
layout: &self.texture_layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(
&self.texture_view,
),
}],
});
}
}
43 changes: 11 additions & 32 deletions wgpu/src/image/cache.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
use crate::core::{self, Size};
use crate::image::atlas::{self, Atlas};

use std::cell::{RefCell, RefMut};
use std::rc::Rc;
use std::sync::Arc;

#[derive(Debug)]
pub struct Cache {
Expand All @@ -14,16 +13,24 @@ pub struct Cache {
}

impl Cache {
pub fn new(device: &wgpu::Device, backend: wgpu::Backend) -> Self {
pub fn new(
device: &wgpu::Device,
backend: wgpu::Backend,
layout: Arc<wgpu::BindGroupLayout>,
) -> Self {
Self {
atlas: Atlas::new(device, backend),
atlas: Atlas::new(device, backend, layout),
#[cfg(feature = "image")]
raster: crate::image::raster::Cache::default(),
#[cfg(feature = "svg")]
vector: crate::image::vector::Cache::default(),
}
}

pub fn bind_group(&self) -> &wgpu::BindGroup {
self.atlas.bind_group()
}

pub fn layer_count(&self) -> usize {
self.atlas.layer_count()
}
Expand Down Expand Up @@ -69,21 +76,6 @@ impl Cache {
)
}

pub fn create_bind_group(
&self,
device: &wgpu::Device,
layout: &wgpu::BindGroupLayout,
) -> wgpu::BindGroup {
device.create_bind_group(&wgpu::BindGroupDescriptor {
label: Some("iced_wgpu::image texture atlas bind group"),
layout,
entries: &[wgpu::BindGroupEntry {
binding: 0,
resource: wgpu::BindingResource::TextureView(self.atlas.view()),
}],
})
}

pub fn trim(&mut self) {
#[cfg(feature = "image")]
self.raster.trim(&mut self.atlas);
Expand All @@ -92,16 +84,3 @@ impl Cache {
self.vector.trim(&mut self.atlas);
}
}

#[derive(Debug, Clone)]
pub struct Shared(Rc<RefCell<Cache>>);

impl Shared {
pub fn new(cache: Cache) -> Self {
Self(Rc::new(RefCell::new(cache)))
}

pub fn lock(&self) -> RefMut<'_, Cache> {
self.0.borrow_mut()
}
}
38 changes: 11 additions & 27 deletions wgpu/src/image/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,9 @@ use crate::core::{Rectangle, Size, Transformation};
use crate::Buffer;

use bytemuck::{Pod, Zeroable};

use std::mem;
use std::sync::Arc;

pub use crate::graphics::Image;

Expand All @@ -22,13 +24,11 @@ pub type Batch = Vec<Image>;
#[derive(Debug)]
pub struct Pipeline {
pipeline: wgpu::RenderPipeline,
backend: wgpu::Backend,
nearest_sampler: wgpu::Sampler,
linear_sampler: wgpu::Sampler,
texture: wgpu::BindGroup,
texture_version: usize,
texture_layout: wgpu::BindGroupLayout,
texture_layout: Arc<wgpu::BindGroupLayout>,
constant_layout: wgpu::BindGroupLayout,
cache: cache::Shared,
layers: Vec<Layer>,
prepare_layer: usize,
}
Expand Down Expand Up @@ -186,32 +186,28 @@ impl Pipeline {
multiview: None,
});

let cache = Cache::new(device, backend);
let texture = cache.create_bind_group(device, &texture_layout);

Pipeline {
pipeline,
backend,
nearest_sampler,
linear_sampler,
texture,
texture_version: cache.layer_count(),
texture_layout,
texture_layout: Arc::new(texture_layout),
constant_layout,
cache: cache::Shared::new(cache),
layers: Vec::new(),
prepare_layer: 0,
}
}

pub fn cache(&self) -> &cache::Shared {
&self.cache
pub fn create_cache(&self, device: &wgpu::Device) -> Cache {
Cache::new(device, self.backend, self.texture_layout.clone())
}

pub fn prepare(
&mut self,
device: &wgpu::Device,
encoder: &mut wgpu::CommandEncoder,
belt: &mut wgpu::util::StagingBelt,
cache: &mut Cache,
images: &Batch,
transformation: Transformation,
scale: f32,
Expand All @@ -221,8 +217,6 @@ impl Pipeline {
let nearest_instances: &mut Vec<Instance> = &mut Vec::new();
let linear_instances: &mut Vec<Instance> = &mut Vec::new();

let mut cache = self.cache.lock();

for image in images {
match &image {
#[cfg(feature = "image")]
Expand Down Expand Up @@ -288,16 +282,6 @@ impl Pipeline {
return;
}

let texture_version = cache.layer_count();

if self.texture_version != texture_version {
log::debug!("Atlas has grown. Recreating bind group...");

self.texture =
cache.create_bind_group(device, &self.texture_layout);
self.texture_version = texture_version;
}

if self.layers.len() <= self.prepare_layer {
self.layers.push(Layer::new(
device,
Expand All @@ -323,6 +307,7 @@ impl Pipeline {

pub fn render<'a>(
&'a self,
cache: &'a Cache,
layer: usize,
bounds: Rectangle<u32>,
render_pass: &mut wgpu::RenderPass<'a>,
Expand All @@ -337,14 +322,13 @@ impl Pipeline {
bounds.height,
);

render_pass.set_bind_group(1, &self.texture, &[]);
render_pass.set_bind_group(1, cache.bind_group(), &[]);

layer.render(render_pass);
}
}

pub fn end_frame(&mut self) {
self.cache.lock().trim();
self.prepare_layer = 0;
}
}
Expand Down
18 changes: 14 additions & 4 deletions wgpu/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ use crate::core::{
use crate::graphics::text::{Editor, Paragraph};
use crate::graphics::Viewport;

use std::cell::RefCell;

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / todos_linux

unused import: `std::cell::RefCell`

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `std::cell::RefCell`

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `std::cell::RefCell`

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / wasm

unused import: `std::cell::RefCell`

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / todos_macos

unused import: `std::cell::RefCell`

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / todos_raspberry

unused import: `std::cell::RefCell`

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / todos_raspberry

unused import: `std::cell::RefCell`

Check warning on line 70 in wgpu/src/lib.rs

View workflow job for this annotation

GitHub Actions / todos_windows

unused import: `std::cell::RefCell`

/// A [`wgpu`] graphics renderer for [`iced`].
///
/// [`wgpu`]: https://github.com/gfx-rs/wgpu-rs
Expand All @@ -82,11 +84,12 @@ pub struct Renderer {

// TODO: Centralize all the image feature handling
#[cfg(any(feature = "svg", feature = "image"))]
image_cache: image::cache::Shared,
image_cache: RefCell<image::Cache>,
}

impl Renderer {
pub fn new(
_device: &wgpu::Device,
_engine: &Engine,
default_font: Font,
default_text_size: Pixels,
Expand All @@ -100,7 +103,7 @@ impl Renderer {
text_storage: text::Storage::new(),

#[cfg(any(feature = "svg", feature = "image"))]
image_cache: _engine.image_cache().clone(),
image_cache: RefCell::new(_engine.create_image_cache(_device)),
}
}

Expand All @@ -122,6 +125,9 @@ impl Renderer {

self.triangle_storage.trim();
self.text_storage.trim();

#[cfg(any(feature = "svg", feature = "image"))]
self.image_cache.borrow_mut().trim();
}

fn prepare(
Expand Down Expand Up @@ -191,6 +197,7 @@ impl Renderer {
device,
encoder,
&mut engine.staging_belt,
&mut self.image_cache.borrow_mut(),
&layer.images,
viewport.projection(),
scale_factor,
Expand Down Expand Up @@ -246,6 +253,8 @@ impl Renderer {

#[cfg(any(feature = "svg", feature = "image"))]
let mut image_layer = 0;
#[cfg(any(feature = "svg", feature = "image"))]
let image_cache = self.image_cache.borrow();

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

fn measure_image(&self, handle: &Self::Handle) -> Size<u32> {
self.image_cache.lock().measure_image(handle)
self.image_cache.borrow_mut().measure_image(handle)
}

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

fn draw_svg(
Expand Down
1 change: 1 addition & 0 deletions wgpu/src/window/compositor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -290,6 +290,7 @@ impl graphics::Compositor for Compositor {

fn create_renderer(&self) -> Self::Renderer {
Renderer::new(
&self.device,
&self.engine,
self.settings.default_font,
self.settings.default_text_size,
Expand Down

0 comments on commit db07b9b

Please sign in to comment.