@@ -2,6 +2,7 @@ use crate::{CompiledShaderModules, Options, maybe_watch};
22use wgpu:: ShaderModuleDescriptorPassthrough ;
33
44use shared:: ShaderConstants ;
5+ use std:: slice;
56use winit:: {
67 event:: { ElementState , Event , MouseButton , WindowEvent } ,
78 event_loop:: { ControlFlow , EventLoop } ,
@@ -174,15 +175,59 @@ async fn run(
174175 let mut surface_with_config = initial_surface
175176 . map ( |surface| auto_configure_surface ( & adapter, & device, surface, window. inner_size ( ) ) ) ;
176177
177- // Load the shaders from disk
178+ // Describe the pipeline layout and build the initial pipeline.
179+ let push_constants_or_rossbo_emulation = {
180+ const PUSH_CONSTANTS_SIZE : usize = std:: mem:: size_of :: < ShaderConstants > ( ) ;
181+ let stages = wgpu:: ShaderStages :: VERTEX | wgpu:: ShaderStages :: FRAGMENT ;
178182
183+ if !options. emulate_push_constants_with_storage_buffer {
184+ Ok ( wgpu:: PushConstantRange {
185+ stages,
186+ range : 0 ..PUSH_CONSTANTS_SIZE as u32 ,
187+ } )
188+ } else {
189+ let buffer = device. create_buffer ( & wgpu:: BufferDescriptor {
190+ label : None ,
191+ size : PUSH_CONSTANTS_SIZE as u64 ,
192+ usage : wgpu:: BufferUsages :: STORAGE | wgpu:: BufferUsages :: COPY_DST ,
193+ mapped_at_creation : false ,
194+ } ) ;
195+ let binding0 = wgpu:: BindGroupLayoutEntry {
196+ binding : 0 ,
197+ visibility : stages,
198+ ty : wgpu:: BindingType :: Buffer {
199+ ty : wgpu:: BufferBindingType :: Storage { read_only : true } ,
200+ has_dynamic_offset : false ,
201+ min_binding_size : Some ( ( PUSH_CONSTANTS_SIZE as u64 ) . try_into ( ) . unwrap ( ) ) ,
202+ } ,
203+ count : None ,
204+ } ;
205+ let bind_group_layout =
206+ device. create_bind_group_layout ( & wgpu:: BindGroupLayoutDescriptor {
207+ label : None ,
208+ entries : & [ binding0] ,
209+ } ) ;
210+ let bind_group = device. create_bind_group ( & wgpu:: BindGroupDescriptor {
211+ label : None ,
212+ layout : & bind_group_layout,
213+ entries : & [ wgpu:: BindGroupEntry {
214+ binding : 0 ,
215+ resource : buffer. as_entire_binding ( ) ,
216+ } ] ,
217+ } ) ;
218+ Err ( ( buffer, bind_group_layout, bind_group) )
219+ }
220+ } ;
179221 let pipeline_layout = device. create_pipeline_layout ( & wgpu:: PipelineLayoutDescriptor {
180222 label : None ,
181- bind_group_layouts : & [ ] ,
182- push_constant_ranges : & [ wgpu:: PushConstantRange {
183- stages : wgpu:: ShaderStages :: VERTEX | wgpu:: ShaderStages :: FRAGMENT ,
184- range : 0 ..std:: mem:: size_of :: < ShaderConstants > ( ) as u32 ,
185- } ] ,
223+ bind_group_layouts : push_constants_or_rossbo_emulation
224+ . as_ref ( )
225+ . err ( )
226+ . map ( |( _, layout, _) | layout)
227+ . as_slice ( ) ,
228+ push_constant_ranges : push_constants_or_rossbo_emulation
229+ . as_ref ( )
230+ . map_or ( & [ ] , slice:: from_ref) ,
186231 } ) ;
187232
188233 let mut render_pipeline = create_pipeline (
@@ -339,11 +384,23 @@ async fn run(
339384 } ;
340385
341386 rpass. set_pipeline ( render_pipeline) ;
342- rpass. set_push_constants (
343- wgpu:: ShaderStages :: VERTEX | wgpu:: ShaderStages :: FRAGMENT ,
344- 0 ,
345- bytemuck:: bytes_of ( & push_constants) ,
346- ) ;
387+ let ( push_constant_offset, push_constant_bytes) =
388+ ( 0 , bytemuck:: bytes_of ( & push_constants) ) ;
389+ match & push_constants_or_rossbo_emulation {
390+ Ok ( _) => rpass. set_push_constants (
391+ wgpu:: ShaderStages :: VERTEX | wgpu:: ShaderStages :: FRAGMENT ,
392+ push_constant_offset as u32 ,
393+ push_constant_bytes,
394+ ) ,
395+ Err ( ( buffer, _, bind_group) ) => {
396+ queue. write_buffer (
397+ buffer,
398+ push_constant_offset,
399+ push_constant_bytes,
400+ ) ;
401+ rpass. set_bind_group ( 0 , bind_group, & [ ] ) ;
402+ }
403+ }
347404 rpass. draw ( 0 ..3 , 0 ..1 ) ;
348405 }
349406
@@ -421,8 +478,39 @@ fn create_pipeline(
421478 device : & wgpu:: Device ,
422479 pipeline_layout : & wgpu:: PipelineLayout ,
423480 surface_format : wgpu:: TextureFormat ,
424- compiled_shader_modules : CompiledShaderModules ,
481+ mut compiled_shader_modules : CompiledShaderModules ,
425482) -> wgpu:: RenderPipeline {
483+ if options. emulate_push_constants_with_storage_buffer {
484+ let ( ds, b) = ( 0 , 0 ) ;
485+
486+ for ( _, shader_module_descr) in & mut compiled_shader_modules. named_spv_modules {
487+ let w = shader_module_descr. source . to_mut ( ) ;
488+ assert_eq ! ( ( w[ 0 ] , w[ 4 ] ) , ( 0x07230203 , 0 ) ) ;
489+ let mut last_op_decorate_start = None ;
490+ let mut i = 5 ;
491+ while i < w. len ( ) {
492+ let ( op, len) = ( w[ i] & 0xffff , w[ i] >> 16 ) ;
493+ match op {
494+ 71 => last_op_decorate_start = Some ( i) ,
495+ 32 if w[ i + 2 ] == 9 => w[ i + 2 ] = 12 ,
496+ 59 if w[ i + 3 ] == 9 => {
497+ w[ i + 3 ] = 12 ;
498+ let id = w[ i + 2 ] ;
499+ let j = last_op_decorate_start. expect ( "no OpDecorate?" ) ;
500+ w. splice (
501+ j..j,
502+ [ 0x4_0047 , id, 34 , ds, 0x4_0047 , id, 33 , b, 0x3_0047 , id, 24 ] ,
503+ ) ;
504+ i += 11 ;
505+ }
506+ 54 => break ,
507+ _ => { }
508+ }
509+ i += len as usize ;
510+ }
511+ }
512+ }
513+
426514 // FIXME(eddyb) automate this decision by default.
427515 let create_module = |module| {
428516 if options. force_spirv_passthru {
0 commit comments