@@ -2,6 +2,7 @@ use crate::{CompiledShaderModules, Options, maybe_watch};
2
2
use wgpu:: ShaderModuleDescriptorPassthrough ;
3
3
4
4
use shared:: ShaderConstants ;
5
+ use std:: slice;
5
6
use winit:: {
6
7
event:: { ElementState , Event , MouseButton , WindowEvent } ,
7
8
event_loop:: { ControlFlow , EventLoop } ,
@@ -174,15 +175,59 @@ async fn run(
174
175
let mut surface_with_config = initial_surface
175
176
. map ( |surface| auto_configure_surface ( & adapter, & device, surface, window. inner_size ( ) ) ) ;
176
177
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 ;
178
182
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
+ } ;
179
221
let pipeline_layout = device. create_pipeline_layout ( & wgpu:: PipelineLayoutDescriptor {
180
222
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) ,
186
231
} ) ;
187
232
188
233
let mut render_pipeline = create_pipeline (
@@ -339,11 +384,23 @@ async fn run(
339
384
} ;
340
385
341
386
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
+ }
347
404
rpass. draw ( 0 ..3 , 0 ..1 ) ;
348
405
}
349
406
@@ -421,8 +478,39 @@ fn create_pipeline(
421
478
device : & wgpu:: Device ,
422
479
pipeline_layout : & wgpu:: PipelineLayout ,
423
480
surface_format : wgpu:: TextureFormat ,
424
- compiled_shader_modules : CompiledShaderModules ,
481
+ mut compiled_shader_modules : CompiledShaderModules ,
425
482
) -> 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
+
426
514
// FIXME(eddyb) automate this decision by default.
427
515
let create_module = |module| {
428
516
if options. force_spirv_passthru {
0 commit comments