16
16
17
17
//! A simple compute shader example that draws into a window, based on wgpu.
18
18
19
- use wgpu:: Extent3d ;
19
+ use wgpu:: util:: DeviceExt ;
20
+ use wgpu:: { BufferUsage , Extent3d } ;
21
+
20
22
use winit:: {
21
23
event:: { Event , WindowEvent } ,
22
24
event_loop:: { ControlFlow , EventLoop } ,
@@ -27,12 +29,10 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
27
29
let instance = wgpu:: Instance :: new ( wgpu:: BackendBit :: PRIMARY ) ;
28
30
let surface = unsafe { instance. create_surface ( & window) } ;
29
31
let adapter = instance
30
- . request_adapter (
31
- & wgpu:: RequestAdapterOptions {
32
- power_preference : Default :: default ( ) ,
33
- compatible_surface : Some ( & surface) ,
34
- } ,
35
- )
32
+ . request_adapter ( & wgpu:: RequestAdapterOptions {
33
+ power_preference : Default :: default ( ) ,
34
+ compatible_surface : Some ( & surface) ,
35
+ } )
36
36
. await
37
37
. expect ( "error finding adapter" ) ;
38
38
@@ -60,31 +60,32 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
60
60
source : wgpu:: ShaderSource :: Wgsl ( include_str ! ( "copy.wgsl" ) . into ( ) ) ,
61
61
flags : shader_flags,
62
62
} ) ;
63
- let copy_bind_group_layout = device. create_bind_group_layout ( & wgpu:: BindGroupLayoutDescriptor {
64
- label : None ,
65
- entries : & [
66
- wgpu:: BindGroupLayoutEntry {
67
- binding : 0 ,
68
- visibility : wgpu:: ShaderStage :: FRAGMENT ,
69
- ty : wgpu:: BindingType :: Texture {
70
- multisampled : false ,
71
- // Should filterable be false if we want nearest-neighbor?
72
- sample_type : wgpu:: TextureSampleType :: Float { filterable : true } ,
73
- view_dimension : wgpu:: TextureViewDimension :: D2 ,
63
+ let copy_bind_group_layout =
64
+ device. create_bind_group_layout ( & wgpu:: BindGroupLayoutDescriptor {
65
+ label : None ,
66
+ entries : & [
67
+ wgpu:: BindGroupLayoutEntry {
68
+ binding : 0 ,
69
+ visibility : wgpu:: ShaderStage :: FRAGMENT ,
70
+ ty : wgpu:: BindingType :: Texture {
71
+ multisampled : false ,
72
+ // Should filterable be false if we want nearest-neighbor?
73
+ sample_type : wgpu:: TextureSampleType :: Float { filterable : true } ,
74
+ view_dimension : wgpu:: TextureViewDimension :: D2 ,
75
+ } ,
76
+ count : None ,
74
77
} ,
75
- count : None ,
76
- } ,
77
- wgpu:: BindGroupLayoutEntry {
78
- binding : 1 ,
79
- visibility : wgpu :: ShaderStage :: FRAGMENT ,
80
- ty : wgpu :: BindingType :: Sampler {
81
- filtering : false ,
82
- comparison : false ,
78
+ wgpu :: BindGroupLayoutEntry {
79
+ binding : 1 ,
80
+ visibility : wgpu:: ShaderStage :: FRAGMENT ,
81
+ ty : wgpu :: BindingType :: Sampler {
82
+ filtering : false ,
83
+ comparison : false ,
84
+ } ,
85
+ count : None ,
83
86
} ,
84
- count : None ,
85
- } ,
86
- ]
87
- } ) ;
87
+ ] ,
88
+ } ) ;
88
89
let pipeline_layout = device. create_pipeline_layout ( & wgpu:: PipelineLayoutDescriptor {
89
90
label : None ,
90
91
bind_group_layouts : & [ & copy_bind_group_layout] ,
@@ -107,77 +108,108 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
107
108
depth_stencil : None ,
108
109
multisample : wgpu:: MultisampleState :: default ( ) ,
109
110
} ) ;
111
+
112
+ let img = device. create_texture ( & wgpu:: TextureDescriptor {
113
+ label : None ,
114
+ size : Extent3d {
115
+ width : size. width ,
116
+ height : size. height ,
117
+ depth_or_array_layers : 1 ,
118
+ } ,
119
+ mip_level_count : 1 ,
120
+ sample_count : 1 ,
121
+ dimension : wgpu:: TextureDimension :: D2 ,
122
+ format : wgpu:: TextureFormat :: Rgba8Unorm ,
123
+ usage : wgpu:: TextureUsage :: STORAGE | wgpu:: TextureUsage :: SAMPLED ,
124
+ } ) ;
125
+ let img_view = img. create_view ( & Default :: default ( ) ) ;
126
+
127
+ const CONFIG_SIZE : u64 = 12 ;
128
+
129
+ let config_dev = device. create_buffer ( & wgpu:: BufferDescriptor {
130
+ label : None ,
131
+ size : CONFIG_SIZE ,
132
+ usage : BufferUsage :: COPY_DST | BufferUsage :: STORAGE ,
133
+ mapped_at_creation : false ,
134
+ } ) ;
135
+ let config_resource = config_dev. as_entire_binding ( ) ;
136
+
137
+ let cs_module = device. create_shader_module ( & wgpu:: ShaderModuleDescriptor {
138
+ label : None ,
139
+ source : wgpu:: ShaderSource :: Wgsl ( include_str ! ( "paint.wgsl" ) . into ( ) ) ,
140
+ flags : shader_flags,
141
+ } ) ;
142
+ let pipeline = device. create_compute_pipeline ( & wgpu:: ComputePipelineDescriptor {
143
+ label : None ,
144
+ layout : None ,
145
+ module : & cs_module,
146
+ entry_point : "main" ,
147
+ } ) ;
148
+ let bind_group_layout = pipeline. get_bind_group_layout ( 0 ) ;
149
+ let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
150
+ label : None ,
151
+ layout : & bind_group_layout,
152
+ entries : & [
153
+ wgpu:: BindGroupEntry {
154
+ binding : 0 ,
155
+ resource : config_resource,
156
+ } ,
157
+ wgpu:: BindGroupEntry {
158
+ binding : 1 ,
159
+ resource : wgpu:: BindingResource :: TextureView ( & img_view) ,
160
+ } ,
161
+ ] ,
162
+ } ) ;
163
+ let sampler = device. create_sampler ( & wgpu:: SamplerDescriptor {
164
+ address_mode_u : wgpu:: AddressMode :: ClampToEdge ,
165
+ address_mode_v : wgpu:: AddressMode :: ClampToEdge ,
166
+ address_mode_w : wgpu:: AddressMode :: ClampToEdge ,
167
+ mag_filter : wgpu:: FilterMode :: Nearest ,
168
+ min_filter : wgpu:: FilterMode :: Nearest ,
169
+ mipmap_filter : wgpu:: FilterMode :: Nearest ,
170
+ ..Default :: default ( )
171
+ } ) ;
172
+ let copy_bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
173
+ label : None ,
174
+ layout : & copy_bind_group_layout,
175
+ entries : & [
176
+ wgpu:: BindGroupEntry {
177
+ binding : 0 ,
178
+ resource : wgpu:: BindingResource :: TextureView ( & img_view) ,
179
+ } ,
180
+ wgpu:: BindGroupEntry {
181
+ binding : 1 ,
182
+ resource : wgpu:: BindingResource :: Sampler ( & sampler) ,
183
+ } ,
184
+ ] ,
185
+ } ) ;
186
+ let start_time = std:: time:: Instant :: now ( ) ;
187
+
110
188
event_loop. run ( move |event, _, control_flow| {
111
- //println!("event {:?}", event);
112
- * control_flow = ControlFlow :: Wait ;
189
+ // TODO: this may be excessive polling. It really should be synchronized with
190
+ // swapchain presentation, but that's currently underbaked in wgpu.
191
+ * control_flow = ControlFlow :: Poll ;
113
192
match event {
114
193
Event :: RedrawRequested ( _) => {
115
194
let frame = swap_chain
116
195
. get_current_frame ( )
117
196
. expect ( "error getting frame from swap chain" )
118
197
. output ;
119
- let img = device. create_texture ( & wgpu:: TextureDescriptor {
120
- label : None ,
121
- size : Extent3d {
122
- width : size. width ,
123
- height : size. height ,
124
- depth_or_array_layers : 1 ,
125
- } ,
126
- mip_level_count : 1 ,
127
- sample_count : 1 ,
128
- dimension : wgpu:: TextureDimension :: D2 ,
129
- format : wgpu:: TextureFormat :: Rgba8Unorm ,
130
- usage : wgpu:: TextureUsage :: STORAGE | wgpu:: TextureUsage :: SAMPLED ,
131
- } ) ;
132
- let img_view = img. create_view ( & Default :: default ( ) ) ;
133
- let cs_module = device. create_shader_module ( & wgpu:: ShaderModuleDescriptor {
134
- label : None ,
135
- source : wgpu:: ShaderSource :: SpirV ( bytes_to_u32 ( include_bytes ! ( "paint.spv" ) ) . into ( ) ) ,
136
- //source: wgpu::ShaderSource::Wgsl(include_str!("paint.wgsl").into()),
137
- flags : shader_flags,
138
- } ) ;
139
- let pipeline = device. create_compute_pipeline ( & wgpu:: ComputePipelineDescriptor {
140
- label : None ,
141
- layout : None ,
142
- module : & cs_module,
143
- entry_point : "main" ,
144
- } ) ;
145
- let bind_group_layout = pipeline. get_bind_group_layout ( 0 ) ;
146
- let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
147
- label : None ,
148
- layout : & bind_group_layout,
149
- entries : & [ wgpu:: BindGroupEntry {
150
- binding : 0 ,
151
- resource : wgpu:: BindingResource :: TextureView ( & img_view) ,
152
- } ] ,
153
- } ) ;
154
- let sampler = device. create_sampler ( & wgpu:: SamplerDescriptor {
155
- address_mode_u : wgpu:: AddressMode :: ClampToEdge ,
156
- address_mode_v : wgpu:: AddressMode :: ClampToEdge ,
157
- address_mode_w : wgpu:: AddressMode :: ClampToEdge ,
158
- mag_filter : wgpu:: FilterMode :: Nearest ,
159
- min_filter : wgpu:: FilterMode :: Nearest ,
160
- mipmap_filter : wgpu:: FilterMode :: Nearest ,
161
- ..Default :: default ( )
162
- } ) ;
163
- let copy_bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
198
+
199
+ let i_time: f32 = 0.5 + start_time. elapsed ( ) . as_micros ( ) as f32 * 1e-6 ;
200
+ let config_data = [ size. width , size. height , i_time. to_bits ( ) ] ;
201
+ let config_host = device. create_buffer_init ( & wgpu:: util:: BufferInitDescriptor {
164
202
label : None ,
165
- layout : & copy_bind_group_layout,
166
- entries : & [ wgpu:: BindGroupEntry {
167
- binding : 0 ,
168
- resource : wgpu:: BindingResource :: TextureView ( & img_view) ,
169
- } ,
170
- wgpu:: BindGroupEntry {
171
- binding : 1 ,
172
- resource : wgpu:: BindingResource :: Sampler ( & sampler) ,
173
- } ] ,
203
+ contents : bytemuck:: bytes_of ( & config_data) ,
204
+ usage : BufferUsage :: COPY_SRC ,
174
205
} ) ;
175
206
let mut encoder = device. create_command_encoder ( & Default :: default ( ) ) ;
207
+ encoder. copy_buffer_to_buffer ( & config_host, 0 , & config_dev, 0 , CONFIG_SIZE ) ;
176
208
{
177
209
let mut cpass = encoder. begin_compute_pass ( & Default :: default ( ) ) ;
178
210
cpass. set_pipeline ( & pipeline) ;
179
211
cpass. set_bind_group ( 0 , & bind_group, & [ ] ) ;
180
- cpass. dispatch ( 1 , 1 , 1 ) ;
212
+ cpass. dispatch ( size . width / 16 , size . height / 16 , 1 ) ;
181
213
}
182
214
{
183
215
let mut rpass = encoder. begin_render_pass ( & wgpu:: RenderPassDescriptor {
@@ -198,6 +230,9 @@ async fn run(event_loop: EventLoop<()>, window: Window) {
198
230
}
199
231
queue. submit ( Some ( encoder. finish ( ) ) ) ;
200
232
}
233
+ Event :: MainEventsCleared => {
234
+ window. request_redraw ( ) ;
235
+ }
201
236
Event :: WindowEvent {
202
237
event : WindowEvent :: CloseRequested ,
203
238
..
@@ -212,16 +247,3 @@ fn main() {
212
247
let window = Window :: new ( & event_loop) . unwrap ( ) ;
213
248
pollster:: block_on ( run ( event_loop, window) ) ;
214
249
}
215
-
216
- // This will be used if we have spv shaders.
217
- #[ allow( unused) ]
218
- fn bytes_to_u32 ( bytes : & [ u8 ] ) -> Vec < u32 > {
219
- bytes
220
- . chunks_exact ( 4 )
221
- . map ( |b| {
222
- let mut bytes = [ 0 ; 4 ] ;
223
- bytes. copy_from_slice ( b) ;
224
- u32:: from_le_bytes ( bytes)
225
- } )
226
- . collect ( )
227
- }
0 commit comments