@@ -6,49 +6,49 @@ use wgpu::util::DeviceExt;
66use super :: { NoUserData , TuiShaderBackend } ;
77
88#[ repr( C ) ]
9- #[ derive( Copy , Clone , bytemuck:: Pod , bytemuck:: Zeroable ) ]
9+ #[ derive( Copy , Clone , PartialEq , bytemuck:: Pod , bytemuck:: Zeroable ) ]
1010struct ShaderInput {
1111 // struct field order matters
1212 time : f32 ,
1313 padding : f32 ,
1414 resolution : [ f32 ; 2 ] ,
1515}
1616
17- #[ derive( Debug , Clone , Eq , PartialEq ) ]
17+ #[ derive( Debug , Clone ) ]
1818pub struct WgpuBackend < T >
1919where
20- T : Copy + Clone + bytemuck:: Pod + bytemuck:: Zeroable ,
20+ T : Copy + Clone + Default + bytemuck:: Pod + bytemuck:: Zeroable ,
2121{
2222 device : wgpu:: Device ,
2323 queue : wgpu:: Queue ,
2424 pipeline : wgpu:: RenderPipeline ,
25- creation_time : Instant ,
2625 texture : wgpu:: Texture ,
2726 output_buffer : wgpu:: Buffer ,
2827 shader_input_buffer : wgpu:: Buffer ,
2928 bind_group : wgpu:: BindGroup ,
29+ creation_time : Instant ,
3030 width : u16 ,
3131 height : u16 ,
3232 _user_data : PhantomData < T > ,
3333}
3434
3535impl < T > WgpuBackend < T >
3636where
37- T : Copy + Clone + bytemuck:: Pod + bytemuck:: Zeroable ,
37+ T : Copy + Clone + Default + bytemuck:: Pod + bytemuck:: Zeroable ,
3838{
3939 pub fn new ( path_to_fragment_shader : & str , entry_point : & str ) -> Self {
4040 Self :: new_inner ( path_to_fragment_shader, entry_point) . block_on ( )
4141 }
4242
43- async fn new_inner ( path_to_fragment_shader : & str , entry_point : & str ) -> Self {
43+ async fn get_device_and_queue ( ) -> ( wgpu :: Device , wgpu :: Queue ) {
4444 let instance = wgpu:: Instance :: default ( ) ;
4545
4646 let adapter = instance
4747 . request_adapter ( & wgpu:: RequestAdapterOptions :: default ( ) )
4848 . await
4949 . expect ( "unable to create adapter from wgpu instance" ) ;
5050
51- let ( device , queue ) = adapter
51+ let device_and_queue = adapter
5252 . request_device (
5353 & wgpu:: DeviceDescriptor {
5454 label : None ,
6060 )
6161 . await
6262 . expect ( "unable to create device and queue from wgpu adapter" ) ;
63+ device_and_queue
64+ }
65+
66+ fn create_texture ( device : & wgpu:: Device , width : u32 , height : u32 ) -> wgpu:: Texture {
67+ let texture_desc = wgpu:: TextureDescriptor {
68+ size : wgpu:: Extent3d {
69+ width,
70+ height,
71+ depth_or_array_layers : 1 ,
72+ } ,
73+ mip_level_count : 1 ,
74+ sample_count : 1 ,
75+ dimension : wgpu:: TextureDimension :: D2 ,
76+ format : wgpu:: TextureFormat :: Rgba8Unorm ,
77+ usage : wgpu:: TextureUsages :: RENDER_ATTACHMENT | wgpu:: TextureUsages :: COPY_SRC ,
78+ label : None ,
79+ view_formats : & [ wgpu:: TextureFormat :: Rgba8Unorm ] ,
80+ } ;
81+ device. create_texture ( & texture_desc)
82+ }
83+
84+ fn create_buffer ( device : & wgpu:: Device , width : u32 , height : u32 ) -> wgpu:: Buffer {
85+ let row_size = width * 4 ;
86+ let bytes_per_row = ( row_size + 255 ) & !255 ;
87+
88+ device. create_buffer ( & wgpu:: BufferDescriptor {
89+ label : None ,
90+ size : ( bytes_per_row * height) as wgpu:: BufferAddress ,
91+ usage : wgpu:: BufferUsages :: COPY_DST | wgpu:: BufferUsages :: MAP_READ ,
92+ mapped_at_creation : false ,
93+ } )
94+ }
95+
96+ async fn new_inner ( path_to_fragment_shader : & str , entry_point : & str ) -> Self {
97+ let ( device, queue) = Self :: get_device_and_queue ( ) . await ;
6398
6499 let vertex_shader =
65100 device. create_shader_module ( wgpu:: include_wgsl!( "../shaders/fullscreen_vertex.wgsl" ) ) ;
@@ -73,12 +108,11 @@ where
73108 } ) ;
74109
75110 let creation_time = Instant :: now ( ) ;
76-
77111 let width = 64u16 ;
78112 let height = 64u16 ;
79113
80- let texture = WgpuBackend :: < T > :: create_texture ( & device, width. into ( ) , height. into ( ) ) ;
81- let output_buffer = WgpuBackend :: < T > :: create_buffer ( & device, width. into ( ) , height. into ( ) ) ;
114+ let texture = Self :: create_texture ( & device, width. into ( ) , height. into ( ) ) ;
115+ let output_buffer = Self :: create_buffer ( & device, width. into ( ) , height. into ( ) ) ;
82116
83117 let shader_input = ShaderInput {
84118 time : creation_time. elapsed ( ) . as_secs_f32 ( ) ,
@@ -92,30 +126,58 @@ where
92126 usage : wgpu:: BufferUsages :: UNIFORM | wgpu:: BufferUsages :: COPY_DST ,
93127 } ) ;
94128
129+ let user_data_buffer = device. create_buffer_init ( & wgpu:: util:: BufferInitDescriptor {
130+ label : None ,
131+ contents : bytemuck:: cast_slice ( & [ T :: default ( ) ] ) ,
132+ usage : wgpu:: BufferUsages :: UNIFORM | wgpu:: BufferUsages :: COPY_DST ,
133+ } ) ;
134+
95135 let bind_group_layout = device. create_bind_group_layout ( & wgpu:: BindGroupLayoutDescriptor {
96- entries : & [ wgpu:: BindGroupLayoutEntry {
97- binding : 0 ,
98- visibility : wgpu:: ShaderStages :: FRAGMENT ,
99- ty : wgpu:: BindingType :: Buffer {
100- ty : wgpu:: BufferBindingType :: Uniform ,
101- has_dynamic_offset : false ,
102- min_binding_size : None ,
136+ entries : & [
137+ wgpu:: BindGroupLayoutEntry {
138+ binding : 0 ,
139+ visibility : wgpu:: ShaderStages :: FRAGMENT ,
140+ ty : wgpu:: BindingType :: Buffer {
141+ ty : wgpu:: BufferBindingType :: Uniform ,
142+ has_dynamic_offset : false ,
143+ min_binding_size : None ,
144+ } ,
145+ count : None ,
103146 } ,
104- count : None ,
105- } ] ,
147+ wgpu:: BindGroupLayoutEntry {
148+ binding : 1 ,
149+ visibility : wgpu:: ShaderStages :: FRAGMENT ,
150+ ty : wgpu:: BindingType :: Buffer {
151+ ty : wgpu:: BufferBindingType :: Uniform ,
152+ has_dynamic_offset : false ,
153+ min_binding_size : None ,
154+ } ,
155+ count : None ,
156+ } ,
157+ ] ,
106158 label : None ,
107159 } ) ;
108160
109161 let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
110162 layout : & bind_group_layout,
111- entries : & [ wgpu:: BindGroupEntry {
112- binding : 0 ,
113- resource : wgpu:: BindingResource :: Buffer ( wgpu:: BufferBinding {
114- buffer : & shader_input_buffer,
115- offset : 0 ,
116- size : None ,
117- } ) ,
118- } ] ,
163+ entries : & [
164+ wgpu:: BindGroupEntry {
165+ binding : 0 ,
166+ resource : wgpu:: BindingResource :: Buffer ( wgpu:: BufferBinding {
167+ buffer : & shader_input_buffer,
168+ offset : 0 ,
169+ size : None ,
170+ } ) ,
171+ } ,
172+ wgpu:: BindGroupEntry {
173+ binding : 1 ,
174+ resource : wgpu:: BindingResource :: Buffer ( wgpu:: BufferBinding {
175+ buffer : & user_data_buffer,
176+ offset : 0 ,
177+ size : None ,
178+ } ) ,
179+ } ,
180+ ] ,
119181 label : None ,
120182 } ) ;
121183
@@ -166,53 +228,12 @@ where
166228 }
167229 }
168230
169- fn create_texture ( device : & wgpu:: Device , width : u32 , height : u32 ) -> wgpu:: Texture {
170- let texture_desc = wgpu:: TextureDescriptor {
171- size : wgpu:: Extent3d {
172- width,
173- height,
174- depth_or_array_layers : 1 ,
175- } ,
176- mip_level_count : 1 ,
177- sample_count : 1 ,
178- dimension : wgpu:: TextureDimension :: D2 ,
179- format : wgpu:: TextureFormat :: Rgba8Unorm ,
180- usage : wgpu:: TextureUsages :: RENDER_ATTACHMENT | wgpu:: TextureUsages :: COPY_SRC ,
181- label : None ,
182- view_formats : & [ wgpu:: TextureFormat :: Rgba8Unorm ] ,
183- } ;
184- device. create_texture ( & texture_desc)
185- }
186-
187- fn create_buffer ( device : & wgpu:: Device , width : u32 , height : u32 ) -> wgpu:: Buffer {
188- let row_size = width * 4 ;
189- let bytes_per_row = ( row_size + 255 ) & !255 ;
190-
191- device. create_buffer ( & wgpu:: BufferDescriptor {
192- label : None ,
193- size : ( bytes_per_row * height) as wgpu:: BufferAddress ,
194- usage : wgpu:: BufferUsages :: COPY_DST | wgpu:: BufferUsages :: MAP_READ ,
195- mapped_at_creation : false ,
196- } )
197- }
198-
199- fn bytes_per_row ( & self , width : u16 ) -> u16 {
200- let row_size = width * 4 ;
201- ( row_size + 255 ) & !255
202- }
203-
204- fn row_padding ( & self , width : u16 ) -> u16 {
205- let row_size = width * 4 ;
206- let bytes_per_row = self . bytes_per_row ( width) ;
207- ( bytes_per_row - row_size) / 4
208- }
209-
210231 async fn execute_inner ( & mut self , width : u16 , height : u16 , _user_data : & T ) -> Vec < [ u8 ; 4 ] > {
211- if self . bytes_per_row ( width) != self . bytes_per_row ( self . width ) || height != self . height {
232+ if bytes_per_row ( width) != bytes_per_row ( self . width ) || height != self . height {
212233 self . texture = Self :: create_texture ( & self . device , width. into ( ) , height. into ( ) ) ;
213234 self . output_buffer = Self :: create_buffer ( & self . device , width. into ( ) , height. into ( ) ) ;
214235 }
215- let bytes_per_row = self . bytes_per_row ( width) ;
236+ let bytes_per_row = bytes_per_row ( width) ;
216237
217238 let texture_view = self
218239 . texture
@@ -230,7 +251,6 @@ where
230251 let mut command_encoder = self
231252 . device
232253 . create_command_encoder ( & wgpu:: CommandEncoderDescriptor { label : None } ) ;
233-
234254 {
235255 let mut render_pass = command_encoder. begin_render_pass ( & wgpu:: RenderPassDescriptor {
236256 label : None ,
@@ -299,7 +319,7 @@ where
299319 let mut buffer: Vec < [ u8 ; 4 ] > = Vec :: new ( ) ;
300320 for y in 0 ..height {
301321 for x in 0 ..width {
302- let index = ( y * ( width + self . row_padding ( width) ) + x) as usize ;
322+ let index = ( y * ( width + row_padding ( width) ) + x) as usize ;
303323 let pixel = padded_buffer[ index] ;
304324 buffer. push ( pixel) ;
305325 }
@@ -310,7 +330,7 @@ where
310330
311331impl < T > TuiShaderBackend < T > for WgpuBackend < T >
312332where
313- T : Copy + Clone + bytemuck:: Pod + bytemuck:: Zeroable ,
333+ T : Copy + Clone + Default + bytemuck:: Pod + bytemuck:: Zeroable ,
314334{
315335 fn execute ( & mut self , width : u16 , height : u16 , user_data : & T ) -> Vec < [ u8 ; 4 ] > {
316336 self . execute_inner ( width, height, user_data) . block_on ( )
@@ -322,3 +342,14 @@ impl Default for WgpuBackend<NoUserData> {
322342 Self :: new ( "src/shaders/default_fragment.wgsl" , "magenta" )
323343 }
324344}
345+
346+ fn bytes_per_row ( width : u16 ) -> u16 {
347+ let row_size = width * 4 ;
348+ ( row_size + 255 ) & !255
349+ }
350+
351+ fn row_padding ( width : u16 ) -> u16 {
352+ let row_size = width * 4 ;
353+ let bytes_per_row = bytes_per_row ( width) ;
354+ ( bytes_per_row - row_size) / 4
355+ }
0 commit comments