Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix windows fighting over shared image::Cache #2425

Merged
merged 2 commits into from
May 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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::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 / 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 / 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`

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

// 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 @@
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 @@

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 @@
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 @@

#[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 @@
#[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 @@
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 @@
#[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
Loading