@@ -26,7 +26,7 @@ use crate::{
26
26
} ,
27
27
dx12:: {
28
28
borrow_optional_interface_temporarily, shader_compilation, suballocation,
29
- DynamicStorageBufferOffsets , Event ,
29
+ DynamicStorageBufferOffsets , Event , ShaderCacheKey , ShaderCacheValue ,
30
30
} ,
31
31
AccelerationStructureEntries , TlasInstance ,
32
32
} ;
@@ -203,6 +203,7 @@ impl super::Device {
203
203
null_rtv_handle,
204
204
mem_allocator,
205
205
dxc_container,
206
+ shader_cache : Default :: default ( ) ,
206
207
counters : Default :: default ( ) ,
207
208
} )
208
209
}
@@ -304,63 +305,98 @@ impl super::Device {
304
305
} ;
305
306
306
307
//TODO: reuse the writer
307
- let mut source = String :: new ( ) ;
308
- let mut writer = hlsl:: Writer :: new ( & mut source, naga_options, & pipeline_options) ;
309
- let reflection_info = {
308
+ let ( source, entry_point) = {
309
+ let mut source = String :: new ( ) ;
310
+ let mut writer = hlsl:: Writer :: new ( & mut source, naga_options, & pipeline_options) ;
311
+
310
312
profiling:: scope!( "naga::back::hlsl::write" ) ;
311
- writer
313
+ let mut reflection_info = writer
312
314
. write ( & module, & info, frag_ep. as_ref ( ) )
313
- . map_err ( |e| crate :: PipelineError :: Linkage ( stage_bit, format ! ( "HLSL: {e:?}" ) ) ) ?
315
+ . map_err ( |e| crate :: PipelineError :: Linkage ( stage_bit, format ! ( "HLSL: {e:?}" ) ) ) ?;
316
+
317
+ assert_eq ! ( reflection_info. entry_point_names. len( ) , 1 ) ;
318
+
319
+ let entry_point = reflection_info
320
+ . entry_point_names
321
+ . pop ( )
322
+ . unwrap ( )
323
+ . map_err ( |e| crate :: PipelineError :: Linkage ( stage_bit, format ! ( "{e}" ) ) ) ?;
324
+
325
+ ( source, entry_point)
314
326
} ;
315
327
328
+ log:: info!(
329
+ "Naga generated shader for {:?} at {:?}:\n {}" ,
330
+ entry_point,
331
+ naga_stage,
332
+ source
333
+ ) ;
334
+
335
+ let key = ShaderCacheKey {
336
+ source,
337
+ entry_point,
338
+ stage : naga_stage,
339
+ shader_model : naga_options. shader_model ,
340
+ } ;
341
+
342
+ {
343
+ let mut shader_cache = self . shader_cache . lock ( ) ;
344
+ let nr_of_shaders_compiled = shader_cache. nr_of_shaders_compiled ;
345
+ if let Some ( value) = shader_cache. entries . get_mut ( & key) {
346
+ value. last_used = nr_of_shaders_compiled;
347
+ return Ok ( value. shader . clone ( ) ) ;
348
+ }
349
+ }
350
+
351
+ let source_name = stage. module . raw_name . as_deref ( ) ;
352
+
316
353
let full_stage = format ! (
317
354
"{}_{}" ,
318
355
naga_stage. to_hlsl_str( ) ,
319
356
naga_options. shader_model. to_str( )
320
357
) ;
321
358
322
- let raw_ep = reflection_info. entry_point_names [ 0 ]
323
- . as_ref ( )
324
- . map_err ( |e| crate :: PipelineError :: Linkage ( stage_bit, format ! ( "{e}" ) ) ) ?;
325
-
326
- let source_name = stage. module . raw_name . as_deref ( ) ;
327
-
328
359
// Compile with DXC if available, otherwise fall back to FXC
329
- let result = if let Some ( ref dxc_container) = self . dxc_container {
360
+ let compiled_shader = if let Some ( ref dxc_container) = self . dxc_container {
330
361
shader_compilation:: compile_dxc (
331
362
self ,
332
- & source,
363
+ & key . source ,
333
364
source_name,
334
- raw_ep ,
365
+ & key . entry_point ,
335
366
stage_bit,
336
367
& full_stage,
337
368
dxc_container,
338
- )
369
+ ) ?
339
370
} else {
340
371
shader_compilation:: compile_fxc (
341
372
self ,
342
- & source,
373
+ & key . source ,
343
374
source_name,
344
- raw_ep ,
375
+ & key . entry_point ,
345
376
stage_bit,
346
377
& full_stage,
347
- )
378
+ ) ?
348
379
} ;
349
380
350
- let log_level = if result. is_ok ( ) {
351
- log:: Level :: Info
352
- } else {
353
- log:: Level :: Error
354
- } ;
381
+ {
382
+ let mut shader_cache = self . shader_cache . lock ( ) ;
383
+ shader_cache. nr_of_shaders_compiled += 1 ;
384
+ let nr_of_shaders_compiled = shader_cache. nr_of_shaders_compiled ;
385
+ let value = ShaderCacheValue {
386
+ last_used : nr_of_shaders_compiled,
387
+ shader : compiled_shader. clone ( ) ,
388
+ } ;
389
+ shader_cache. entries . insert ( key, value) ;
355
390
356
- log:: log!(
357
- log_level,
358
- "Naga generated shader for {:?} at {:?}:\n {}" ,
359
- raw_ep,
360
- naga_stage,
361
- source
362
- ) ;
363
- result
391
+ // Retain all entries that have been used since we compiled the last 100 shaders.
392
+ if shader_cache. entries . len ( ) > 200 {
393
+ shader_cache
394
+ . entries
395
+ . retain ( |_, v| v. last_used >= nr_of_shaders_compiled - 100 ) ;
396
+ }
397
+ }
398
+
399
+ Ok ( compiled_shader)
364
400
}
365
401
366
402
pub fn raw_device ( & self ) -> & Direct3D12 :: ID3D12Device {
@@ -1831,11 +1867,6 @@ impl crate::Device for super::Device {
1831
1867
}
1832
1868
. map_err ( |err| crate :: PipelineError :: Linkage ( shader_stages, err. to_string ( ) ) ) ?;
1833
1869
1834
- unsafe { blob_vs. destroy ( ) } ;
1835
- if let Some ( blob_fs) = blob_fs {
1836
- unsafe { blob_fs. destroy ( ) } ;
1837
- } ;
1838
-
1839
1870
if let Some ( label) = desc. label {
1840
1871
raw. set_name ( label) ?;
1841
1872
}
@@ -1893,8 +1924,6 @@ impl crate::Device for super::Device {
1893
1924
}
1894
1925
} ;
1895
1926
1896
- unsafe { blob_cs. destroy ( ) } ;
1897
-
1898
1927
let raw: Direct3D12 :: ID3D12PipelineState = pair. map_err ( |err| {
1899
1928
crate :: PipelineError :: Linkage ( wgt:: ShaderStages :: COMPUTE , err. to_string ( ) )
1900
1929
} ) ?;
0 commit comments