mirror of
https://github.com/slint-ui/slint.git
synced 2025-08-27 22:04:08 +00:00

- Create a `slint::wgpu_24` module - Re-export `wgpu` in it - Place the WGPU config types used by the `BackendSelector::require_wgpu_24` function in it, and remove the 24 infix. As an upside, this also adds the feature guard to the docs at least for the `wgpu_24` module.
194 lines
7 KiB
Rust
194 lines
7 KiB
Rust
// Copyright © SixtyFPS GmbH <info@slint.dev>
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
slint::include_modules!();
|
|
|
|
use slint::wgpu_24::{wgpu, WGPUConfiguration, WGPUSettings};
|
|
|
|
struct DemoRenderer {
|
|
device: wgpu::Device,
|
|
queue: wgpu::Queue,
|
|
pipeline: wgpu::RenderPipeline,
|
|
displayed_texture: wgpu::Texture,
|
|
next_texture: wgpu::Texture,
|
|
start_time: std::time::Instant,
|
|
}
|
|
|
|
#[repr(C)]
|
|
#[derive(Clone, Copy, bytemuck::Pod, bytemuck::Zeroable)]
|
|
struct PushConstants {
|
|
light_color_and_time: [f32; 4],
|
|
}
|
|
|
|
impl DemoRenderer {
|
|
fn new(device: &wgpu::Device, queue: &wgpu::Queue) -> Self {
|
|
let shader = device.create_shader_module(wgpu::ShaderModuleDescriptor {
|
|
label: None,
|
|
source: wgpu::ShaderSource::Wgsl(std::borrow::Cow::Borrowed(include_str!(
|
|
"shader.wgsl"
|
|
))),
|
|
});
|
|
|
|
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
|
|
label: None,
|
|
bind_group_layouts: &[],
|
|
push_constant_ranges: &[wgpu::PushConstantRange {
|
|
stages: wgpu::ShaderStages::FRAGMENT,
|
|
range: 0..16, // full size in bytes, aligned
|
|
}],
|
|
});
|
|
|
|
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
|
|
label: None,
|
|
layout: Some(&pipeline_layout),
|
|
vertex: wgpu::VertexState {
|
|
module: &shader,
|
|
entry_point: Some("vs_main"),
|
|
buffers: &[],
|
|
compilation_options: Default::default(),
|
|
},
|
|
fragment: Some(wgpu::FragmentState {
|
|
module: &shader,
|
|
entry_point: Some("fs_main"),
|
|
compilation_options: Default::default(),
|
|
targets: &[Some(wgpu::TextureFormat::Rgba8Unorm.into())],
|
|
}),
|
|
primitive: wgpu::PrimitiveState::default(),
|
|
depth_stencil: None,
|
|
multisample: wgpu::MultisampleState::default(),
|
|
multiview: None,
|
|
cache: None,
|
|
});
|
|
|
|
let displayed_texture = Self::create_texture(&device, 320, 200);
|
|
let next_texture = Self::create_texture(&device, 320, 200);
|
|
|
|
Self {
|
|
device: device.clone(),
|
|
queue: queue.clone(),
|
|
pipeline,
|
|
displayed_texture,
|
|
next_texture,
|
|
start_time: std::time::Instant::now(),
|
|
}
|
|
}
|
|
|
|
fn create_texture(device: &wgpu::Device, width: u32, height: u32) -> wgpu::Texture {
|
|
device.create_texture(&wgpu::TextureDescriptor {
|
|
label: None,
|
|
size: wgpu::Extent3d { width, height, depth_or_array_layers: 1 },
|
|
mip_level_count: 1,
|
|
sample_count: 1,
|
|
dimension: wgpu::TextureDimension::D2,
|
|
format: wgpu::TextureFormat::Rgba8Unorm,
|
|
usage: wgpu::TextureUsages::RENDER_ATTACHMENT | wgpu::TextureUsages::TEXTURE_BINDING,
|
|
view_formats: &[],
|
|
})
|
|
}
|
|
|
|
fn render(
|
|
&mut self,
|
|
light_red: f32,
|
|
light_green: f32,
|
|
light_blue: f32,
|
|
width: u32,
|
|
height: u32,
|
|
) -> wgpu::Texture {
|
|
if self.next_texture.size().width != width || self.next_texture.size().height != height {
|
|
let mut new_texture = Self::create_texture(&self.device, width, height);
|
|
std::mem::swap(&mut self.next_texture, &mut new_texture);
|
|
}
|
|
|
|
let elapsed: f32 = self.start_time.elapsed().as_millis() as f32 / 500.;
|
|
let push_constants =
|
|
PushConstants { light_color_and_time: [light_red, light_green, light_blue, elapsed] };
|
|
|
|
let mut encoder =
|
|
self.device.create_command_encoder(&wgpu::CommandEncoderDescriptor { label: None });
|
|
{
|
|
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
|
|
label: None,
|
|
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
|
|
view: &self.next_texture.create_view(&wgpu::TextureViewDescriptor::default()),
|
|
resolve_target: None,
|
|
ops: wgpu::Operations {
|
|
load: wgpu::LoadOp::Clear(wgpu::Color::GREEN),
|
|
store: wgpu::StoreOp::Store,
|
|
},
|
|
})],
|
|
depth_stencil_attachment: None,
|
|
timestamp_writes: None,
|
|
occlusion_query_set: None,
|
|
});
|
|
rpass.set_pipeline(&self.pipeline);
|
|
rpass.set_push_constants(
|
|
wgpu::ShaderStages::FRAGMENT, // Stage (your constants are for fragment shader)
|
|
0, // Offset in bytes (start at 0)
|
|
bytemuck::bytes_of(&push_constants),
|
|
);
|
|
rpass.draw(0..3, 0..1);
|
|
}
|
|
|
|
self.queue.submit(Some(encoder.finish()));
|
|
|
|
let result_texture = self.next_texture.clone();
|
|
|
|
std::mem::swap(&mut self.next_texture, &mut self.displayed_texture);
|
|
|
|
result_texture
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let mut wgpu_settings = WGPUSettings::default();
|
|
wgpu_settings.device_required_features = wgpu::Features::PUSH_CONSTANTS;
|
|
wgpu_settings.device_required_limits.max_push_constant_size = 16;
|
|
|
|
slint::BackendSelector::new()
|
|
.require_wgpu_24(WGPUConfiguration::Automatic(wgpu_settings))
|
|
.select()
|
|
.expect("Unable to create Slint backend with WGPU based renderer");
|
|
|
|
let app = App::new().unwrap();
|
|
|
|
let mut underlay = None;
|
|
|
|
let app_weak = app.as_weak();
|
|
|
|
app.window()
|
|
.set_rendering_notifier(move |state, graphics_api| {
|
|
//eprintln!("rendering state {:#?} {:#?}", state, graphics_api);
|
|
|
|
match state {
|
|
slint::RenderingState::RenderingSetup => {
|
|
match graphics_api {
|
|
slint::GraphicsAPI::WGPU24 { device, queue, .. } => {
|
|
underlay = Some(DemoRenderer::new(device, queue));
|
|
}
|
|
_ => return,
|
|
};
|
|
}
|
|
slint::RenderingState::BeforeRendering => {
|
|
if let (Some(underlay), Some(app)) = (underlay.as_mut(), app_weak.upgrade()) {
|
|
let texture = underlay.render(
|
|
app.get_selected_red(),
|
|
app.get_selected_green(),
|
|
app.get_selected_blue(),
|
|
app.get_requested_texture_width() as u32,
|
|
app.get_requested_texture_height() as u32,
|
|
);
|
|
app.set_texture(slint::Image::try_from(texture).unwrap());
|
|
app.window().request_redraw();
|
|
}
|
|
}
|
|
slint::RenderingState::AfterRendering => {}
|
|
slint::RenderingState::RenderingTeardown => {
|
|
drop(underlay.take());
|
|
}
|
|
_ => {}
|
|
}
|
|
})
|
|
.expect("Unable to set rendering notifier");
|
|
|
|
app.run().unwrap();
|
|
}
|