mirror of
https://github.com/Zenithsiz/zsw.git
synced 2026-02-03 09:50:31 +00:00
Compare commits
10 Commits
07935a6d89
...
f9de217a55
| Author | SHA1 | Date | |
|---|---|---|---|
| f9de217a55 | |||
| 077b1c6ce0 | |||
| 657de4f5cb | |||
| fe368dbef6 | |||
| 39310e0c32 | |||
| cf42081eaf | |||
| 4e99f2b55b | |||
| cf9a1b9e82 | |||
| ad3b866868 | |||
| c30c239e29 |
@ -121,7 +121,6 @@ rust.unused_crate_dependencies = "warn"
|
||||
rust.unused_lifetimes = "warn"
|
||||
rust.unused_macro_rules = "warn"
|
||||
rust.unused_results = "warn"
|
||||
rust.variant_size_differences = "warn"
|
||||
|
||||
|
||||
# We want to annotate unsafe inside unsafe fns
|
||||
|
||||
@ -1,33 +1,25 @@
|
||||
//! Loadable
|
||||
|
||||
// Imports
|
||||
use {
|
||||
crate::AppError,
|
||||
core::{fmt, task::Poll},
|
||||
futures::FutureExt,
|
||||
std::task,
|
||||
};
|
||||
use {crate::AppError, core::task::Poll, futures::FutureExt, std::task};
|
||||
|
||||
/// Loadable value
|
||||
pub struct Loadable<T, F> {
|
||||
#[derive(Debug)]
|
||||
pub struct Loadable<T> {
|
||||
/// Current value, if any
|
||||
value: Option<T>,
|
||||
|
||||
/// Loading task
|
||||
task: Option<tokio::task::JoinHandle<T>>,
|
||||
|
||||
/// Loader
|
||||
loader: F,
|
||||
}
|
||||
|
||||
impl<T, F> Loadable<T, F> {
|
||||
impl<T> Loadable<T> {
|
||||
/// Creates a new, empty, loadable
|
||||
#[must_use]
|
||||
pub fn new(loader: F) -> Self {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
value: None,
|
||||
task: None,
|
||||
loader,
|
||||
task: None,
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,11 +44,14 @@ impl<T, F> Loadable<T, F> {
|
||||
self.value.take()
|
||||
}
|
||||
|
||||
/// Tries to load the inner value
|
||||
pub fn try_load<Args>(&mut self, args: Args) -> Option<&mut T>
|
||||
/// Tries to load the inner value.
|
||||
///
|
||||
/// If the value isn't loading, `spawn_task` is called to spawn a
|
||||
/// task that loads the value
|
||||
pub fn try_load<F>(&mut self, spawn_task: F) -> Option<&mut T>
|
||||
where
|
||||
T: Send + 'static,
|
||||
F: Loader<Args, T>,
|
||||
F: FnOnce() -> Result<tokio::task::JoinHandle<T>, AppError>,
|
||||
{
|
||||
// If the value is loaded, we're done
|
||||
// Note: We can't use if-let due to a borrow-checker limitation
|
||||
@ -88,7 +83,7 @@ impl<T, F> Loadable<T, F> {
|
||||
}
|
||||
},
|
||||
None => {
|
||||
match self.loader.spawn(args) {
|
||||
match spawn_task() {
|
||||
Ok(task) => self.task = Some(task),
|
||||
Err(err) => tracing::warn!("Unable to spawn task: {}", err.pretty()),
|
||||
}
|
||||
@ -99,18 +94,8 @@ impl<T, F> Loadable<T, F> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Loader trait
|
||||
pub trait Loader<Args, T> {
|
||||
/// Spawns the loader future
|
||||
fn spawn(&mut self, args: Args) -> Result<tokio::task::JoinHandle<T>, AppError>;
|
||||
}
|
||||
|
||||
impl<T: fmt::Debug, F> fmt::Debug for Loadable<T, F> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("Loadable")
|
||||
.field("value", &self.value)
|
||||
.field("task", &self.task)
|
||||
.field("loader", &"..")
|
||||
.finish()
|
||||
impl<T> Default for Loadable<T> {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,6 @@ use {
|
||||
app_error::Context,
|
||||
core::sync::atomic::{self, AtomicBool},
|
||||
image::DynamicImage,
|
||||
std::path::Path,
|
||||
wgpu::{util as wgpu_util, util::DeviceExt},
|
||||
zsw_util::AppError,
|
||||
};
|
||||
@ -76,7 +75,7 @@ impl Wgpu {
|
||||
/// Creates a texture from an image.
|
||||
pub fn create_texture_from_image(
|
||||
&self,
|
||||
path: &Path,
|
||||
label: &str,
|
||||
image: DynamicImage,
|
||||
) -> Result<(wgpu::Texture, wgpu::TextureView), AppError> {
|
||||
// Get the image's format, converting if necessary.
|
||||
@ -104,7 +103,7 @@ impl Wgpu {
|
||||
);
|
||||
|
||||
let texture_descriptor = wgpu::TextureDescriptor {
|
||||
label: Some(&format!("[zsw] Image ({path:?})")),
|
||||
label: Some(label),
|
||||
size: wgpu::Extent3d {
|
||||
width: image.width(),
|
||||
height: image.height(),
|
||||
@ -125,7 +124,10 @@ impl Wgpu {
|
||||
image.as_bytes(),
|
||||
);
|
||||
|
||||
let texture_view_descriptor = wgpu::TextureViewDescriptor::default();
|
||||
let texture_view_descriptor = wgpu::TextureViewDescriptor {
|
||||
label: Some(&format!("{label}-view")),
|
||||
..Default::default()
|
||||
};
|
||||
let texture_view = texture.create_view(&texture_view_descriptor);
|
||||
|
||||
Ok((texture, texture_view))
|
||||
@ -136,7 +138,7 @@ impl Wgpu {
|
||||
async fn create_device(adapter: &wgpu::Adapter) -> Result<(wgpu::Device, wgpu::Queue), AppError> {
|
||||
// Request the device without any features
|
||||
let device_descriptor = wgpu::DeviceDescriptor {
|
||||
label: Some("[zsw] Device"),
|
||||
label: Some("zsw-device"),
|
||||
required_features: wgpu::Features::default(),
|
||||
required_limits: wgpu::Limits::default(),
|
||||
memory_hints: wgpu::MemoryHints::default(),
|
||||
@ -148,12 +150,6 @@ async fn create_device(adapter: &wgpu::Adapter) -> Result<(wgpu::Device, wgpu::Q
|
||||
.await
|
||||
.context("Unable to request device")?;
|
||||
|
||||
// Configure the device to not panic on errors
|
||||
device.on_uncaptured_error(Box::new(|err| {
|
||||
let err = AppError::new(&err);
|
||||
tracing::error!("Wgpu error: {}", err.pretty());
|
||||
}));
|
||||
|
||||
Ok((device, queue))
|
||||
}
|
||||
|
||||
@ -191,7 +187,7 @@ async fn create_adapter(instance: &wgpu::Instance) -> Result<wgpu::Adapter, AppE
|
||||
fn create_empty_image_texture(device: &wgpu::Device) -> (wgpu::Texture, wgpu::TextureView) {
|
||||
// TODO: Pass some view formats?
|
||||
let texture_descriptor = wgpu::TextureDescriptor {
|
||||
label: Some("[zsw] Empty image"),
|
||||
label: Some("zsw-texture-empty"),
|
||||
size: wgpu::Extent3d {
|
||||
width: 1,
|
||||
height: 1,
|
||||
@ -206,7 +202,10 @@ fn create_empty_image_texture(device: &wgpu::Device) -> (wgpu::Texture, wgpu::Te
|
||||
};
|
||||
|
||||
let texture = device.create_texture(&texture_descriptor);
|
||||
let texture_view_descriptor = wgpu::TextureViewDescriptor::default();
|
||||
let texture_view_descriptor = wgpu::TextureViewDescriptor {
|
||||
label: Some("zsw-texture-empty-view"),
|
||||
..Default::default()
|
||||
};
|
||||
let texture_view = texture.create_view(&texture_view_descriptor);
|
||||
|
||||
(texture, texture_view)
|
||||
|
||||
@ -87,14 +87,14 @@ impl WgpuRenderer {
|
||||
}
|
||||
});
|
||||
let surface_view_descriptor = wgpu::TextureViewDescriptor {
|
||||
label: Some("[zsw] Window surface texture view"),
|
||||
label: Some("zsw-frame-surface-texture-view"),
|
||||
..wgpu::TextureViewDescriptor::default()
|
||||
};
|
||||
let surface_texture_view = surface_texture.texture.create_view(&surface_view_descriptor);
|
||||
|
||||
// Then create an encoder for our frame
|
||||
let encoder_descriptor = wgpu::CommandEncoderDescriptor {
|
||||
label: Some("[zsw] Frame render command encoder"),
|
||||
label: Some("zsw-frame-command-encoder"),
|
||||
};
|
||||
let encoder = wgpu.device.create_command_encoder(&encoder_descriptor);
|
||||
|
||||
|
||||
@ -5,18 +5,18 @@
|
||||
#import fade::uniforms::{uniforms, ImageUniforms}
|
||||
|
||||
// Bindings
|
||||
@group(1) @binding(0) var texture_prev: texture_2d<f32>;
|
||||
@group(1) @binding(1) var texture_cur: texture_2d<f32>;
|
||||
@group(1) @binding(2) var texture_next: texture_2d<f32>;
|
||||
@group(1) @binding(3) var texture_sampler: sampler;
|
||||
@group(1) @binding(0) var image_prev: texture_2d<f32>;
|
||||
@group(1) @binding(1) var image_cur: texture_2d<f32>;
|
||||
@group(1) @binding(2) var image_next: texture_2d<f32>;
|
||||
@group(1) @binding(3) var image_sampler: sampler;
|
||||
|
||||
struct Sampled {
|
||||
color: vec4<f32>,
|
||||
uvs : vec2<f32>,
|
||||
}
|
||||
|
||||
// Samples a texture
|
||||
fn sample(texture: texture_2d<f32>, in_uvs: vec2<f32>, image_uniforms: ImageUniforms, progress_raw: f32, alpha: f32) -> Sampled {
|
||||
// Samples an image
|
||||
fn sample(image: texture_2d<f32>, in_uvs: vec2<f32>, image_uniforms: ImageUniforms, progress_raw: f32, alpha: f32) -> Sampled {
|
||||
var sampled: Sampled;
|
||||
var uvs = in_uvs;
|
||||
|
||||
@ -42,7 +42,7 @@ fn sample(texture: texture_2d<f32>, in_uvs: vec2<f32>, image_uniforms: ImageUnif
|
||||
|
||||
#endif
|
||||
|
||||
sampled.color = textureSample(texture, texture_sampler, uvs);
|
||||
sampled.color = textureSample(image, image_sampler, uvs);
|
||||
sampled.uvs = uvs;
|
||||
|
||||
return sampled;
|
||||
@ -65,10 +65,10 @@ fn main(in: VertexOutput) -> FragOutput {
|
||||
let alpha_next = 0.5 * saturate(1.0 - (1.0 - p) / f);
|
||||
let alpha_cur = 1.0 - max(alpha_prev, alpha_next);
|
||||
|
||||
// Sample the textures
|
||||
let sample_prev = sample(texture_prev, in.uvs, uniforms.prev, progress_prev, alpha_prev);
|
||||
let sample_cur = sample( texture_cur, in.uvs, uniforms.cur , progress_cur , alpha_cur );
|
||||
let sample_next = sample(texture_next, in.uvs, uniforms.next, progress_next, alpha_next);
|
||||
// Sample the images
|
||||
let sample_prev = sample(image_prev, in.uvs, uniforms.prev, progress_prev, alpha_prev);
|
||||
let sample_cur = sample( image_cur, in.uvs, uniforms.cur , progress_cur , alpha_cur );
|
||||
let sample_next = sample(image_next, in.uvs, uniforms.next, progress_next, alpha_next);
|
||||
|
||||
// Then mix the color
|
||||
// TODO: Don't repeat this once we're able to use `defined(FADE_BASIC) || defined(FADE_OUT)`
|
||||
|
||||
@ -34,7 +34,6 @@ fn draw_plot(ui: &mut egui::Ui, display: &FrameTimesDisplay, charts: impl IntoIt
|
||||
|
||||
/// Display
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[expect(variant_size_differences, reason = "It'll be heap allocated anyway")]
|
||||
enum FrameTimesDisplay {
|
||||
/// Time graph
|
||||
TimeGraph { stack_charts: bool },
|
||||
|
||||
@ -132,13 +132,13 @@ fn draw_fade_panel_editor(
|
||||
|
||||
ui.collapsing("Images", |ui| {
|
||||
ui.collapsing("Previous", |ui| {
|
||||
self::draw_panel_image(ui, &mut panel_state.images_mut().prev);
|
||||
self::draw_fade_panel_image(ui, &mut panel_state.images_mut().prev);
|
||||
});
|
||||
ui.collapsing("Current", |ui| {
|
||||
self::draw_panel_image(ui, &mut panel_state.images_mut().cur);
|
||||
self::draw_fade_panel_image(ui, &mut panel_state.images_mut().cur);
|
||||
});
|
||||
ui.collapsing("Next", |ui| {
|
||||
self::draw_panel_image(ui, &mut panel_state.images_mut().next);
|
||||
self::draw_fade_panel_image(ui, &mut panel_state.images_mut().next);
|
||||
});
|
||||
});
|
||||
|
||||
@ -168,8 +168,8 @@ fn draw_fade_panel_editor(
|
||||
});
|
||||
}
|
||||
|
||||
/// Draws a panel image
|
||||
fn draw_panel_image(ui: &mut egui::Ui, image: &mut Option<PanelFadeImage>) {
|
||||
/// Draws a fade panel image
|
||||
fn draw_fade_panel_image(ui: &mut egui::Ui, image: &mut Option<PanelFadeImage>) {
|
||||
match image {
|
||||
None => {
|
||||
ui.label("[Unloaded]");
|
||||
|
||||
@ -36,9 +36,9 @@ use {
|
||||
/// Panels renderer shared
|
||||
#[derive(Debug)]
|
||||
pub struct PanelsRendererShared {
|
||||
/// Render pipeline for each shader by shader name
|
||||
/// Render pipeline for each shader
|
||||
// TODO: Prune ones that aren't used?
|
||||
render_pipelines: Mutex<HashMap<&'static str, Arc<wgpu::RenderPipeline>>>,
|
||||
render_pipelines: Mutex<HashMap<RenderPipelineId, Arc<wgpu::RenderPipeline>>>,
|
||||
|
||||
/// Vertex buffer
|
||||
vertices: wgpu::Buffer,
|
||||
@ -157,7 +157,7 @@ impl PanelsRenderer {
|
||||
},
|
||||
};
|
||||
let render_pass_descriptor = wgpu::RenderPassDescriptor {
|
||||
label: Some("[zsw::panel] Render pass"),
|
||||
label: Some("zsw-panel-render-pass"),
|
||||
color_attachments: &[Some(render_pass_color_attachment)],
|
||||
depth_stencil_attachment: None,
|
||||
timestamp_writes: None,
|
||||
@ -202,8 +202,21 @@ impl PanelsRenderer {
|
||||
continue;
|
||||
}
|
||||
|
||||
let render_pipeline_id = match &panel.state {
|
||||
PanelState::None(_) => RenderPipelineId::None,
|
||||
PanelState::Fade(state) => RenderPipelineId::Fade(match state.shader() {
|
||||
PanelFadeShader::Basic => RenderPipelineFadeId::Basic,
|
||||
PanelFadeShader::White { .. } => RenderPipelineFadeId::White,
|
||||
PanelFadeShader::Out { .. } => RenderPipelineFadeId::Out,
|
||||
PanelFadeShader::In { .. } => RenderPipelineFadeId::In,
|
||||
}),
|
||||
PanelState::Slide(state) => RenderPipelineId::Slide(match state.shader() {
|
||||
PanelSlideShader::Basic => RenderPipelineSlideId::Basic,
|
||||
}),
|
||||
};
|
||||
|
||||
#[time(create_render_pipeline)]
|
||||
let render_pipeline = match shared.render_pipelines.lock().await.entry(panel.state.shader().name()) {
|
||||
let render_pipeline = match shared.render_pipelines.lock().await.entry(render_pipeline_id) {
|
||||
hash_map::Entry::Occupied(entry) => Arc::clone(entry.get()),
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let bind_group_layouts = match panel.state {
|
||||
@ -218,6 +231,7 @@ impl PanelsRenderer {
|
||||
let render_pipeline = self::create_render_pipeline(
|
||||
wgpu_renderer,
|
||||
wgpu,
|
||||
render_pipeline_id,
|
||||
bind_group_layouts,
|
||||
panel.state.shader(),
|
||||
self.msaa_samples,
|
||||
@ -320,7 +334,7 @@ impl PanelsRenderer {
|
||||
let geometry_uniforms = panel_geometry
|
||||
.uniforms
|
||||
.entry(window.id())
|
||||
.or_insert_with(|| self::create_panel_geometry_uniforms(wgpu, shared));
|
||||
.or_insert_with(|| self::create_geometry_uniforms(wgpu, &shared.uniforms_bind_group_layout));
|
||||
let write_uniforms = |uniforms_bytes| {
|
||||
wgpu.queue.write_buffer(&geometry_uniforms.buffer, 0, uniforms_bytes);
|
||||
};
|
||||
@ -404,10 +418,10 @@ impl PanelsRenderer {
|
||||
}
|
||||
|
||||
/// Creates the panel geometry uniforms
|
||||
fn create_panel_geometry_uniforms(wgpu: &Wgpu, shared: &PanelsRendererShared) -> PanelGeometryUniforms {
|
||||
fn create_geometry_uniforms(wgpu: &Wgpu, layout: &wgpu::BindGroupLayout) -> PanelGeometryUniforms {
|
||||
// Create the uniforms
|
||||
let buffer_descriptor = wgpu::BufferDescriptor {
|
||||
label: Some("[zsw::panel] Geometry uniforms buffer"),
|
||||
label: Some("zsw-panel-geometry-uniforms-buffer"),
|
||||
usage: wgpu::BufferUsages::UNIFORM | wgpu::BufferUsages::COPY_DST,
|
||||
size: u64::try_from(MAX_UNIFORM_SIZE).expect("Maximum uniform size didn't fit into a `u64`"),
|
||||
mapped_at_creation: false,
|
||||
@ -416,12 +430,12 @@ fn create_panel_geometry_uniforms(wgpu: &Wgpu, shared: &PanelsRendererShared) ->
|
||||
|
||||
// Create the uniform bind group
|
||||
let bind_group_descriptor = wgpu::BindGroupDescriptor {
|
||||
layout: &shared.uniforms_bind_group_layout,
|
||||
label: Some("zsw-panel-geometry-uniforms-bind-group"),
|
||||
layout,
|
||||
entries: &[wgpu::BindGroupEntry {
|
||||
binding: 0,
|
||||
resource: buffer.as_entire_binding(),
|
||||
}],
|
||||
label: Some("[zsw::panel] Geometry uniforms bind group"),
|
||||
};
|
||||
let bind_group = wgpu.device.create_bind_group(&bind_group_descriptor);
|
||||
|
||||
@ -431,7 +445,7 @@ fn create_panel_geometry_uniforms(wgpu: &Wgpu, shared: &PanelsRendererShared) ->
|
||||
/// Creates the vertices
|
||||
fn create_vertices(wgpu: &Wgpu) -> wgpu::Buffer {
|
||||
let descriptor = wgpu::util::BufferInitDescriptor {
|
||||
label: Some("[zsw::panel] Vertex buffer"),
|
||||
label: Some("zsw-panel-vertex-buffer"),
|
||||
contents: bytemuck::cast_slice(&PanelVertex::QUAD),
|
||||
usage: wgpu::BufferUsages::VERTEX,
|
||||
};
|
||||
@ -443,7 +457,7 @@ fn create_vertices(wgpu: &Wgpu) -> wgpu::Buffer {
|
||||
fn create_indices(wgpu: &Wgpu) -> wgpu::Buffer {
|
||||
const INDICES: [u32; 6] = [0, 1, 3, 0, 3, 2];
|
||||
let descriptor = wgpu::util::BufferInitDescriptor {
|
||||
label: Some("[zsw::panel] Index buffer"),
|
||||
label: Some("zsw-panel-index-buffer"),
|
||||
contents: bytemuck::cast_slice(&INDICES),
|
||||
usage: wgpu::BufferUsages::INDEX,
|
||||
};
|
||||
@ -451,16 +465,78 @@ fn create_indices(wgpu: &Wgpu) -> wgpu::Buffer {
|
||||
wgpu.device.create_buffer_init(&descriptor)
|
||||
}
|
||||
|
||||
/// Render pipeline id
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
pub enum RenderPipelineId {
|
||||
/// None shader
|
||||
None,
|
||||
|
||||
/// Fade shader
|
||||
Fade(RenderPipelineFadeId),
|
||||
|
||||
/// Slide
|
||||
Slide(RenderPipelineSlideId),
|
||||
}
|
||||
|
||||
impl RenderPipelineId {
|
||||
/// Returns this pipeline's name
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::None => "none",
|
||||
Self::Fade(id) => id.name(),
|
||||
Self::Slide(id) => id.name(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Render pipeline fade id
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
pub enum RenderPipelineFadeId {
|
||||
Basic,
|
||||
White,
|
||||
Out,
|
||||
In,
|
||||
}
|
||||
|
||||
impl RenderPipelineFadeId {
|
||||
/// Returns this pipeline's name
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::Basic => "fade-basic",
|
||||
Self::White => "fade-white",
|
||||
Self::Out => "fade-out",
|
||||
Self::In => "fade-in",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Render pipeline slide id
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
|
||||
pub enum RenderPipelineSlideId {
|
||||
Basic,
|
||||
}
|
||||
|
||||
impl RenderPipelineSlideId {
|
||||
/// Returns this pipeline's name
|
||||
pub fn name(self) -> &'static str {
|
||||
match self {
|
||||
Self::Basic => "slide-basic",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Creates the render pipeline
|
||||
fn create_render_pipeline(
|
||||
wgpu_renderer: &WgpuRenderer,
|
||||
wgpu: &Wgpu,
|
||||
id: RenderPipelineId,
|
||||
bind_group_layouts: &[&wgpu::BindGroupLayout],
|
||||
shader: PanelShader,
|
||||
msaa_samples: u32,
|
||||
) -> Result<wgpu::RenderPipeline, AppError> {
|
||||
let render_pipeline_name = id.name();
|
||||
let shader_name = shader.name();
|
||||
tracing::debug!("Creating render pipeline for shader {shader_name:?}");
|
||||
tracing::debug!("Creating render pipeline {render_pipeline_name:?} for shader {shader_name:?}");
|
||||
|
||||
// Parse the shader from the build script
|
||||
let shader_module =
|
||||
@ -468,14 +544,16 @@ fn create_render_pipeline(
|
||||
|
||||
// Load the shader
|
||||
let shader_descriptor = wgpu::ShaderModuleDescriptor {
|
||||
label: Some(&format!("[zsw::panel] Shader {shader_name:?}")),
|
||||
label: Some(&format!("zsw-panel-shader[name={shader_name:?}]")),
|
||||
source: wgpu::ShaderSource::Naga(Cow::Owned(shader_module)),
|
||||
};
|
||||
let shader = wgpu.device.create_shader_module(shader_descriptor);
|
||||
|
||||
// Create the pipeline layout
|
||||
let render_pipeline_layout_descriptor = wgpu::PipelineLayoutDescriptor {
|
||||
label: Some(&format!("[zsw::panel] Shader {shader_name:?} render pipeline layout")),
|
||||
label: Some(&format!(
|
||||
"zsw-panel-render-pipeline[name={render_pipeline_name:?}]-layout"
|
||||
)),
|
||||
bind_group_layouts,
|
||||
push_constant_ranges: &[],
|
||||
};
|
||||
@ -487,7 +565,7 @@ fn create_render_pipeline(
|
||||
write_mask: wgpu::ColorWrites::ALL,
|
||||
})];
|
||||
let render_pipeline_descriptor = wgpu::RenderPipelineDescriptor {
|
||||
label: Some(&format!("[zsw::panel] Shader {shader_name:?} render pipeline")),
|
||||
label: Some(&format!("zsw-panel-render-pipeline[name={render_pipeline_name:?}]")),
|
||||
layout: Some(&render_pipeline_layout),
|
||||
|
||||
vertex: wgpu::VertexState {
|
||||
@ -539,25 +617,28 @@ fn create_msaa_framebuffer(
|
||||
|
||||
let surface_config = wgpu_renderer.surface_config();
|
||||
let msaa_frame_descriptor = wgpu::TextureDescriptor {
|
||||
label: Some("zsw-panel-framebuffer-msaa"),
|
||||
size: msaa_texture_extent,
|
||||
mip_level_count: 1,
|
||||
sample_count: msaa_samples,
|
||||
dimension: wgpu::TextureDimension::D2,
|
||||
format: surface_config.format,
|
||||
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
|
||||
label: Some("[zsw::panel] MSAA framebuffer"),
|
||||
view_formats: &surface_config.view_formats,
|
||||
};
|
||||
|
||||
wgpu.device
|
||||
.create_texture(&msaa_frame_descriptor)
|
||||
.create_view(&wgpu::TextureViewDescriptor::default())
|
||||
.create_view(&wgpu::TextureViewDescriptor {
|
||||
label: Some("zsw-panel-framebuffer-msaa-view"),
|
||||
..Default::default()
|
||||
})
|
||||
}
|
||||
|
||||
/// Creates the uniforms bind group layout
|
||||
fn create_uniforms_bind_group_layout(wgpu: &Wgpu) -> wgpu::BindGroupLayout {
|
||||
let descriptor = wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("[zsw::panel] Geometry uniforms bind group layout"),
|
||||
label: Some("zsw-panel-geometry-uniforms-bind-group-layout"),
|
||||
entries: &[wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::VERTEX_FRAGMENT,
|
||||
|
||||
@ -7,7 +7,7 @@ use {
|
||||
image::{DynamicImage, imageops},
|
||||
std::{self, mem, path::Path, sync::Arc},
|
||||
tokio::sync::OnceCell,
|
||||
zsw_util::{AppError, Loadable, loadable::Loader},
|
||||
zsw_util::{AppError, Loadable},
|
||||
zsw_wgpu::Wgpu,
|
||||
zutil_cloned::cloned,
|
||||
};
|
||||
@ -40,14 +40,14 @@ pub struct PanelFadeImages {
|
||||
/// Next image
|
||||
pub next: Option<PanelFadeImage>,
|
||||
|
||||
/// Texture sampler
|
||||
/// Image sampler
|
||||
pub image_sampler: OnceCell<wgpu::Sampler>,
|
||||
|
||||
/// Texture bind group
|
||||
/// Image bind group
|
||||
pub image_bind_group: OnceCell<wgpu::BindGroup>,
|
||||
|
||||
/// Next image
|
||||
pub next_image: Loadable<ImageLoadRes, NextImageLoader>,
|
||||
pub next_image: Loadable<ImageLoadRes>,
|
||||
}
|
||||
|
||||
/// Panel's fade image
|
||||
@ -63,14 +63,6 @@ pub struct PanelFadeImage {
|
||||
pub path: Arc<Path>,
|
||||
}
|
||||
|
||||
|
||||
/// Arguments to the next image loader
|
||||
pub struct NextImageArgs {
|
||||
playlist_pos: usize,
|
||||
path: Arc<Path>,
|
||||
max_image_size: u32,
|
||||
}
|
||||
|
||||
impl PanelFadeImages {
|
||||
/// Creates a new panel
|
||||
#[must_use]
|
||||
@ -81,7 +73,7 @@ impl PanelFadeImages {
|
||||
next: None,
|
||||
image_sampler: OnceCell::new(),
|
||||
image_bind_group: OnceCell::new(),
|
||||
next_image: Loadable::new(NextImageLoader),
|
||||
next_image: Loadable::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -187,7 +179,8 @@ impl PanelFadeImages {
|
||||
};
|
||||
|
||||
if let Some(slot) = slot {
|
||||
let texture_view = match wgpu.create_texture_from_image(&res.path, image) {
|
||||
let texture_label = format!("zsw-panel-fade-image-texture[path={:?}]", res.path);
|
||||
let texture_view = match wgpu.create_texture_from_image(&texture_label, image) {
|
||||
Ok((_, texture_view)) => texture_view,
|
||||
Err(err) => {
|
||||
tracing::warn!("Unable to create texture for image {:?}: {}", res.path, err.pretty());
|
||||
@ -240,10 +233,18 @@ impl PanelFadeImages {
|
||||
|
||||
let max_image_size = wgpu.device.limits().max_texture_dimension_2d;
|
||||
|
||||
self.next_image.try_load(NextImageArgs {
|
||||
playlist_pos,
|
||||
path,
|
||||
max_image_size,
|
||||
self.next_image.try_load(|| {
|
||||
tokio::task::Builder::new()
|
||||
.name(&format!("Load image {path:?}"))
|
||||
.spawn_blocking(move || {
|
||||
let image_res = self::load(&path, max_image_size);
|
||||
ImageLoadRes {
|
||||
path,
|
||||
playlist_pos,
|
||||
image_res,
|
||||
}
|
||||
})
|
||||
.context("Unable to spawn task")
|
||||
})
|
||||
}
|
||||
|
||||
@ -253,25 +254,6 @@ impl PanelFadeImages {
|
||||
}
|
||||
}
|
||||
|
||||
/// Next image loader
|
||||
pub struct NextImageLoader;
|
||||
|
||||
impl Loader<NextImageArgs, ImageLoadRes> for NextImageLoader {
|
||||
fn spawn(&mut self, args: NextImageArgs) -> Result<tokio::task::JoinHandle<ImageLoadRes>, AppError> {
|
||||
tokio::task::Builder::new()
|
||||
.name(&format!("Load image {:?}", args.path))
|
||||
.spawn_blocking(move || {
|
||||
let image_res = self::load(&args.path, args.max_image_size);
|
||||
ImageLoadRes {
|
||||
path: args.path,
|
||||
playlist_pos: args.playlist_pos,
|
||||
image_res,
|
||||
}
|
||||
})
|
||||
.context("Unable to spawn task")
|
||||
}
|
||||
}
|
||||
|
||||
/// Image slot
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
|
||||
enum Slot {
|
||||
@ -313,7 +295,7 @@ pub fn load(path: &Arc<Path>, max_image_size: u32) -> Result<DynamicImage, AppEr
|
||||
/// Creates the fade image bind group layout
|
||||
fn create_bind_group_layout(wgpu: &Wgpu) -> wgpu::BindGroupLayout {
|
||||
let descriptor = wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("[zsw::panel] Fade image bind group layout"),
|
||||
label: Some("zsw-panel-fade-image-bind-group-layout"),
|
||||
entries: &[
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
@ -357,7 +339,7 @@ fn create_bind_group_layout(wgpu: &Wgpu) -> wgpu::BindGroupLayout {
|
||||
wgpu.device.create_bind_group_layout(&descriptor)
|
||||
}
|
||||
|
||||
/// Creates the texture bind group
|
||||
/// Creates the image bind group
|
||||
fn create_image_bind_group(
|
||||
wgpu: &Wgpu,
|
||||
bind_group_layout: &wgpu::BindGroupLayout,
|
||||
@ -367,6 +349,7 @@ fn create_image_bind_group(
|
||||
sampler: &wgpu::Sampler,
|
||||
) -> wgpu::BindGroup {
|
||||
let descriptor = wgpu::BindGroupDescriptor {
|
||||
label: Some("zsw-panel-fade-image-bind-group"),
|
||||
layout: bind_group_layout,
|
||||
entries: &[
|
||||
wgpu::BindGroupEntry {
|
||||
@ -386,7 +369,6 @@ fn create_image_bind_group(
|
||||
resource: wgpu::BindingResource::Sampler(sampler),
|
||||
},
|
||||
],
|
||||
label: Some("[zsw::panel] Image bind group"),
|
||||
};
|
||||
wgpu.device.create_bind_group(&descriptor)
|
||||
}
|
||||
@ -394,7 +376,7 @@ fn create_image_bind_group(
|
||||
/// Creates the image sampler
|
||||
fn create_image_sampler(wgpu: &Wgpu) -> wgpu::Sampler {
|
||||
let descriptor = wgpu::SamplerDescriptor {
|
||||
label: Some("[zsw::panel] Image sampler"),
|
||||
label: Some("zsw-panel-fade-image-sampler"),
|
||||
address_mode_u: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_v: wgpu::AddressMode::ClampToEdge,
|
||||
address_mode_w: wgpu::AddressMode::ClampToEdge,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user