32
32
#include " driver/shaders/dxil/dxil_bytecode.h"
33
33
#include " lz4/lz4.h"
34
34
#include " md5/md5.h"
35
+ #include " miniz/miniz.h"
35
36
#include " replay/replay_driver.h"
36
37
#include " serialise/serialiser.h"
37
38
#include " dxbc_bytecode.h"
@@ -46,6 +47,7 @@ namespace
46
47
47
48
// lookup from plain filename -> absolute path of first result in search paths
48
49
std::unordered_map<rdcstr, rdcstr> cachedDebugFilesLookup;
50
+ int32_t cachedDebugFilesLookupInit = 0 ;
49
51
50
52
void CacheSearchDirDebugPaths (rdcstr dir)
51
53
{
@@ -70,7 +72,7 @@ void CacheSearchDirDebugPaths(rdcstr dir)
70
72
71
73
void CacheSearchDirDebugPaths ()
72
74
{
73
- if (!cachedDebugFilesLookup. empty () )
75
+ if (Atomic::CmpExch32 (&cachedDebugFilesLookupInit, 0 , 1 ) != 0 )
74
76
return ;
75
77
76
78
if (!RenderDoc::Inst ().IsReplayApp ())
@@ -92,6 +94,7 @@ namespace DXBC
92
94
void ResetSearchDirsCache ()
93
95
{
94
96
cachedDebugFilesLookup.clear ();
97
+ cachedDebugFilesLookupInit = 0 ;
95
98
}
96
99
97
100
rdcstr BasicDemangle (const rdcstr &possiblyMangledName)
@@ -2329,6 +2332,33 @@ DXBCContainer::DXBCContainer(const bytebuf &ByteCode, const rdcstr &debugInfoPat
2329
2332
PreprocessLineDirectives (m_DebugInfo->Files );
2330
2333
}
2331
2334
2335
+ // if we have DXIL bytecode, check for separate source-info chunks and layer them over the top
2336
+ if (m_DXILByteCode)
2337
+ {
2338
+ // check debug header first, but we don't expect to see these in a non-debug header
2339
+ for (uint32_t chunkIdx = 0 ; debugHeader && chunkIdx < debugHeader->numChunks ; chunkIdx++)
2340
+ {
2341
+ const uint32_t *fourcc = (const uint32_t *)(debugData + debugChunkOffsets[chunkIdx]);
2342
+ const uint32_t *chunkSize = (const uint32_t *)(fourcc + 1 );
2343
+
2344
+ const byte *chunkContents = (const byte *)(chunkSize + 1 );
2345
+
2346
+ if (*fourcc == FOURCC_SRCI)
2347
+ ProcessSourceInfo (chunkContents, *chunkSize);
2348
+ }
2349
+
2350
+ for (uint32_t chunkIdx = 0 ; header && chunkIdx < header->numChunks ; chunkIdx++)
2351
+ {
2352
+ const uint32_t *fourcc = (const uint32_t *)(data + chunkOffsets[chunkIdx]);
2353
+ const uint32_t *chunkSize = (const uint32_t *)(fourcc + 1 );
2354
+
2355
+ const byte *chunkContents = (const byte *)(chunkSize + 1 );
2356
+
2357
+ if (*fourcc == FOURCC_SRCI)
2358
+ ProcessSourceInfo (chunkContents, *chunkSize);
2359
+ }
2360
+ }
2361
+
2332
2362
// if we had bytecode in this container, ensure we had reflection. If it's a blob with only an
2333
2363
// input signature then we can do without reflection.
2334
2364
if (m_DXBCByteCode || m_DXILByteCode)
@@ -2372,6 +2402,297 @@ DXBCContainer::~DXBCContainer()
2372
2402
SAFE_DELETE (m_Reflection);
2373
2403
}
2374
2404
2405
+ struct SRCIHeader
2406
+ {
2407
+ uint32_t size; // utterly redundant?
2408
+ uint16_t flags;
2409
+ uint16_t numSections;
2410
+ };
2411
+
2412
+ enum class SRCISectionType : uint16_t
2413
+ {
2414
+ FileContents = 0 ,
2415
+ Filenames,
2416
+ Args,
2417
+ };
2418
+
2419
+ struct SRCISection
2420
+ {
2421
+ uint32_t sectionSize;
2422
+ uint16_t flags;
2423
+ SRCISectionType type;
2424
+ };
2425
+
2426
+ struct SRCIArgsSection
2427
+ {
2428
+ uint32_t flags;
2429
+ uint32_t dataSize;
2430
+ uint32_t numArgs;
2431
+ };
2432
+
2433
+ struct SRCIFileContentsSection
2434
+ {
2435
+ uint32_t sectionSize; // NOTE For this section only, this is the size of the data *with* the
2436
+ // header. Who knows why?
2437
+ uint16_t flags;
2438
+ uint16_t zLibCompressed;
2439
+ uint32_t dataSize;
2440
+ uint32_t uncompressedDataSize;
2441
+ uint32_t numFiles;
2442
+ };
2443
+
2444
+ struct SRCIFileContentsEntry
2445
+ {
2446
+ uint32_t entrySize;
2447
+ uint32_t flags;
2448
+ uint32_t fileSize;
2449
+ };
2450
+
2451
+ struct SRCIFilenamesSection
2452
+ {
2453
+ uint32_t flags;
2454
+ uint32_t numFiles;
2455
+ uint16_t dataSize;
2456
+ // NOTE: NO PADDING HERE BECAUSE OF COURSE NOT
2457
+ byte beginningOfData;
2458
+
2459
+ static constexpr size_t unpaddedSize () { return offsetof (SRCIFilenamesSection, beginningOfData); }
2460
+ };
2461
+
2462
+ struct SRCIFilenameEntry
2463
+ {
2464
+ uint32_t entrySize;
2465
+ uint32_t flags;
2466
+ uint32_t nameSize;
2467
+ uint32_t fileSize;
2468
+ };
2469
+
2470
+ void DXBCContainer::ProcessSourceInfo (const byte *chunkContents, uint32_t chunkSize)
2471
+ {
2472
+ const SRCIHeader *srci = (const SRCIHeader *)chunkContents;
2473
+ chunkContents += sizeof (SRCIHeader);
2474
+
2475
+ // redundant size? this should always be equal
2476
+ RDCASSERTEQUAL (srci->size , chunkSize);
2477
+ RDCASSERTEQUAL (srci->flags , 0 );
2478
+
2479
+ rdcarray<ShaderSourceFile> &sourceFiles = m_DXILByteCode->Files ;
2480
+
2481
+ if (!sourceFiles.empty ())
2482
+ {
2483
+ // if we have source files, check that they're all at least empty
2484
+ bool allEmpty = true ;
2485
+ for (const ShaderSourceFile &f : sourceFiles)
2486
+ allEmpty &= f.contents .empty ();
2487
+
2488
+ if (!allEmpty)
2489
+ RDCERR (" Some shader source files have contents being overridden by SRCI" );
2490
+ sourceFiles.clear ();
2491
+ }
2492
+
2493
+ for (uint32_t sec = 0 ; sec < srci->numSections ; sec++)
2494
+ {
2495
+ const SRCISection *section = (const SRCISection *)chunkContents;
2496
+ chunkContents += section->sectionSize ;
2497
+ RDCASSERTEQUAL (section->flags , 0 );
2498
+
2499
+ const byte *sectionContents = (const byte *)(section + 1 );
2500
+ switch (section->type )
2501
+ {
2502
+ case SRCISectionType::FileContents:
2503
+ {
2504
+ const SRCIFileContentsSection *contents = (const SRCIFileContentsSection *)(section + 1 );
2505
+
2506
+ // flags on flags on flags
2507
+ RDCASSERTEQUAL (contents->flags , 0 );
2508
+ // not only would this be pointless if it contains the section size, but dxc seems to set it
2509
+ // to 0 because of course it does.
2510
+ RDCASSERTEQUAL (contents->sectionSize , 0 );
2511
+
2512
+ if (!sourceFiles.empty () && sourceFiles.size () != contents->numFiles )
2513
+ {
2514
+ RDCERR (
2515
+ " Unexpected number of source files in contents section %u when we have %zu already" ,
2516
+ contents->numFiles , sourceFiles.size ());
2517
+ continue ;
2518
+ }
2519
+
2520
+ sourceFiles.resize (contents->numFiles );
2521
+
2522
+ bytebuf decompressedData;
2523
+ const byte *contentsData = (const byte *)(contents + 1 );
2524
+
2525
+ if (contents->zLibCompressed == 1 )
2526
+ {
2527
+ decompressedData.resize (contents->uncompressedDataSize );
2528
+
2529
+ mz_stream stream = {};
2530
+
2531
+ stream.next_in = contentsData;
2532
+ stream.avail_in = contents->dataSize ;
2533
+ stream.next_out = decompressedData.data ();
2534
+ stream.avail_out = contents->uncompressedDataSize ;
2535
+
2536
+ int status = mz_inflateInit (&stream);
2537
+ if (status != MZ_OK)
2538
+ {
2539
+ RDCERR (" Couldn't initialise zlib decompressor" );
2540
+ continue ;
2541
+ }
2542
+
2543
+ status = mz_inflate (&stream, MZ_FINISH);
2544
+ if (status != MZ_STREAM_END)
2545
+ {
2546
+ mz_inflateEnd (&stream);
2547
+ RDCERR (" zlib decompression failed" );
2548
+ continue ;
2549
+ }
2550
+ RDCASSERTEQUAL ((uint32_t )stream.total_out , contents->uncompressedDataSize );
2551
+ decompressedData.resize (stream.total_out );
2552
+
2553
+ status = mz_inflateEnd (&stream);
2554
+ if (status != MZ_OK)
2555
+ {
2556
+ RDCERR (" Failed shutting down zlib decompressor" );
2557
+ continue ;
2558
+ }
2559
+
2560
+ contentsData = decompressedData.data ();
2561
+ }
2562
+ else
2563
+ {
2564
+ RDCASSERTEQUAL (contents->zLibCompressed , 0 );
2565
+ }
2566
+
2567
+ for (uint32_t fileIdx = 0 ; fileIdx < contents->numFiles ; fileIdx++)
2568
+ {
2569
+ const SRCIFileContentsEntry *contentsEntry = (const SRCIFileContentsEntry *)contentsData;
2570
+ const char *fileContents = (const char *)(contentsEntry + 1 );
2571
+
2572
+ // should be null terminated but don't take any chances because who knows if that will change
2573
+ sourceFiles[fileIdx].contents .assign (fileContents, contentsEntry->fileSize );
2574
+
2575
+ RDCASSERTEQUAL (fileContents[contentsEntry->fileSize ], 0 );
2576
+
2577
+ // flags on flags on flags
2578
+ RDCASSERTEQUAL (contentsEntry->flags , 0 );
2579
+
2580
+ contentsData += contentsEntry->entrySize ;
2581
+ }
2582
+ break ;
2583
+ }
2584
+ case SRCISectionType::Filenames:
2585
+ {
2586
+ const SRCIFilenamesSection *names = (const SRCIFilenamesSection *)(section + 1 );
2587
+
2588
+ // flags on flags on flags
2589
+ RDCASSERTEQUAL (names->flags , 0 );
2590
+
2591
+ RDCASSERTEQUAL (AlignUp4 (names->dataSize + SRCIFilenamesSection::unpaddedSize ()),
2592
+ AlignUp4 (section->sectionSize - sizeof (SRCISection)));
2593
+
2594
+ if (!sourceFiles.empty () && sourceFiles.size () != names->numFiles )
2595
+ {
2596
+ RDCERR (
2597
+ " Unexpected number of source files in filenames section %u when we have %zu already" ,
2598
+ names->numFiles , sourceFiles.size ());
2599
+ continue ;
2600
+ }
2601
+
2602
+ sourceFiles.resize (names->numFiles );
2603
+
2604
+ const byte *nameContents = (const byte *)names + SRCIFilenamesSection::unpaddedSize ();
2605
+ for (uint32_t fileIdx = 0 ; fileIdx < names->numFiles ; fileIdx++)
2606
+ {
2607
+ const SRCIFilenameEntry *filenameEntry = (const SRCIFilenameEntry *)nameContents;
2608
+ const char *filename = (const char *)(filenameEntry + 1 );
2609
+
2610
+ sourceFiles[fileIdx].filename .assign (filename, filenameEntry->nameSize );
2611
+
2612
+ RDCASSERTEQUAL (filename[filenameEntry->nameSize ], 0 );
2613
+
2614
+ nameContents += filenameEntry->entrySize ;
2615
+
2616
+ // I have no idea what you're expected to do with this filesize. I guess pre-allocate, but why?
2617
+ RDCASSERT (sourceFiles[fileIdx].contents .empty () ||
2618
+ sourceFiles[fileIdx].contents .size () == filenameEntry->fileSize ,
2619
+ sourceFiles[fileIdx].contents .count (), filenameEntry->fileSize );
2620
+ }
2621
+
2622
+ break ;
2623
+ }
2624
+ case SRCISectionType::Args:
2625
+ {
2626
+ const SRCIArgsSection *args = (const SRCIArgsSection *)sectionContents;
2627
+
2628
+ // flags on flags on flags
2629
+ RDCASSERTEQUAL (args->flags , 0 );
2630
+ RDCASSERTEQUAL (AlignUp4 (args->dataSize + sizeof (SRCIArgsSection)),
2631
+ AlignUp4 (section->sectionSize - sizeof (SRCISection)));
2632
+
2633
+ ShaderCompileFlags flags = m_DXILByteCode->GetShaderCompileFlags ();
2634
+
2635
+ size_t cmdlineIdx = flags.flags .size ();
2636
+ for (size_t i = 0 ; i < flags.flags .size (); i++)
2637
+ {
2638
+ if (flags.flags [i].name == " preferSourceDebug" )
2639
+ continue ;
2640
+
2641
+ if (flags.flags [i].name == " @cmdline" )
2642
+ {
2643
+ cmdlineIdx = i;
2644
+
2645
+ // print an error if we're not just overriding default data, but continue to override
2646
+ // assuming the SRCI is 'better' data
2647
+ if (flags.flags [i].value != m_DXILByteCode->GetDefaultCommandLine ())
2648
+ {
2649
+ RDCERR (
2650
+ " Unexpected non-default command line in existing DXIL data, will be "
2651
+ " overridden by SRCI information: %s" ,
2652
+ flags.flags [i].value .c_str ());
2653
+ }
2654
+
2655
+ continue ;
2656
+ }
2657
+ }
2658
+
2659
+ // if we didn't find a @cmdline (we expect to always do that, even with no original debug
2660
+ // source info), add one here
2661
+ if (cmdlineIdx == flags.flags .size ())
2662
+ flags.flags .push_back ({" @cmdline" , " " });
2663
+
2664
+ flags.flags [cmdlineIdx].value .clear ();
2665
+
2666
+ // NULL-terminated pairs of strings
2667
+ const char *strData = (const char *)(args + 1 );
2668
+ for (uint32_t arg = 0 ; arg < args->numArgs ; arg++)
2669
+ {
2670
+ const char *name = strData;
2671
+ strData += strlen (name) + 1 ;
2672
+ const char *value = strData;
2673
+ strData += strlen (value) + 1 ;
2674
+
2675
+ if (arg > 0 )
2676
+ flags.flags [cmdlineIdx].value += " " ;
2677
+
2678
+ flags.flags [cmdlineIdx].value += " -" ;
2679
+ flags.flags [cmdlineIdx].value += name;
2680
+ if (value[0 ] != 0 )
2681
+ {
2682
+ flags.flags [cmdlineIdx].value += " =" ;
2683
+ flags.flags [cmdlineIdx].value += value;
2684
+ }
2685
+ }
2686
+
2687
+ m_DXILByteCode->SetShaderCompileFlags (flags);
2688
+
2689
+ break ;
2690
+ }
2691
+ default : RDCERR (" Unexpected SRCI section type %u" , section->type ); break ;
2692
+ }
2693
+ }
2694
+ }
2695
+
2375
2696
struct DxcArg
2376
2697
{
2377
2698
uint32_t bit;
0 commit comments