1
1
use super :: { shader_module, Options } ;
2
- use core:: num:: NonZeroU64 ;
2
+ use std:: convert:: TryInto ;
3
+ use wgpu:: util:: DeviceExt ;
3
4
4
- fn create_device_queue ( ) -> ( wgpu:: Device , wgpu:: Queue ) {
5
+ async fn create_device_queue ( ) -> ( wgpu:: Device , wgpu:: Queue ) {
5
6
async fn create_device_queue_async ( ) -> ( wgpu:: Device , wgpu:: Queue ) {
6
7
let instance = wgpu:: Instance :: new ( wgpu:: BackendBit :: PRIMARY ) ;
7
8
let adapter = instance
8
9
. request_adapter ( & wgpu:: RequestAdapterOptions {
9
- power_preference : wgpu:: PowerPreference :: default ( ) ,
10
+ power_preference : wgpu:: PowerPreference :: Default ,
10
11
compatible_surface : None ,
11
12
} )
12
13
. await
@@ -28,33 +29,57 @@ fn create_device_queue() -> (wgpu::Device, wgpu::Queue) {
28
29
if #[ cfg( target_arch = "wasm32" ) ] {
29
30
wasm_bindgen_futures:: spawn_local( create_device_queue_async( ) )
30
31
} else {
31
- futures :: executor :: block_on ( create_device_queue_async( ) )
32
+ create_device_queue_async( ) . await
32
33
}
33
34
}
34
35
}
35
36
36
- pub fn start ( options : & Options ) {
37
- let ( device, queue) = create_device_queue ( ) ;
37
+ pub async fn start ( options : & Options ) -> Vec < u32 > {
38
+ wgpu_subscriber:: initialize_default_subscriber ( None ) ;
39
+ let numbers: Vec < u32 > = vec ! [ 1 , 2 , 3 , 4 ] ;
40
+ let slice_size = numbers. len ( ) * std:: mem:: size_of :: < u32 > ( ) ;
41
+ let size = slice_size as wgpu:: BufferAddress ;
38
42
39
- // Load the shaders from disk
40
- let module = device. create_shader_module ( shader_module ( options. shader ) ) ;
43
+ let ( device, queue) = create_device_queue ( ) . await ;
44
+
45
+ let cs_module = device. create_shader_module ( shader_module ( options. shader ) ) ;
46
+
47
+ let staging_buffer = device. create_buffer ( & wgpu:: BufferDescriptor {
48
+ label : None ,
49
+ size,
50
+ usage : wgpu:: BufferUsage :: MAP_READ | wgpu:: BufferUsage :: COPY_DST ,
51
+ mapped_at_creation : false ,
52
+ } ) ;
53
+
54
+ let storage_buffer = device. create_buffer_init ( & wgpu:: util:: BufferInitDescriptor {
55
+ label : Some ( "Storage Buffer" ) ,
56
+ contents : bytemuck:: cast_slice ( & numbers) ,
57
+ usage : wgpu:: BufferUsage :: STORAGE
58
+ | wgpu:: BufferUsage :: COPY_DST
59
+ | wgpu:: BufferUsage :: COPY_SRC ,
60
+ } ) ;
41
61
42
62
let bind_group_layout = device. create_bind_group_layout ( & wgpu:: BindGroupLayoutDescriptor {
43
63
label : None ,
44
- entries : & [
45
- // XXX - some graphics cards do not support empty bind layout groups, so
46
- // create a dummy entry.
47
- wgpu:: BindGroupLayoutEntry {
48
- binding : 0 ,
49
- count : None ,
50
- visibility : wgpu:: ShaderStage :: COMPUTE ,
51
- ty : wgpu:: BindingType :: StorageBuffer {
52
- dynamic : false ,
53
- min_binding_size : Some ( NonZeroU64 :: new ( 1 ) . unwrap ( ) ) ,
54
- readonly : false ,
55
- } ,
64
+ entries : & [ wgpu:: BindGroupLayoutEntry {
65
+ binding : 0 ,
66
+ visibility : wgpu:: ShaderStage :: COMPUTE ,
67
+ ty : wgpu:: BindingType :: StorageBuffer {
68
+ dynamic : false ,
69
+ readonly : false ,
70
+ min_binding_size : wgpu:: BufferSize :: new ( 4 ) ,
56
71
} ,
57
- ] ,
72
+ count : None ,
73
+ } ] ,
74
+ } ) ;
75
+
76
+ let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
77
+ label : None ,
78
+ layout : & bind_group_layout,
79
+ entries : & [ wgpu:: BindGroupEntry {
80
+ binding : 0 ,
81
+ resource : wgpu:: BindingResource :: Buffer ( storage_buffer. slice ( ..) ) ,
82
+ } ] ,
58
83
} ) ;
59
84
60
85
let pipeline_layout = device. create_pipeline_layout ( & wgpu:: PipelineLayoutDescriptor {
@@ -67,36 +92,49 @@ pub fn start(options: &Options) {
67
92
label : None ,
68
93
layout : Some ( & pipeline_layout) ,
69
94
compute_stage : wgpu:: ProgrammableStageDescriptor {
70
- module : & module ,
95
+ module : & cs_module ,
71
96
entry_point : "main_cs" ,
72
97
} ,
73
98
} ) ;
74
99
75
- let buf = device. create_buffer ( & wgpu:: BufferDescriptor {
76
- label : None ,
77
- size : 1 ,
78
- usage : wgpu:: BufferUsage :: STORAGE ,
79
- mapped_at_creation : false ,
80
- } ) ;
81
-
82
- let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
83
- label : None ,
84
- layout : & bind_group_layout,
85
- entries : & [ wgpu:: BindGroupEntry {
86
- binding : 0 ,
87
- resource : wgpu:: BindingResource :: Buffer ( buf. slice ( ..) ) ,
88
- } ] ,
89
- } ) ;
90
-
91
100
let mut encoder =
92
101
device. create_command_encoder ( & wgpu:: CommandEncoderDescriptor { label : None } ) ;
93
-
94
102
{
95
103
let mut cpass = encoder. begin_compute_pass ( ) ;
96
- cpass. set_bind_group ( 0 , & bind_group, & [ ] ) ;
97
104
cpass. set_pipeline ( & compute_pipeline) ;
98
- cpass. dispatch ( 1 , 1 , 1 ) ;
105
+ cpass. set_bind_group ( 0 , & bind_group, & [ ] ) ;
106
+ cpass. insert_debug_marker ( "compute collatz iterations" ) ;
107
+ cpass. dispatch ( numbers. len ( ) as u32 , 1 , 1 ) ;
99
108
}
100
-
109
+ encoder . copy_buffer_to_buffer ( & storage_buffer , 0 , & staging_buffer , 0 , size ) ;
101
110
queue. submit ( Some ( encoder. finish ( ) ) ) ;
111
+ // Note that we're not calling `.await` here.
112
+
113
+ let buffer_slice = staging_buffer. slice ( ..) ;
114
+ let buffer_future = buffer_slice. map_async ( wgpu:: MapMode :: Read ) ;
115
+
116
+ // Poll the device in a blocking manner so that our future resolves.
117
+ // In an actual application, `device.poll(...)` should
118
+ // be called in an event loop or on another thread.
119
+ device. poll ( wgpu:: Maintain :: Wait ) ;
120
+
121
+ if let Ok ( ( ) ) = buffer_future. await {
122
+ let data = buffer_slice. get_mapped_range ( ) ;
123
+ let result = data
124
+ . chunks_exact ( 4 )
125
+ . map ( |b| u32:: from_ne_bytes ( b. try_into ( ) . unwrap ( ) ) )
126
+ . collect ( ) ;
127
+
128
+ // With the current interface, we have to make sure all mapped views are
129
+ // dropped before we unmap the buffer.
130
+ drop ( data) ;
131
+ staging_buffer. unmap ( ) ;
132
+
133
+ println ! ( "Times: {:?}" , result) ;
134
+ #[ cfg( target_arch = "wasm32" ) ]
135
+ log:: info!( "Times: {:?}" , result) ;
136
+ result
137
+ } else {
138
+ panic ! ( "failed to run compute on gpu!" )
139
+ }
102
140
}
0 commit comments