mirror of
https://github.com/bspeice/speice.io
synced 2025-04-26 15:51:31 -04:00
Refactor to allow running examples
This commit is contained in:
parent
8aeb3cc32a
commit
a976ddaf30
@ -1,15 +1,25 @@
|
||||
#![no_std]
|
||||
|
||||
use glam::Vec4Swizzles;
|
||||
use spirv_std::spirv;
|
||||
|
||||
pub trait DrawSettings: Copy + Sized + bytemuck::Pod + bytemuck::Zeroable {}
|
||||
|
||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct Viewport {
|
||||
pub offset: glam::UVec2,
|
||||
pub size: glam::UVec2,
|
||||
pub image: glam::UVec2,
|
||||
pub struct DrawSized {
|
||||
pub image_size: glam::UVec2,
|
||||
pub viewport_size: glam::UVec2,
|
||||
}
|
||||
impl DrawSettings for DrawSized {}
|
||||
|
||||
#[derive(Copy, Clone, bytemuck::Pod, bytemuck::Zeroable)]
|
||||
#[repr(C)]
|
||||
pub struct DrawRect {
|
||||
pub image_size: glam::UVec2,
|
||||
pub viewport_size: glam::UVec2,
|
||||
pub viewport_offset: glam::UVec2,
|
||||
}
|
||||
impl DrawSettings for DrawRect {}
|
||||
|
||||
const BLOCK_SIZE: usize = 16;
|
||||
const BLACK: glam::Vec4 = glam::vec4(0.0, 0.0, 0.0, 1.0);
|
||||
@ -19,13 +29,37 @@ fn image_index(x: usize, y: usize, width: usize) -> usize {
|
||||
y * width + x
|
||||
}
|
||||
|
||||
fn in_bounds(image_coordinate: glam::Vec2, image_size: glam::Vec2) -> bool {
|
||||
image_coordinate.cmpge(glam::Vec2::ZERO).all() && image_coordinate.cmplt(image_size).all()
|
||||
}
|
||||
|
||||
#[spirv(compute(threads(1)))]
|
||||
pub fn main_cs(
|
||||
#[spirv(uniform, descriptor_set = 0, binding = 0)] viewport: &Viewport,
|
||||
pub fn main_cs_bounding(
|
||||
#[spirv(uniform, descriptor_set = 0, binding = 0)] viewport: &DrawSized,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] image: &mut [glam::Vec4],
|
||||
) {
|
||||
let width = viewport.image.x as usize;
|
||||
let height = viewport.image.y as usize;
|
||||
let width = viewport.image_size.x as usize;
|
||||
let height = viewport.image_size.y as usize;
|
||||
|
||||
for x in 0..width {
|
||||
for y in 0..height {
|
||||
image[image_index(x, y, width)] =
|
||||
if x == 0 || x == width - 1 || y == 0 || y == height - 1 {
|
||||
WHITE
|
||||
} else {
|
||||
BLACK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[spirv(compute(threads(1)))]
|
||||
pub fn main_cs_blocks(
|
||||
#[spirv(uniform, descriptor_set = 0, binding = 0)] viewport: &DrawSized,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] image: &mut [glam::Vec4],
|
||||
) {
|
||||
let width = viewport.image_size.x as usize;
|
||||
let height = viewport.image_size.y as usize;
|
||||
for x in 0..width {
|
||||
let x_even = x / BLOCK_SIZE % 2 == 0;
|
||||
for y in 0..height {
|
||||
@ -48,24 +82,50 @@ pub fn main_vs(
|
||||
}
|
||||
|
||||
#[spirv(fragment)]
|
||||
pub fn main_fs(
|
||||
pub fn main_fs_size(
|
||||
#[spirv(frag_coord)] frag_coord: glam::Vec4,
|
||||
#[spirv(uniform, descriptor_set = 0, binding = 0)] viewport: &Viewport,
|
||||
#[spirv(uniform, descriptor_set = 0, binding = 0)] draw_settings: &DrawSized,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] image: &mut [glam::Vec4],
|
||||
output: &mut glam::Vec4,
|
||||
) {
|
||||
let vp_size = viewport.size.as_vec2();
|
||||
let img_size = viewport.image.as_vec2();
|
||||
let vp_size = draw_settings.viewport_size.as_vec2();
|
||||
let img_size = draw_settings.image_size.as_vec2();
|
||||
|
||||
let scale = (vp_size / img_size).min_element();
|
||||
let img_offset = (vp_size / scale - img_size) / 2.0;
|
||||
let img_coord = (frag_coord.xy() - viewport.offset.as_vec2()) / scale - img_offset;
|
||||
let img_coord = frag_coord.xy() / scale - img_offset;
|
||||
|
||||
*output = if img_coord.cmpge(glam::Vec2::ZERO).all() && img_coord.cmple(img_size).all() {
|
||||
*output = if in_bounds(img_coord, img_size) {
|
||||
image[image_index(
|
||||
img_coord.x as usize,
|
||||
img_coord.y as usize,
|
||||
viewport.image.x as usize,
|
||||
img_size.x as usize,
|
||||
)]
|
||||
} else {
|
||||
BLACK
|
||||
}
|
||||
}
|
||||
|
||||
#[spirv(fragment)]
|
||||
pub fn main_fs_rect(
|
||||
#[spirv(frag_coord)] frag_coord: glam::Vec4,
|
||||
#[spirv(uniform, descriptor_set = 0, binding = 0)] draw_settings: &DrawRect,
|
||||
#[spirv(storage_buffer, descriptor_set = 0, binding = 1)] image: &mut [glam::Vec4],
|
||||
output: &mut glam::Vec4,
|
||||
) {
|
||||
let vp_size = draw_settings.viewport_size.as_vec2();
|
||||
let img_size = draw_settings.image_size.as_vec2();
|
||||
|
||||
let scale = (vp_size / img_size).min_element();
|
||||
let img_offset = (vp_size / scale - img_size) / 2.0;
|
||||
let img_coord =
|
||||
(frag_coord.xy() - draw_settings.viewport_offset.as_vec2()) / scale - img_offset;
|
||||
|
||||
*output = if in_bounds(img_coord, img_size) {
|
||||
image[image_index(
|
||||
img_coord.x as usize,
|
||||
img_coord.y as usize,
|
||||
img_size.x as usize,
|
||||
)]
|
||||
} else {
|
||||
BLACK
|
||||
|
@ -0,0 +1,16 @@
|
||||
use draw_compute::draw_shaders::ShaderBounding;
|
||||
use draw_compute::ComputeDraw;
|
||||
|
||||
fn main() {
|
||||
let native_options = eframe::NativeOptions {
|
||||
renderer: eframe::Renderer::Wgpu,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"Compute Draw",
|
||||
native_options,
|
||||
Box::new(|_cc| Ok(Box::new(ComputeDraw::<ShaderBounding>::new()))),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
use draw_compute::draw_shaders::ShaderOffset;
|
||||
use draw_compute::ComputeDraw;
|
||||
|
||||
fn main() {
|
||||
let native_options = eframe::NativeOptions {
|
||||
renderer: eframe::Renderer::Wgpu,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"Compute Draw",
|
||||
native_options,
|
||||
Box::new(|_cc| Ok(Box::new(ComputeDraw::<ShaderOffset>::new()))),
|
||||
).unwrap()
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
use draw_compute::draw_shaders::ShaderOffsetBlocks;
|
||||
use draw_compute::ComputeDraw;
|
||||
|
||||
fn main() {
|
||||
let native_options = eframe::NativeOptions {
|
||||
renderer: eframe::Renderer::Wgpu,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"Compute Draw",
|
||||
native_options,
|
||||
Box::new(|_cc| Ok(Box::new(ComputeDraw::<ShaderOffsetBlocks>::new()))),
|
||||
).unwrap()
|
||||
}
|
@ -1,26 +1,34 @@
|
||||
use eframe::epaint::PaintCallbackInfo;
|
||||
use eframe::wgpu::{CommandBuffer, CommandEncoder, Device, Queue, RenderPass};
|
||||
use eframe::Frame;
|
||||
use egui::{Context, Sense};
|
||||
use egui_wgpu::{CallbackResources, CallbackTrait, ScreenDescriptor};
|
||||
use shader::DrawSettings;
|
||||
use std::marker::PhantomData;
|
||||
|
||||
struct DrawResources {
|
||||
device: wgpu::Device,
|
||||
bind_group_layout: wgpu::BindGroupLayout,
|
||||
bind_group: wgpu::BindGroup,
|
||||
viewport_buffer: wgpu::Buffer,
|
||||
image_buffer: wgpu::Buffer,
|
||||
image_size: glam::UVec2,
|
||||
compute_pipeline: wgpu::ComputePipeline,
|
||||
render_pipeline: wgpu::RenderPipeline,
|
||||
pub trait ShaderSettings: Send + Sync {
|
||||
type DrawSettings: DrawSettings;
|
||||
|
||||
fn compute_shader() -> &'static str;
|
||||
fn fragment_shader() -> &'static str;
|
||||
|
||||
fn new(interact_rect: egui::Rect) -> Self;
|
||||
|
||||
fn write_buffer(&self, queue: &wgpu::Queue, buffer: &wgpu::Buffer, image_size: glam::UVec2);
|
||||
}
|
||||
|
||||
impl DrawResources {
|
||||
pub struct DrawResources<S: ShaderSettings> {
|
||||
bind_group_layout: wgpu::BindGroupLayout,
|
||||
pub bind_group: wgpu::BindGroup,
|
||||
pub viewport_buffer: wgpu::Buffer,
|
||||
image_buffer: wgpu::Buffer,
|
||||
pub image_size: glam::UVec2,
|
||||
pub compute_pipeline: wgpu::ComputePipeline,
|
||||
pub render_pipeline: wgpu::RenderPipeline,
|
||||
settings: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<S: ShaderSettings> DrawResources<S> {
|
||||
fn bind_group_layout(device: &wgpu::Device) -> wgpu::BindGroupLayout {
|
||||
device.create_bind_group_layout(&wgpu::BindGroupLayoutDescriptor {
|
||||
label: Some("compute_draw"),
|
||||
entries: &[
|
||||
// viewport
|
||||
// draw_settings
|
||||
wgpu::BindGroupLayoutEntry {
|
||||
binding: 0,
|
||||
visibility: wgpu::ShaderStages::COMPUTE | wgpu::ShaderStages::FRAGMENT,
|
||||
@ -71,7 +79,7 @@ impl DrawResources {
|
||||
fn viewport_buffer(device: &wgpu::Device) -> wgpu::Buffer {
|
||||
device.create_buffer(&wgpu::BufferDescriptor {
|
||||
label: Some("viewport"),
|
||||
size: size_of::<shader::Viewport>() as u64,
|
||||
size: size_of::<S::DrawSettings>() as u64,
|
||||
usage: wgpu::BufferUsages::COPY_DST | wgpu::BufferUsages::UNIFORM,
|
||||
mapped_at_creation: false,
|
||||
})
|
||||
@ -105,7 +113,7 @@ impl DrawResources {
|
||||
label: Some("compute"),
|
||||
layout: Some(&pipeline_layout),
|
||||
module: &module,
|
||||
entry_point: Some("main_cs"),
|
||||
entry_point: Some(S::compute_shader()),
|
||||
compilation_options: Default::default(),
|
||||
cache: None,
|
||||
})
|
||||
@ -136,7 +144,7 @@ impl DrawResources {
|
||||
multisample: Default::default(),
|
||||
fragment: Some(wgpu::FragmentState {
|
||||
module,
|
||||
entry_point: Some("main_fs"),
|
||||
entry_point: Some(S::fragment_shader()),
|
||||
compilation_options: Default::default(),
|
||||
targets: &[Some((*format).into())],
|
||||
}),
|
||||
@ -145,7 +153,12 @@ impl DrawResources {
|
||||
})
|
||||
}
|
||||
|
||||
fn new(device: &wgpu::Device, format: &wgpu::TextureFormat, width: u64, height: u64) -> Self {
|
||||
pub fn new(
|
||||
device: &wgpu::Device,
|
||||
format: &wgpu::TextureFormat,
|
||||
width: u64,
|
||||
height: u64,
|
||||
) -> Self {
|
||||
let bind_group_layout = Self::bind_group_layout(device);
|
||||
let viewport_buffer = Self::viewport_buffer(device);
|
||||
let image_buffer = Self::image_buffer(device, width, height);
|
||||
@ -159,7 +172,6 @@ impl DrawResources {
|
||||
let render_pipeline = Self::render_pipeline(device, &module, &bind_group_layout, format);
|
||||
|
||||
Self {
|
||||
device: device.clone(),
|
||||
bind_group_layout,
|
||||
bind_group,
|
||||
viewport_buffer,
|
||||
@ -167,156 +179,18 @@ impl DrawResources {
|
||||
image_size,
|
||||
compute_pipeline,
|
||||
render_pipeline,
|
||||
settings: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn resize(&mut self, width: u64, height: u64) {
|
||||
self.image_buffer = Self::image_buffer(&self.device, width, height);
|
||||
pub fn resize(&mut self, device: &wgpu::Device, width: u64, height: u64) {
|
||||
self.image_buffer = Self::image_buffer(device, width, height);
|
||||
self.image_size = glam::uvec2(width as u32, height as u32);
|
||||
self.bind_group = Self::bind_group(
|
||||
&self.device,
|
||||
device,
|
||||
&self.bind_group_layout,
|
||||
&self.viewport_buffer,
|
||||
&self.image_buffer,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
struct DrawCallback {
|
||||
draw_rect: egui::Rect,
|
||||
draw_resize: bool,
|
||||
}
|
||||
|
||||
impl CallbackTrait for DrawCallback {
|
||||
fn prepare(
|
||||
&self,
|
||||
_device: &Device,
|
||||
queue: &Queue,
|
||||
_screen_descriptor: &ScreenDescriptor,
|
||||
egui_encoder: &mut CommandEncoder,
|
||||
callback_resources: &mut CallbackResources,
|
||||
) -> Vec<CommandBuffer> {
|
||||
let resources = callback_resources
|
||||
.get_mut::<DrawResources>()
|
||||
.expect("missing draw resources");
|
||||
|
||||
if self.draw_resize {
|
||||
resources.resize(
|
||||
self.draw_rect.size().x as u64,
|
||||
self.draw_rect.size().y as u64,
|
||||
);
|
||||
}
|
||||
|
||||
let viewport = shader::Viewport {
|
||||
image: resources.image_size,
|
||||
offset: glam::uvec2(self.draw_rect.min.x as u32, self.draw_rect.min.y as u32),
|
||||
size: glam::uvec2(
|
||||
self.draw_rect.size().x as u32,
|
||||
self.draw_rect.size().y as u32,
|
||||
),
|
||||
};
|
||||
|
||||
queue.write_buffer(
|
||||
&resources.viewport_buffer,
|
||||
0,
|
||||
bytemuck::cast_slice(&[viewport]),
|
||||
);
|
||||
|
||||
if self.draw_resize {
|
||||
let mut compute_pass = egui_encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
label: Some("compute"),
|
||||
timestamp_writes: None,
|
||||
});
|
||||
|
||||
compute_pass.set_pipeline(&resources.compute_pipeline);
|
||||
compute_pass.set_bind_group(0, &resources.bind_group, &[]);
|
||||
compute_pass.dispatch_workgroups(1, 1, 1);
|
||||
}
|
||||
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&self,
|
||||
_info: PaintCallbackInfo,
|
||||
render_pass: &mut RenderPass<'static>,
|
||||
callback_resources: &CallbackResources,
|
||||
) {
|
||||
let resources = callback_resources.get::<DrawResources>().unwrap();
|
||||
|
||||
render_pass.set_pipeline(&resources.render_pipeline);
|
||||
render_pass.set_bind_group(0, &resources.bind_group, &[]);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
struct ComputeDraw {
|
||||
initial_draw: bool,
|
||||
}
|
||||
|
||||
impl eframe::App for ComputeDraw {
|
||||
fn update(&mut self, ctx: &Context, frame: &mut Frame) {
|
||||
let initial_draw = self.initial_draw;
|
||||
self.initial_draw = false;
|
||||
|
||||
if initial_draw {
|
||||
let wgpu_render_state = frame.wgpu_render_state().expect("missing WGPU state");
|
||||
let device = wgpu_render_state.device.clone();
|
||||
let format = wgpu_render_state.target_format.clone();
|
||||
let callback_resources = &mut wgpu_render_state
|
||||
.renderer
|
||||
.as_ref()
|
||||
.write()
|
||||
.callback_resources;
|
||||
|
||||
// Guess an initial size for initializing GPU resources, it will be adjusted later
|
||||
callback_resources.insert(DrawResources::new(&device, &format, 800, 600));
|
||||
}
|
||||
|
||||
egui::TopBottomPanel::bottom("bottom").show(ctx, |ui| {
|
||||
let wgpu_render_state = frame.wgpu_render_state().expect("missing WGPU state");
|
||||
let image_size = wgpu_render_state
|
||||
.renderer
|
||||
.as_ref()
|
||||
.read()
|
||||
.callback_resources
|
||||
.get::<DrawResources>()
|
||||
.unwrap()
|
||||
.image_size;
|
||||
|
||||
ui.label(format!("Viewport: image={image_size}"))
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
egui::Frame::canvas(ui.style()).show(ui, |ui| {
|
||||
let interact_rect = ui.available_rect_before_wrap();
|
||||
let (response, painter) = ui.allocate_painter(interact_rect.size(), Sense::click());
|
||||
|
||||
let callback = DrawCallback {
|
||||
draw_rect: interact_rect,
|
||||
draw_resize: initial_draw || response.clicked(),
|
||||
};
|
||||
|
||||
painter.add(egui_wgpu::Callback::new_paint_callback(
|
||||
interact_rect,
|
||||
callback,
|
||||
))
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let native_options = eframe::NativeOptions {
|
||||
renderer: eframe::Renderer::Wgpu,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"Compute Draw",
|
||||
native_options,
|
||||
Box::new(|_cc| Ok(Box::new(ComputeDraw { initial_draw: true }))),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
use crate::draw_resources::ShaderSettings;
|
||||
use glam::UVec2;
|
||||
use shader::{DrawRect, DrawSized};
|
||||
use wgpu::{Buffer, Queue};
|
||||
|
||||
pub struct ShaderBounding {
|
||||
draw_size: egui::Vec2,
|
||||
}
|
||||
|
||||
impl ShaderSettings for ShaderBounding {
|
||||
type DrawSettings = DrawSized;
|
||||
|
||||
fn compute_shader() -> &'static str {
|
||||
"main_cs_bounding"
|
||||
}
|
||||
|
||||
fn fragment_shader() -> &'static str {
|
||||
"main_fs_size"
|
||||
}
|
||||
|
||||
fn new(interact_rect: egui::Rect) -> Self {
|
||||
Self {
|
||||
draw_size: interact_rect.size()
|
||||
}
|
||||
}
|
||||
|
||||
fn write_buffer(&self, queue: &Queue, buffer: &Buffer, image_size: glam::UVec2) {
|
||||
let draw_settings = DrawSized {
|
||||
image_size,
|
||||
viewport_size: glam::uvec2(self.draw_size.x as u32, self.draw_size.y as u32),
|
||||
};
|
||||
queue.write_buffer(&buffer, 0, bytemuck::cast_slice(&[draw_settings]));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShaderOffset {
|
||||
draw_rect: egui::Rect,
|
||||
}
|
||||
|
||||
impl ShaderSettings for ShaderOffset {
|
||||
type DrawSettings = DrawRect;
|
||||
|
||||
fn compute_shader() -> &'static str {
|
||||
"main_cs_bounding"
|
||||
}
|
||||
|
||||
fn fragment_shader() -> &'static str {
|
||||
"main_fs_rect"
|
||||
}
|
||||
|
||||
fn new(interact_rect: egui::Rect) -> Self {
|
||||
Self { draw_rect: interact_rect }
|
||||
}
|
||||
|
||||
fn write_buffer(&self, queue: &Queue, buffer: &Buffer, image_size: UVec2) {
|
||||
let viewport_size = glam::uvec2(self.draw_rect.size().x as u32, self.draw_rect.size().y as u32);
|
||||
let viewport_offset = glam::uvec2(self.draw_rect.min.x as u32, self.draw_rect.min.y as u32);
|
||||
let draw_settings = DrawRect {
|
||||
image_size,
|
||||
viewport_size,
|
||||
viewport_offset
|
||||
};
|
||||
queue.write_buffer(&buffer, 0, bytemuck::cast_slice(&[draw_settings]));
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ShaderOffsetBlocks {
|
||||
draw_rect: egui::Rect,
|
||||
}
|
||||
|
||||
impl ShaderSettings for ShaderOffsetBlocks {
|
||||
type DrawSettings = DrawRect;
|
||||
|
||||
fn compute_shader() -> &'static str {
|
||||
"main_cs_blocks"
|
||||
}
|
||||
|
||||
fn fragment_shader() -> &'static str {
|
||||
"main_fs_rect"
|
||||
}
|
||||
|
||||
fn new(interact_rect: egui::Rect) -> Self {
|
||||
Self { draw_rect: interact_rect }
|
||||
}
|
||||
|
||||
fn write_buffer(&self, queue: &Queue, buffer: &Buffer, image_size: UVec2) {
|
||||
let viewport_size = glam::uvec2(self.draw_rect.size().x as u32, self.draw_rect.size().y as u32);
|
||||
let viewport_offset = glam::uvec2(self.draw_rect.min.x as u32, self.draw_rect.min.y as u32);
|
||||
let draw_settings = DrawRect {
|
||||
image_size,
|
||||
viewport_size,
|
||||
viewport_offset
|
||||
};
|
||||
queue.write_buffer(&buffer, 0, bytemuck::cast_slice(&[draw_settings]));
|
||||
}
|
||||
}
|
158
blog/2025-03-30-draw-compute-shader/draw-compute/src/lib.rs
Normal file
158
blog/2025-03-30-draw-compute-shader/draw-compute/src/lib.rs
Normal file
@ -0,0 +1,158 @@
|
||||
mod draw_resources;
|
||||
pub mod draw_shaders;
|
||||
|
||||
use std::marker::PhantomData;
|
||||
use eframe::Frame;
|
||||
use egui::{Context, Sense};
|
||||
|
||||
use crate::draw_resources::{DrawResources, ShaderSettings};
|
||||
use eframe::epaint::PaintCallbackInfo;
|
||||
use egui_wgpu::{CallbackResources, CallbackTrait, ScreenDescriptor};
|
||||
use wgpu::{CommandBuffer, CommandEncoder, Device, Queue, RenderPass};
|
||||
|
||||
struct DrawCallback<S> {
|
||||
interact_rect: egui::Rect,
|
||||
interact_resize: bool,
|
||||
settings: S,
|
||||
}
|
||||
|
||||
impl<S: ShaderSettings> DrawCallback<S> {
|
||||
fn new(interact_rect: egui::Rect, interact_resize: bool) -> Self {
|
||||
Self {
|
||||
interact_rect,
|
||||
interact_resize,
|
||||
settings: S::new(interact_rect),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ShaderSettings + Send + Sync + 'static> CallbackTrait for DrawCallback<S> {
|
||||
fn prepare(
|
||||
&self,
|
||||
device: &Device,
|
||||
queue: &Queue,
|
||||
_screen_descriptor: &ScreenDescriptor,
|
||||
egui_encoder: &mut CommandEncoder,
|
||||
callback_resources: &mut CallbackResources,
|
||||
) -> Vec<CommandBuffer> {
|
||||
let resources = callback_resources
|
||||
.get_mut::<DrawResources<S>>()
|
||||
.expect("missing draw resources");
|
||||
|
||||
if self.interact_resize {
|
||||
resources.resize(
|
||||
device,
|
||||
self.interact_rect.width() as u64,
|
||||
self.interact_rect.height() as u64,
|
||||
);
|
||||
}
|
||||
|
||||
self.settings.write_buffer(queue, &resources.viewport_buffer, resources.image_size);
|
||||
|
||||
if self.interact_resize {
|
||||
let mut compute_pass = egui_encoder.begin_compute_pass(&wgpu::ComputePassDescriptor {
|
||||
label: Some("compute"),
|
||||
timestamp_writes: None,
|
||||
});
|
||||
|
||||
compute_pass.set_pipeline(&resources.compute_pipeline);
|
||||
compute_pass.set_bind_group(0, &resources.bind_group, &[]);
|
||||
compute_pass.dispatch_workgroups(1, 1, 1);
|
||||
}
|
||||
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&self,
|
||||
_info: PaintCallbackInfo,
|
||||
render_pass: &mut RenderPass<'static>,
|
||||
callback_resources: &CallbackResources,
|
||||
) {
|
||||
let resources = callback_resources.get::<DrawResources<S>>().unwrap();
|
||||
|
||||
render_pass.set_pipeline(&resources.render_pipeline);
|
||||
render_pass.set_bind_group(0, &resources.bind_group, &[]);
|
||||
render_pass.draw(0..3, 0..1);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ComputeDraw<S> {
|
||||
initial_draw: bool,
|
||||
settings: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl <S: ShaderSettings> ComputeDraw<S> {
|
||||
pub fn new() -> Self {
|
||||
ComputeDraw {
|
||||
initial_draw: true,
|
||||
settings: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: ShaderSettings + 'static> eframe::App for ComputeDraw<S> {
|
||||
fn update(&mut self, ctx: &Context, frame: &mut Frame) {
|
||||
let initial_draw = self.initial_draw;
|
||||
self.initial_draw = false;
|
||||
|
||||
if initial_draw {
|
||||
let wgpu_render_state = frame.wgpu_render_state().expect("missing WGPU state");
|
||||
let device = wgpu_render_state.device.clone();
|
||||
let format = wgpu_render_state.target_format.clone();
|
||||
let callback_resources = &mut wgpu_render_state
|
||||
.renderer
|
||||
.as_ref()
|
||||
.write()
|
||||
.callback_resources;
|
||||
|
||||
// Guess an initial size for initializing GPU resources, it will be adjusted later
|
||||
callback_resources.insert(DrawResources::<S>::new(&device, &format, 800, 600));
|
||||
}
|
||||
|
||||
/*
|
||||
egui::TopBottomPanel::bottom("bottom").show(ctx, |ui| {
|
||||
let wgpu_render_state = frame.wgpu_render_state().expect("missing WGPU state");
|
||||
let image_size = wgpu_render_state
|
||||
.renderer
|
||||
.as_ref()
|
||||
.read()
|
||||
.callback_resources
|
||||
.get::<DrawResources<DrawSimple>>()
|
||||
.unwrap()
|
||||
.image_size;
|
||||
|
||||
ui.label(format!("Viewport: image={image_size}"))
|
||||
});
|
||||
*/
|
||||
|
||||
egui::CentralPanel::default().show(ctx, |ui| {
|
||||
egui::Frame::canvas(ui.style()).show(ui, |ui| {
|
||||
let interact_rect = ui.available_rect_before_wrap();
|
||||
let (response, painter) = ui.allocate_painter(interact_rect.size(), Sense::click());
|
||||
|
||||
painter.add(egui_wgpu::Callback::new_paint_callback(
|
||||
interact_rect,
|
||||
DrawCallback::<S>::new(interact_rect, initial_draw || response.clicked()),
|
||||
))
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
fn main() {
|
||||
let native_options = eframe::NativeOptions {
|
||||
renderer: eframe::Renderer::Wgpu,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
eframe::run_native(
|
||||
"Compute Draw",
|
||||
native_options,
|
||||
Box::new(|_cc| Ok(Box::new(ComputeDraw { initial_draw: true }))),
|
||||
)
|
||||
.unwrap()
|
||||
}
|
||||
*/
|
Loading…
Reference in New Issue
Block a user