1- use pollster:: FutureExt ;
1+ use std:: { fs, marker:: PhantomData } ;
2+
3+ use pollster:: FutureExt as _;
24use wgpu:: util:: DeviceExt ;
35
46use crate :: { Pixel , ShaderContext } ;
57
8+ use super :: { NoUserData , TuiShaderBackend } ;
9+
610const DEFAULT_SIZE : u32 = 64 ;
711
812#[ derive( Debug , Clone ) ]
9- pub struct ShaderCanvasState {
13+ pub struct WgpuBackend < T >
14+ where
15+ T : Copy + Clone + Default + bytemuck:: Pod + bytemuck:: Zeroable ,
16+ {
1017 device : wgpu:: Device ,
1118 queue : wgpu:: Queue ,
1219 pipeline : wgpu:: RenderPipeline ,
@@ -16,23 +23,18 @@ pub struct ShaderCanvasState {
1623 bind_group : wgpu:: BindGroup ,
1724 width : u32 ,
1825 height : u32 ,
26+ _user_data : PhantomData < T > ,
1927}
2028
21- impl ShaderCanvasState {
22- pub fn new < ' a , S : Into < wgpu:: ShaderModuleDescriptor < ' a > > > (
23- shader : S ,
24- entry_point : Option < & str > ,
25- ) -> Self {
26- Self :: new_inner ( shader. into ( ) , entry_point) . block_on ( )
27- }
28- }
29-
30- impl ShaderCanvasState {
31- pub fn execute ( & mut self , ctx : ShaderContext ) -> Vec < Pixel > {
32- self . execute_inner ( ctx) . block_on ( )
29+ impl < T > WgpuBackend < T >
30+ where
31+ T : Copy + Clone + Default + bytemuck:: Pod + bytemuck:: Zeroable ,
32+ {
33+ pub fn new ( path_to_fragment_shader : & str , entry_point : & str ) -> Self {
34+ Self :: new_inner ( path_to_fragment_shader, entry_point) . block_on ( )
3335 }
3436
35- async fn create_device_and_queue ( ) -> ( wgpu:: Device , wgpu:: Queue ) {
37+ async fn get_device_and_queue ( ) -> ( wgpu:: Device , wgpu:: Queue ) {
3638 let instance = wgpu:: Instance :: default ( ) ;
3739
3840 let adapter = instance
@@ -85,51 +87,19 @@ impl ShaderCanvasState {
8587 } )
8688 }
8789
88- fn create_pipeline (
89- device : & wgpu:: Device ,
90- pipeline_layout : & wgpu:: PipelineLayout ,
91- vertex_shader : & wgpu:: ShaderModule ,
92- fragment_shader : & wgpu:: ShaderModule ,
93- entry_point : Option < & str > ,
94- ) -> wgpu:: RenderPipeline {
95- let pipeline = device. create_render_pipeline ( & wgpu:: RenderPipelineDescriptor {
96- label : None ,
97- layout : Some ( & pipeline_layout) ,
98- vertex : wgpu:: VertexState {
99- module : vertex_shader,
100- entry_point : None ,
101- buffers : & [ ] ,
102- compilation_options : wgpu:: PipelineCompilationOptions :: default ( ) ,
103- } ,
104- fragment : Some ( wgpu:: FragmentState {
105- module : fragment_shader,
106- entry_point,
107- compilation_options : wgpu:: PipelineCompilationOptions :: default ( ) ,
108- targets : & [ Some ( wgpu:: ColorTargetState {
109- format : wgpu:: TextureFormat :: Rgba8Unorm ,
110- blend : Some ( wgpu:: BlendState :: ALPHA_BLENDING ) ,
111- write_mask : wgpu:: ColorWrites :: ALL ,
112- } ) ] ,
113- } ) ,
114- primitive : wgpu:: PrimitiveState :: default ( ) ,
115- depth_stencil : None ,
116- multisample : wgpu:: MultisampleState :: default ( ) ,
117- multiview : None ,
118- cache : None ,
119- } ) ;
120- pipeline
121- }
122-
123- async fn new_inner < ' a > (
124- desc : wgpu:: ShaderModuleDescriptor < ' a > ,
125- entry_point : Option < & str > ,
126- ) -> Self {
127- let ( device, queue) = Self :: create_device_and_queue ( ) . await ;
90+ async fn new_inner ( path_to_fragment_shader : & str , entry_point : & str ) -> Self {
91+ let ( device, queue) = Self :: get_device_and_queue ( ) . await ;
12892
12993 let vertex_shader =
130- device. create_shader_module ( wgpu:: include_wgsl!( "shaders/fullscreen_vertex.wgsl" ) ) ;
94+ device. create_shader_module ( wgpu:: include_wgsl!( "../shaders/fullscreen_vertex.wgsl" ) ) ;
95+
96+ let fragment_shader_source =
97+ fs:: read_to_string ( path_to_fragment_shader) . expect ( "Unable to read fragment shader" ) ;
13198
132- let fragment_shader = device. create_shader_module ( desc) ;
99+ let fragment_shader = device. create_shader_module ( wgpu:: ShaderModuleDescriptor {
100+ label : None ,
101+ source : wgpu:: ShaderSource :: Wgsl ( fragment_shader_source. into ( ) ) ,
102+ } ) ;
133103
134104 let texture = Self :: create_texture ( & device, DEFAULT_SIZE , DEFAULT_SIZE ) ;
135105 let output_buffer = Self :: create_buffer ( & device, DEFAULT_SIZE , DEFAULT_SIZE ) ;
@@ -142,7 +112,7 @@ impl ShaderCanvasState {
142112
143113 let user_data_buffer = device. create_buffer_init ( & wgpu:: util:: BufferInitDescriptor {
144114 label : None ,
145- contents : bytemuck:: cast_slice ( & [ 0.0 ] ) ,
115+ contents : bytemuck:: cast_slice ( & [ T :: default ( ) ] ) ,
146116 usage : wgpu:: BufferUsages :: UNIFORM | wgpu:: BufferUsages :: COPY_DST ,
147117 } ) ;
148118
@@ -201,15 +171,33 @@ impl ShaderCanvasState {
201171 push_constant_ranges : & [ ] ,
202172 } ) ;
203173
204- let pipeline = Self :: create_pipeline (
205- & device,
206- & pipeline_layout,
207- & vertex_shader,
208- & fragment_shader,
209- entry_point,
210- ) ;
174+ let pipeline = device. create_render_pipeline ( & wgpu:: RenderPipelineDescriptor {
175+ label : None ,
176+ layout : Some ( & pipeline_layout) ,
177+ vertex : wgpu:: VertexState {
178+ module : & vertex_shader,
179+ entry_point : Some ( "main" ) ,
180+ buffers : & [ ] ,
181+ compilation_options : wgpu:: PipelineCompilationOptions :: default ( ) ,
182+ } ,
183+ fragment : Some ( wgpu:: FragmentState {
184+ module : & fragment_shader,
185+ entry_point : Some ( entry_point) ,
186+ compilation_options : wgpu:: PipelineCompilationOptions :: default ( ) ,
187+ targets : & [ Some ( wgpu:: ColorTargetState {
188+ format : wgpu:: TextureFormat :: Rgba8Unorm ,
189+ blend : Some ( wgpu:: BlendState :: ALPHA_BLENDING ) ,
190+ write_mask : wgpu:: ColorWrites :: ALL ,
191+ } ) ] ,
192+ } ) ,
193+ primitive : wgpu:: PrimitiveState :: default ( ) ,
194+ depth_stencil : None ,
195+ multisample : wgpu:: MultisampleState :: default ( ) ,
196+ multiview : None ,
197+ cache : None ,
198+ } ) ;
211199
212- Self {
200+ WgpuBackend {
213201 device,
214202 queue,
215203 pipeline,
@@ -219,11 +207,11 @@ impl ShaderCanvasState {
219207 bind_group,
220208 width : DEFAULT_SIZE . into ( ) ,
221209 height : DEFAULT_SIZE . into ( ) ,
210+ _user_data : PhantomData ,
222211 }
223212 }
224213
225- async fn execute_inner ( & mut self , ctx : ShaderContext ) -> Vec < Pixel > {
226- // TODO: handle user_data;
214+ async fn execute_inner ( & mut self , ctx : ShaderContext , _user_data : & T ) -> Vec < Pixel > {
227215 let width = ctx. resolution [ 0 ] ;
228216 let height = ctx. resolution [ 1 ] ;
229217 if bytes_per_row ( width) != bytes_per_row ( self . width ) || height != self . height {
@@ -313,12 +301,18 @@ impl ShaderCanvasState {
313301 }
314302}
315303
316- impl Default for ShaderCanvasState {
304+ impl < T > TuiShaderBackend < T > for WgpuBackend < T >
305+ where
306+ T : Copy + Clone + Default + bytemuck:: Pod + bytemuck:: Zeroable ,
307+ {
308+ fn execute ( & mut self , ctx : ShaderContext , user_data : & T ) -> Vec < Pixel > {
309+ self . execute_inner ( ctx, user_data) . block_on ( )
310+ }
311+ }
312+
313+ impl Default for WgpuBackend < NoUserData > {
317314 fn default ( ) -> Self {
318- Self :: new (
319- wgpu:: include_wgsl!( "shaders/default_fragment.wgsl" ) ,
320- Some ( "magenta" ) ,
321- )
315+ Self :: new ( "src/shaders/default_fragment.wgsl" , "magenta" )
322316 }
323317}
324318
@@ -332,26 +326,3 @@ fn row_padding(width: u32) -> u32 {
332326 let bytes_per_row = bytes_per_row ( width) ;
333327 ( bytes_per_row - row_size) / 4
334328}
335-
336- pub enum WgslShader < ' a > {
337- Source ( & ' a str ) ,
338- Path ( & ' a str ) ,
339- }
340-
341- impl < ' a > From < WgslShader < ' a > > for wgpu:: ShaderModuleDescriptor < ' a > {
342- fn from ( value : WgslShader < ' a > ) -> Self {
343- match value {
344- WgslShader :: Source ( source) => wgpu:: ShaderModuleDescriptor {
345- label : None ,
346- source : wgpu:: ShaderSource :: Wgsl ( source. into ( ) ) ,
347- } ,
348- WgslShader :: Path ( path) => {
349- let source = std:: fs:: read_to_string ( path) . expect ( "unable to read file" ) ;
350- wgpu:: ShaderModuleDescriptor {
351- label : None ,
352- source : wgpu:: ShaderSource :: Wgsl ( source. into ( ) ) ,
353- }
354- }
355- }
356- }
357- }
0 commit comments