@@ -33,7 +33,8 @@ impl PerPixelAdjustShaderRuntime {
3333}
3434
3535impl ShaderRuntime {
36- pub async fn run_per_pixel_adjust < T : BufferStruct > ( & self , shaders : & Shaders < ' _ > , textures : List < Raster < GPU > > , args : Option < & T > ) -> List < Raster < GPU > > {
36+ pub async fn run_per_pixel_adjust < T : BufferStruct > ( & self , shaders : & Shaders < ' _ > , textures : & [ List < Raster < GPU > > ] , args : Option < & T > ) -> List < Raster < GPU > > {
37+ assert_eq ! ( shaders. input_images, textures. len( ) ) ;
3738 let mut cache = self . per_pixel_adjust . pipeline_cache . lock ( ) . await ;
3839 let pipeline = cache
3940 . entry ( shaders. fragment_shader_name . to_owned ( ) )
@@ -54,11 +55,13 @@ impl ShaderRuntime {
5455pub struct Shaders < ' a > {
5556 pub wgsl_shader : & ' a str ,
5657 pub fragment_shader_name : & ' a str ,
58+ pub input_images : usize ,
5759 pub has_uniform : bool ,
5860}
5961
6062pub struct PerPixelAdjustGraphicsPipeline {
6163 name : String ,
64+ input_images : usize ,
6265 has_uniform : bool ,
6366 pipeline : wgpu:: RenderPipeline ,
6467}
@@ -76,46 +79,37 @@ impl PerPixelAdjustGraphicsPipeline {
7679 source : ShaderSource :: Wgsl ( Cow :: Borrowed ( info. wgsl_shader ) ) ,
7780 } ) ;
7881
79- let entries: & [ _ ] = if info. has_uniform {
80- & [
81- BindGroupLayoutEntry {
82- binding : 0 ,
83- visibility : ShaderStages :: FRAGMENT ,
84- ty : BindingType :: Buffer {
85- ty : BufferBindingType :: Storage { read_only : true } ,
86- has_dynamic_offset : false ,
87- min_binding_size : None ,
88- } ,
89- count : None ,
90- } ,
91- BindGroupLayoutEntry {
92- binding : 1 ,
93- visibility : ShaderStages :: FRAGMENT ,
94- ty : BindingType :: Texture {
95- sample_type : TextureSampleType :: Float { filterable : false } ,
96- view_dimension : TextureViewDimension :: D2 ,
97- multisampled : false ,
98- } ,
99- count : None ,
82+ let mut binding_alloc = Counter :: default ( ) ;
83+ let mut entries = Vec :: new ( ) ;
84+ if info. has_uniform {
85+ entries. push ( BindGroupLayoutEntry {
86+ binding : binding_alloc. alloc ( ) ,
87+ visibility : ShaderStages :: FRAGMENT ,
88+ ty : BindingType :: Buffer {
89+ ty : BufferBindingType :: Storage { read_only : true } ,
90+ has_dynamic_offset : false ,
91+ min_binding_size : None ,
10092 } ,
101- ]
102- } else {
103- & [ BindGroupLayoutEntry {
104- binding : 0 ,
93+ count : None ,
94+ } ) ;
95+ }
96+ for _ in 0 ..info. input_images {
97+ entries. push ( BindGroupLayoutEntry {
98+ binding : binding_alloc. alloc ( ) ,
10599 visibility : ShaderStages :: FRAGMENT ,
106100 ty : BindingType :: Texture {
107101 sample_type : TextureSampleType :: Float { filterable : false } ,
108102 view_dimension : TextureViewDimension :: D2 ,
109103 multisampled : false ,
110104 } ,
111105 count : None ,
112- } ]
113- } ;
106+ } ) ;
107+ }
114108 let pipeline_layout = device. create_pipeline_layout ( & PipelineLayoutDescriptor {
115109 label : Some ( & format ! ( "PerPixelAdjust {name} PipelineLayout" ) ) ,
116110 bind_group_layouts : & [ Some ( & device. create_bind_group_layout ( & BindGroupLayoutDescriptor {
117111 label : Some ( & format ! ( "PerPixelAdjust {name} BindGroupLayout 0" ) ) ,
118- entries,
112+ entries : & entries ,
119113 } ) ) ] ,
120114 ..Default :: default ( )
121115 } ) ;
@@ -157,61 +151,73 @@ impl PerPixelAdjustGraphicsPipeline {
157151 pipeline,
158152 name,
159153 has_uniform : info. has_uniform ,
154+ input_images : info. input_images ,
160155 }
161156 }
162157
163- pub fn dispatch ( & self , context : & WgpuContext , textures : List < Raster < GPU > > , arg_buffer : Option < Buffer > ) -> List < Raster < GPU > > {
158+ pub fn dispatch ( & self , context : & WgpuContext , in_textures : & [ List < Raster < GPU > > ] , arg_buffer : Option < Buffer > ) -> List < Raster < GPU > > {
164159 assert_eq ! ( self . has_uniform, arg_buffer. is_some( ) ) ;
160+ assert_eq ! ( self . input_images, in_textures. len( ) ) ;
165161 let device = & context. device ;
166162 let name = self . name . as_str ( ) ;
167163
164+ // Assumption: when we have multiple input images to our node, each input's List of images can have a different
165+ // length. Only process the minimum between all input images, same as `impl Blend<Color> for List<Raster<CPU>>`.
166+ let dispatch_cnt = match in_textures. iter ( ) . map ( |t| t. len ( ) ) . min ( ) {
167+ None => {
168+ return List :: new ( ) ;
169+ }
170+ Some ( e) => e,
171+ } ;
172+
168173 let mut cmd = device. create_command_encoder ( & wgpu:: CommandEncoderDescriptor {
169174 label : Some ( & format ! ( "{name} cmd encoder" ) ) ,
170175 } ) ;
171- let out = ( 0 ..textures. len ( ) )
172- . map ( |index| {
173- let element = textures. element ( index) . unwrap ( ) ;
174- let tex_in = & element. texture ;
175- let view_in = tex_in. create_view ( & TextureViewDescriptor :: default ( ) ) ;
176- let format = tex_in. format ( ) ;
177-
178- let entries: & [ _ ] = if let Some ( arg_buffer) = arg_buffer. as_ref ( ) {
179- & [
180- BindGroupEntry {
181- binding : 0 ,
182- resource : BindingResource :: Buffer ( BufferBinding {
183- buffer : arg_buffer,
184- offset : 0 ,
185- size : None ,
186- } ) ,
187- } ,
188- BindGroupEntry {
189- binding : 1 ,
190- resource : BindingResource :: TextureView ( & view_in) ,
191- } ,
192- ]
193- } else {
194- & [ BindGroupEntry {
195- binding : 0 ,
176+ let out = ( 0 ..dispatch_cnt)
177+ . map ( |dispatch_id| {
178+ let mut binding_alloc = Counter :: default ( ) ;
179+ let mut entries = Vec :: new ( ) ;
180+ if let Some ( arg_buffer) = arg_buffer. as_ref ( ) {
181+ entries. push ( BindGroupEntry {
182+ binding : binding_alloc. alloc ( ) ,
183+ resource : BindingResource :: Buffer ( BufferBinding {
184+ buffer : arg_buffer,
185+ offset : 0 ,
186+ size : None ,
187+ } ) ,
188+ } ) ;
189+ }
190+ let in_texture_views = in_textures. iter ( ) . map ( |texture| {
191+ let element = texture. element ( dispatch_id) . unwrap ( ) ;
192+ element. texture . create_view ( & TextureViewDescriptor :: default ( ) )
193+ } ) . collect :: < Vec < _ > > ( ) ;
194+ for view_in in & in_texture_views {
195+ entries. push ( BindGroupEntry {
196+ binding : binding_alloc. alloc ( ) ,
196197 resource : BindingResource :: TextureView ( & view_in) ,
197- } ]
198- } ;
198+ } ) ;
199+ }
200+
199201 let bind_group = device. create_bind_group ( & BindGroupDescriptor {
200202 label : Some ( & format ! ( "{name} bind group" ) ) ,
201203 // `get_bind_group_layout` allocates unnecessary memory, we could create it manually to not do that
202204 layout : & self . pipeline . get_bind_group_layout ( 0 ) ,
203- entries,
205+ entries : & entries ,
204206 } ) ;
205207
208+ // Assumption: The output texture has the same size and format as the first input texture. Like the
209+ // blend node, that writes the output directly back into the first texture.
210+ let outref_list = & in_textures[ 0 ] ;
211+ let outref_tex = & outref_list. element ( dispatch_id) . unwrap ( ) . texture ;
206212 let tex_out = device. create_texture ( & TextureDescriptor {
207213 label : Some ( & format ! ( "{name} texture out" ) ) ,
208- size : tex_in . size ( ) ,
214+ size : outref_tex . size ( ) ,
209215 mip_level_count : 1 ,
210216 sample_count : 1 ,
211217 dimension : TextureDimension :: D2 ,
212- format,
218+ format : outref_tex . format ( ) ,
213219 usage : wgpu:: TextureUsages :: TEXTURE_BINDING | wgpu:: TextureUsages :: COPY_DST | wgpu:: TextureUsages :: COPY_SRC | wgpu:: TextureUsages :: RENDER_ATTACHMENT ,
214- view_formats : & [ format] ,
220+ view_formats : & [ outref_tex . format ( ) ] ,
215221 } ) ;
216222
217223 let view_out = tex_out. create_view ( & TextureViewDescriptor :: default ( ) ) ;
@@ -233,11 +239,22 @@ impl PerPixelAdjustGraphicsPipeline {
233239 rp. set_bind_group ( 0 , Some ( & bind_group) , & [ ] ) ;
234240 rp. draw ( 0 ..3 , 0 ..1 ) ;
235241
236- let attributes = textures . clone_item_attributes ( index ) ;
242+ let attributes = outref_list . clone_item_attributes ( dispatch_id ) ;
237243 Item :: from_parts ( Raster :: new ( GPU { texture : tex_out } ) , attributes)
238244 } )
239245 . collect :: < List < _ > > ( ) ;
240246 context. queue . submit ( [ cmd. finish ( ) ] ) ;
241247 out
242248 }
243249}
250+
251+ #[ derive( Clone , Debug , Default ) ]
252+ pub struct Counter ( pub u32 ) ;
253+
254+ impl Counter {
255+ pub fn alloc ( & mut self ) -> u32 {
256+ let out = self . 0 ;
257+ self . 0 += 1 ;
258+ out
259+ }
260+ }
0 commit comments