1
1
use super :: { shader_module, Options } ;
2
+ use std:: convert:: TryInto ;
3
+ use wgpu:: util:: DeviceExt ;
2
4
3
5
fn create_device_queue ( ) -> ( wgpu:: Device , wgpu:: Queue ) {
4
6
async fn create_device_queue_async ( ) -> ( wgpu:: Device , wgpu:: Queue ) {
5
7
let instance = wgpu:: Instance :: new ( wgpu:: BackendBit :: PRIMARY ) ;
6
8
let adapter = instance
7
9
. request_adapter ( & wgpu:: RequestAdapterOptions {
8
- power_preference : wgpu:: PowerPreference :: default ( ) ,
10
+ power_preference : wgpu:: PowerPreference :: Default ,
9
11
compatible_surface : None ,
10
12
} )
11
13
. await
@@ -32,15 +34,51 @@ fn create_device_queue() -> (wgpu::Device, wgpu::Queue) {
32
34
}
33
35
}
34
36
35
- pub fn start ( options : & Options ) {
37
+ pub async fn start ( options : & Options ) -> Vec < u32 > {
38
+ let numbers: Vec < u32 > = vec ! [ 1 , 2 , 3 , 4 ] ;
39
+ let slice_size = numbers. len ( ) * std:: mem:: size_of :: < u32 > ( ) ;
40
+ let size = slice_size as wgpu:: BufferAddress ;
41
+
36
42
let ( device, queue) = create_device_queue ( ) ;
37
43
38
- // Load the shaders from disk
39
- let module = device. create_shader_module ( shader_module ( options. shader ) ) ;
44
+ let cs_module = device. create_shader_module ( shader_module ( options. shader ) ) ;
45
+
46
+ let staging_buffer = device. create_buffer ( & wgpu:: BufferDescriptor {
47
+ label : None ,
48
+ size,
49
+ usage : wgpu:: BufferUsage :: MAP_READ | wgpu:: BufferUsage :: COPY_DST ,
50
+ mapped_at_creation : false ,
51
+ } ) ;
52
+
53
+ let storage_buffer = device. create_buffer_init ( & wgpu:: util:: BufferInitDescriptor {
54
+ label : Some ( "Storage Buffer" ) ,
55
+ contents : bytemuck:: cast_slice ( & numbers) ,
56
+ usage : wgpu:: BufferUsage :: STORAGE
57
+ | wgpu:: BufferUsage :: COPY_DST
58
+ | wgpu:: BufferUsage :: COPY_SRC ,
59
+ } ) ;
40
60
41
61
let bind_group_layout = device. create_bind_group_layout ( & wgpu:: BindGroupLayoutDescriptor {
42
62
label : None ,
43
- entries : & [ ] ,
63
+ entries : & [ wgpu:: BindGroupLayoutEntry {
64
+ binding : 0 ,
65
+ visibility : wgpu:: ShaderStage :: COMPUTE ,
66
+ ty : wgpu:: BindingType :: StorageBuffer {
67
+ dynamic : false ,
68
+ readonly : false ,
69
+ min_binding_size : wgpu:: BufferSize :: new ( 4 ) ,
70
+ } ,
71
+ count : None ,
72
+ } ] ,
73
+ } ) ;
74
+
75
+ let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
76
+ label : None ,
77
+ layout : & bind_group_layout,
78
+ entries : & [ wgpu:: BindGroupEntry {
79
+ binding : 0 ,
80
+ resource : wgpu:: BindingResource :: Buffer ( storage_buffer. slice ( ..) ) ,
81
+ } ] ,
44
82
} ) ;
45
83
46
84
let pipeline_layout = device. create_pipeline_layout ( & wgpu:: PipelineLayoutDescriptor {
@@ -53,26 +91,47 @@ pub fn start(options: &Options) {
53
91
label : None ,
54
92
layout : Some ( & pipeline_layout) ,
55
93
compute_stage : wgpu:: ProgrammableStageDescriptor {
56
- module : & module ,
94
+ module : & cs_module ,
57
95
entry_point : "main_cs" ,
58
96
} ,
59
97
} ) ;
60
98
61
- let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
62
- label : None ,
63
- layout : & bind_group_layout,
64
- entries : & [ ] ,
65
- } ) ;
66
-
67
99
let mut encoder =
68
100
device. create_command_encoder ( & wgpu:: CommandEncoderDescriptor { label : None } ) ;
69
-
70
101
{
71
102
let mut cpass = encoder. begin_compute_pass ( ) ;
72
- cpass. set_bind_group ( 0 , & bind_group, & [ ] ) ;
73
103
cpass. set_pipeline ( & compute_pipeline) ;
74
- cpass. dispatch ( 1 , 1 , 1 ) ;
104
+ cpass. set_bind_group ( 0 , & bind_group, & [ ] ) ;
105
+ cpass. insert_debug_marker ( "compute collatz iterations" ) ;
106
+ cpass. dispatch ( numbers. len ( ) as u32 , 1 , 1 ) ;
75
107
}
108
+ encoder. copy_buffer_to_buffer ( & storage_buffer, 0 , & staging_buffer, 0 , size) ;
76
109
77
110
queue. submit ( Some ( encoder. finish ( ) ) ) ;
111
+
112
+ // Note that we're not calling `.await` here.
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
+ result
134
+ } else {
135
+ panic ! ( "failed to run compute on gpu!" )
136
+ }
78
137
}
0 commit comments