1 /*========================== begin_copyright_notice ============================
2 
3 Copyright (C) 2017-2021 Intel Corporation
4 
5 SPDX-License-Identifier: MIT
6 
7 ============================= end_copyright_notice ===========================*/
8 
9 #include "AdaptorCommon/customApi.hpp"
10 #include <mutex>
11 
12 #if defined(_WIN32 )|| defined( _WIN64 )
13 #include "Windows.h"
14 #include <direct.h>
15 #include <wtypes.h>
16 #include <process.h>
17 #endif
18 
19 #include "common/debug/Debug.hpp"
20 #include "common/Stats.hpp"
21 #include "common/igc_regkeys.hpp"
22 #include "common/SysUtils.hpp"
23 #include "common/secure_string.h" // strcpy_s()
24 #include "Probe/Assertion.h"
25 
26 #if defined(IGC_DEBUG_VARIABLES)
27 #include "3d/common/iStdLib/File.h"
28 #endif
29 
30 
31 namespace {
32 
33 #ifndef CL_NUMBER
34 #define CL_NUMBER "<undefined>"
35 #endif
36 
37 #define _STRINGIFY(x) #x
38 #define STRINGIFY(x) _STRINGIFY(x)
39 
40 #if defined( _DEBUG )
41 #   if defined( _INTERNAL )
42 #       define CONFIGURATION DebugInternal
43 #   else
44 #       define CONFIGURATION Debug
45 #   endif
46 #else
47 #   if defined( _INTERNAL )
48 #       define CONFIGURATION ReleaseInternal
49 #   else
50 #       define CONFIGURATION Release
51 #   endif
52 #endif
53 
54 #if defined( _WIN64 )
55 #   define BITWIDTH x64
56 #elif defined( _WIN32 )
57 #   define BITWIDTH Win32
58 #else
59 #   define BITWIDTH Unknown
60 #endif
61 
62 // We don't want this static string in the RELEASE builds because it can be discovered using the
63 // Windows SysInternals Strings tool. We don't want to leak such information. Unfortunately this
64 // means that RELEASE builds can't be queried for their version information. There is no middle ground.
65 #if defined( _DEBUG ) || defined( _INTERNAL )
66 static const char g_cBuildInfo[] =
67     "CL: " STRINGIFY(CL_NUMBER) ", "
68     "CONFIGURATION: " STRINGIFY(CONFIGURATION) " " STRINGIFY(BITWIDTH) "\0";
69 #else
70 static const char g_cBuildInfo[] = "\0";
71 #endif
72 
73 #undef CONFIGURATION
74 
75 static bool g_debugFlags[ static_cast<int>( IGC::Debug::DebugFlag::END ) ] = {0};
76 
77 static struct
78 {
79     bool dumpODS;
80     bool dumpFile;
81 } g_dumpFlags[ static_cast<int>( IGC::Debug::DumpType::END ) ] = { };
82 
83 std::string g_shaderCorpusName;
84 std::string g_shaderOutputFolder;
85 std::string g_shaderOutputName;
86 
87 }
88 
89 namespace IGC
90 {
91     namespace Debug
92     {
str(DebugFlag value)93         EnumStr IGC_DEBUG_API_CALL str(DebugFlag value)
94         {
95 #define CASE(x) case DebugFlag::x: return STRINGIFY(x)
96             switch (value)
97             {
98                 CASE(DUMPS);
99                 CASE(DUMP_AFTER_PASSES);
100                 CASE(DUMP_TO_OUTS);
101                 CASE(DUMP_TO_OUTPUTDEBUGSTRING);
102                 CASE(OPTIMIZATION_STATS);
103                 CASE(TIME_STATS_SUM);
104                 CASE(TIME_STATS_PER_SHADER);
105                 CASE(TIME_STATS_COARSE);
106                 CASE(TIME_STATS_PER_PASS);
107                 CASE(MEM_STATS);
108                 CASE(MEM_STATS_DETAIL);
109                 CASE(SHADER_QUALITY_METRICS);
110                 CASE(SIMD8_ONLY);
111                 CASE(SIMD16_ONLY);
112                 CASE(SIMD32_ONLY);
113                 CASE(VISA_OUTPUT);
114                 CASE(VISA_BINARY);
115                 CASE(VISA_DUMPCOMMONISA);
116                 CASE(VISA_NOSCHEDULE);
117                 CASE(VISA_DOTALL);
118                 CASE(VISA_SLOWPATH);
119                 CASE(VISA_NOBXMLENCODER);
120             default : IGC_ASSERT_EXIT_MESSAGE(0, "unknown DebugFlag"); return "<unknown>";
121             }
122 #undef CASE
123         }
124 
str(DumpType value)125         EnumStr IGC_DEBUG_API_CALL str(DumpType value)
126         {
127 #define CASE(x) case DumpType::x: return STRINGIFY(x)
128             switch (value)
129             {
130                 CASE(ASM_TEXT);
131                 CASE(ASM_BC);
132                 CASE(TRANSLATED_IR_TEXT);
133                 CASE(TRANSLATED_IR_BC);
134                 CASE(PASS_IR_TEXT);
135                 CASE(PASS_IR_BC);
136                 CASE(OptIR_TEXT);
137                 CASE(OptIR_BC);
138                 CASE(VISA_TEXT);
139                 CASE(VISA_BC);
140                 CASE(GENX_ISA_TEXT);
141                 CASE(GENX_ISA_BC);
142                 CASE(LLVM_OPT_STAT_TEXT);
143                 CASE(TIME_STATS_TEXT);
144                 CASE(TIME_STATS_CSV);
145             default : IGC_ASSERT_EXIT_MESSAGE(0, "unknown DumpType"); return "<unknown>";
146             }
147 #undef CASE
148         }
149 
str(DumpLoc value)150         EnumStr IGC_DEBUG_API_CALL str(DumpLoc value)
151         {
152 #define CASE(x) case DumpLoc::x: return STRINGIFY(x)
153             switch (value)
154             {
155                 CASE(ODS);
156                 CASE(FILE);
157             default : IGC_ASSERT_EXIT_MESSAGE(0, "unknown DumpLoc"); return "<unknown>";
158             }
159 #undef CASE
160         }
161 
SetCompilerOption(OptionFlag flag,debugString s)162         void IGC_DEBUG_API_CALL SetCompilerOption(OptionFlag flag, debugString s)
163         {
164 #if defined(IGC_DEBUG_VARIABLES)
165             switch(flag)
166             {
167 #define DECLARE_IGC_REGKEY(dataType, regkeyName, defaultValue, description, releaseMode) \
168             case OptionFlag::OPTION_##regkeyName: \
169             strcpy_s(g_RegKeyList.regkeyName.m_string, sizeof(debugString), s);   \
170             break;
171 #include "common/igc_regkeys.h"
172 #undef DECLARE_IGC_REGKEY
173             default:
174                 break;
175             }
176 #endif
177         }
178 
SetCompilerOption(OptionFlag flag,int value)179         void IGC_DEBUG_API_CALL SetCompilerOption( OptionFlag flag, int value )
180         {
181 #if defined(IGC_DEBUG_VARIABLES)
182             switch(flag)
183             {
184 #define DECLARE_IGC_REGKEY(dataType, regkeyName, defaultValue, description, releaseMode) \
185             case OptionFlag::OPTION_##regkeyName: \
186                 g_RegKeyList.regkeyName.m_Value = value;   \
187             break;
188 #include "common/igc_regkeys.h"
189 #undef DECLARE_IGC_REGKEY
190             default:
191                 break;
192             }
193 #endif
194         }
195 
SetCompilerOptionValue(const char * flagName,int value)196         extern "C" void IGC_DEBUG_API_CALL SetCompilerOptionValue( const char* flagName, int value )
197         {
198 #if defined(IGC_DEBUG_VARIABLES)
199             if (!flagName)
200             {
201                 return;
202             }
203 
204             SRegKeyVariableMetaData* pRegKeyVariable = (SRegKeyVariableMetaData*)&g_RegKeyList;
205             unsigned NUM_REGKEY_ENTRIES = sizeof(SRegKeysList) / sizeof(SRegKeyVariableMetaData);
206             for (DWORD i = 0; i < NUM_REGKEY_ENTRIES; i++)
207             {
208                 const char* name = pRegKeyVariable[i].GetName();
209 
210                 if (!strcmp(flagName, name))
211                 {
212                     pRegKeyVariable[i].m_Value = value;
213                     break;
214                 }
215             }
216 #endif
217         }
218 
SetCompilerOptionString(const char * flagName,debugString s)219         extern "C" void IGC_DEBUG_API_CALL SetCompilerOptionString( const char* flagName, debugString s )
220         {
221 #if defined(IGC_DEBUG_VARIABLES)
222             if (!flagName)
223             {
224                 return;
225             }
226 
227             SRegKeyVariableMetaData* pRegKeyVariable = (SRegKeyVariableMetaData*)&g_RegKeyList;
228             unsigned NUM_REGKEY_ENTRIES = sizeof(SRegKeysList) / sizeof(SRegKeyVariableMetaData);
229             for (DWORD i = 0; i < NUM_REGKEY_ENTRIES; i++)
230             {
231                 const char* name = pRegKeyVariable[i].GetName();
232 
233                 if (!strcmp(flagName, name))
234                 {
235                     strcpy_s(pRegKeyVariable[i].m_string,sizeof(debugString), s);
236                     break;
237                 }
238             }
239 #endif
240         }
241 
SetDebugFlag(DebugFlag flag,bool enabled)242         void IGC_DEBUG_API_CALL SetDebugFlag( DebugFlag flag, bool enabled )
243         {
244             IGC_ASSERT_EXIT_MESSAGE((0 <= static_cast<int>(flag)), "range sanity check");
245             IGC_ASSERT_EXIT_MESSAGE((static_cast<int>(flag) < static_cast<int> (DebugFlag::END)), "range sanity check");
246 
247 #if defined( _DEBUG ) || defined( _INTERNAL )
248             g_debugFlags[ static_cast<int>( flag ) ] = enabled;
249 #else
250             (void) flag;
251             (void) enabled;
252 #endif
253         }
254 
GetDebugFlag(DebugFlag flag)255         bool IGC_DEBUG_API_CALL GetDebugFlag( DebugFlag flag )
256         {
257             IGC_ASSERT_EXIT_MESSAGE((0 <= static_cast<int>(flag)), "range sanity check");
258             IGC_ASSERT_EXIT_MESSAGE((static_cast<int>(flag) < static_cast<int> (DebugFlag::END)), "range sanity check");
259 
260 #if defined( _DEBUG ) || defined( _INTERNAL )
261 
262 #if defined(_WIN32 )|| defined( _WIN64 )
263             //Disable Dump  for OS Applications
264             if ( (DebugFlag::VISA_OUTPUT == flag) ||
265                  (DebugFlag::VISA_BINARY == flag)  ||
266                  (DebugFlag::VISA_DUMPCOMMONISA == flag)
267                 )
268             {
269                 if (GetModuleHandleA("dwm.exe") || GetModuleHandleA("explorer.exe"))
270                 {
271                     return false;
272                 }
273 
274             }
275 #endif
276             return g_debugFlags[ static_cast<int>(flag) ];
277 #else
278             (void) flag;
279             return false;
280 #endif
281         }
282 
SetDumpFlag(DumpType type,DumpLoc loc,bool enabled)283         void IGC_DEBUG_API_CALL SetDumpFlag( DumpType type, DumpLoc loc, bool enabled )
284         {
285             IGC_ASSERT_EXIT_MESSAGE((0 <= static_cast<int>(type)), "range sanity check");
286             IGC_ASSERT_EXIT_MESSAGE((static_cast<int>(type) < static_cast<int> (DumpType::END)), "range sanity check");
287 
288 #if defined( _DEBUG ) || defined( _INTERNAL )
289             switch (loc)
290             {
291             case DumpLoc::ODS  : g_dumpFlags[ static_cast<int>(type) ].dumpODS  = enabled; break;
292             case DumpLoc::FILE : g_dumpFlags[ static_cast<int>(type) ].dumpFile = enabled; break;
293             default            : IGC_ASSERT_EXIT_MESSAGE(0, "unreachable"); break;
294             }
295 #else
296             (void) type;
297             (void) loc;
298             (void) enabled;
299 #endif
300         }
301 
GetDumpFlag(DumpType type,DumpLoc loc)302         bool IGC_DEBUG_API_CALL GetDumpFlag( DumpType type, DumpLoc loc )
303         {
304             IGC_ASSERT_EXIT_MESSAGE((0 <= static_cast<int>(type)), "range sanity check");
305             IGC_ASSERT_EXIT_MESSAGE((static_cast<int>(type) < static_cast<int> (DumpType::END)), "range sanity check");
306 
307 #if defined( _DEBUG ) || defined( _INTERNAL )
308 
309 #if defined(_WIN32 )|| defined( _WIN64 )
310             //Disable Dump  for OS Applications
311             if (GetModuleHandleA("dwm.exe") || GetModuleHandleA("explorer.exe"))
312             {
313                 return false;
314             }
315 #endif
316             switch (loc)
317             {
318             case DumpLoc::ODS  : return g_dumpFlags[ static_cast<int>(type) ].dumpODS;
319             case DumpLoc::FILE : return g_dumpFlags[ static_cast<int>(type) ].dumpFile;
320             default            : IGC_ASSERT_EXIT_MESSAGE(0, "unreachable"); return false;
321             }
322 #else
323             (void) type;
324             (void) loc;
325             return false;
326 #endif
327         }
328 
SetShaderCorpusName(CorpusName name)329         void IGC_DEBUG_API_CALL SetShaderCorpusName( CorpusName name )
330         {
331 #if defined( _DEBUG ) || defined( _INTERNAL )
332             g_shaderCorpusName = name;
333 #else
334             (void) name;
335 #endif
336         }
337 
GetShaderCorpusName()338         CorpusName IGC_DEBUG_API_CALL GetShaderCorpusName()
339         {
340 #if defined( _DEBUG ) || defined( _INTERNAL )
341             return g_shaderCorpusName.c_str();
342 #else
343             return "";
344 #endif
345         }
346 
SetShaderOutputFolder(OutputFolderName name)347         void IGC_DEBUG_API_CALL SetShaderOutputFolder( OutputFolderName name )
348         {
349 #if defined(IGC_DEBUG_VARIABLES)
350             g_shaderOutputFolder = name;
351 #endif
352         }
SetShaderOutputName(OutputName name)353         void IGC_DEBUG_API_CALL SetShaderOutputName( OutputName name )
354         {
355 #if defined(IGC_DEBUG_VARIABLES)
356             g_shaderOutputName = name;
357 #endif
358         }
359 
GetBaseIGCOutputFolder()360         OutputFolderName IGC_DEBUG_API_CALL GetBaseIGCOutputFolder()
361         {
362 #if defined(IGC_DEBUG_VARIABLES)
363             static std::mutex m;
364             std::lock_guard<std::mutex> lck(m);
365             static std::string IGCBaseFolder;
366             if(IGCBaseFolder != "")
367             {
368                 return IGCBaseFolder.c_str();
369             }
370 #   if defined(_WIN64) || defined(_WIN32)
371             if (!IGC_IS_FLAG_ENABLED(DumpToCurrentDir) && !IGC_IS_FLAG_ENABLED(DumpToCustomDir))
372             {
373                 bool needMkdir =
374                     IGC_IS_FLAG_ENABLED(DumpLLVMIR) ||
375                     IGC_IS_FLAG_ENABLED(EnableCosDump) ||
376                     IGC_IS_FLAG_ENABLED(EnableVISAOutput) ||
377                     IGC_IS_FLAG_ENABLED(EnableVISABinary) ||
378                     IGC_IS_FLAG_ENABLED(EnableVISADumpCommonISA) ||
379                     GetDebugFlag(DebugFlag::DUMP_AFTER_PASSES) ||
380                     GetDebugFlag(DebugFlag::VISA_OUTPUT) ||
381                     GetDebugFlag(DebugFlag::VISA_BINARY) ||
382                     GetDebugFlag(DebugFlag::VISA_DUMPCOMMONISA) ||
383                     IGC_IS_FLAG_ENABLED(EnableCapsDump) ||
384                     IGC_IS_FLAG_ENABLED(ShaderOverride);
385 
386                 char dumpPath[256];
387 
388                 sprintf_s(dumpPath, "c:\\Intel\\IGC\\");
389 
390                 if(GetFileAttributesA(dumpPath) != FILE_ATTRIBUTE_DIRECTORY && needMkdir)
391                 {
392                     _mkdir(dumpPath);
393                 }
394 
395                 // Make sure we can write in the dump folder as the app may be sandboxed
396                 if(needMkdir)
397                 {
398                     int tmp_id = _getpid();
399                     std::string testFilename = std::string(dumpPath) + "testfile" + std::to_string(tmp_id);
400                     HANDLE testFile =
401                         CreateFileA(testFilename.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_FLAG_DELETE_ON_CLOSE, NULL);
402                     if(testFile == INVALID_HANDLE_VALUE)
403                     {
404                         char temppath[256];
405                         if(GetTempPathA(sizeof(temppath), temppath) != 0)
406                         {
407                             sprintf_s(dumpPath, "%sIGC\\", temppath);
408                         }
409                     }
410                     else
411                     {
412                         CloseHandle(testFile);
413                     }
414                 }
415 
416                 if(GetFileAttributesA(dumpPath) != FILE_ATTRIBUTE_DIRECTORY && needMkdir)
417                 {
418                     _mkdir(dumpPath);
419                 }
420 
421                 IGCBaseFolder = dumpPath;
422             }
423             else if (IGC_IS_FLAG_ENABLED(DumpToCustomDir))
424             {
425                 std::string dumpPath = "c:\\Intel\\IGC\\";        // default if something goes wrong
426                 const char* custom_dir = IGC_GET_REGKEYSTRING(DumpToCustomDir);
427                 if (custom_dir != nullptr && strlen(custom_dir) > 0)
428                 {
429                     dumpPath = custom_dir;
430                 }
431 
432                 char pathBuf[256];
433                 iSTD::CreateAppOutputDir(pathBuf, 256, dumpPath.c_str(), false, false, false);
434 
435                 IGCBaseFolder = pathBuf;
436             }
437 #elif defined ANDROID
438 
439             if(IGC_IS_FLAG_ENABLED(DumpToCurrentDir))
440                 return "";
441             IGCBaseFolder = "/sdcard/intel/igc/";
442 
443 #elif !defined __APPLE__
444         if (!IGC_IS_FLAG_ENABLED(DumpToCustomDir))
445         {
446             IGCBaseFolder = "/tmp/IntelIGC/";
447         }
448         else
449         {
450             std::string dumpPath = "/tmp/IntelIGC/";        // default if something goes wrong
451             const char* custom_dir = IGC_GET_REGKEYSTRING(DumpToCustomDir);
452             if (custom_dir != nullptr && strlen(custom_dir) > 0)
453             {
454                 dumpPath = custom_dir;
455                 dumpPath += "/";
456             }
457 
458             char pathBuf[256];
459             iSTD::CreateAppOutputDir(pathBuf, 256, dumpPath.c_str(), false, false, false);
460 
461             IGCBaseFolder = pathBuf;
462         }
463 #endif
464             return IGCBaseFolder.c_str();
465 #else
466             return "";
467 #endif
468         }
469 
GetShaderOverridePath()470         OutputFolderName IGC_DEBUG_API_CALL GetShaderOverridePath()
471         {
472             if(IGC_IS_FLAG_ENABLED(ShaderOverride))
473             {
474                 static std::mutex m;
475                 std::lock_guard<std::mutex> lck(m);
476                 static std::string overridePath;
477                 if(overridePath == "")
478                 {
479                     overridePath = std::string(GetBaseIGCOutputFolder()) + "ShaderOverride/";
480                 }
481                 return overridePath.c_str();
482             }
483             return "";
484         }
485 
GetShaderOutputFolder()486         OutputFolderName IGC_DEBUG_API_CALL GetShaderOutputFolder()
487         {
488 #if defined(IGC_DEBUG_VARIABLES)
489             static std::mutex m;
490             std::lock_guard<std::mutex> lck(m);
491             if(g_shaderOutputFolder != "")
492             {
493                 return g_shaderOutputFolder.c_str();
494             }
495 #   if defined(_WIN64) || defined(_WIN32)
496             if (!IGC_IS_FLAG_ENABLED(DumpToCurrentDir) && !IGC_IS_FLAG_ENABLED(DumpToCustomDir))
497             {
498                 char dumpPath[256];
499                 sprintf_s(dumpPath, "%s", GetBaseIGCOutputFolder());
500                 char appPath[MAX_PATH] = { 0 };
501                 // check a process id and make an adequate directory for it:
502 
503                 if (::GetModuleFileNameA(NULL, appPath, sizeof(appPath)-1))
504                 {
505                     std::string appPathStr = std::string(appPath);
506                     int pos = appPathStr.find_last_of("\\") + 1;
507 
508                     if (IGC_IS_FLAG_ENABLED(ShaderDumpPidDisable))
509                     {
510                         sprintf_s(dumpPath, "%s%s\\", dumpPath, appPathStr.substr(pos, MAX_PATH).c_str());
511                     }
512                     else
513                     {
514                         sprintf_s(dumpPath, "%s%s_%d\\", dumpPath, appPathStr.substr(pos, MAX_PATH).c_str(), _getpid());
515                     }
516                 }
517                 else
518                 {
519                     sprintf_s(dumpPath, "%sunknownProcess_%d\\", dumpPath, _getpid());
520                 }
521 
522                 if (GetFileAttributesA(dumpPath) != FILE_ATTRIBUTE_DIRECTORY)
523                 {
524                     _mkdir(dumpPath);
525                 }
526 
527                 g_shaderOutputFolder = dumpPath;
528             }
529             else if (IGC_IS_FLAG_ENABLED(DumpToCustomDir))
530             {
531                 char pathBuf[256];
532                 iSTD::CreateAppOutputDir(pathBuf, 256, GetBaseIGCOutputFolder(), false, true, !IGC_IS_FLAG_ENABLED(ShaderDumpPidDisable));
533                 g_shaderOutputFolder = pathBuf;
534             }
535 #elif defined ANDROID
536 
537             if (IGC_IS_FLAG_ENABLED(DumpToCurrentDir))
538 
539                 return "";
540 
541 
542 
543             if (!SysUtils::CreateDir(GetBaseIGCOutputFolder(), true, IGC_IS_FLAG_DISABLED(ShaderDumpPidDisable), &g_shaderOutputFolder))
544 
545                 g_shaderOutputFolder = "";
546 
547 #elif !defined __APPLE__
548             if (!IGC_IS_FLAG_ENABLED(DumpToCurrentDir) && g_shaderOutputFolder == "" && !IGC_IS_FLAG_ENABLED(DumpToCustomDir))
549             {
550                 bool needMkdir = false;
551 
552                 if (IGC_IS_FLAG_ENABLED(DumpLLVMIR) ||
553                     IGC_IS_FLAG_ENABLED(EnableCosDump) ||
554                     IGC_IS_FLAG_ENABLED(EnableVISAOutput) ||
555                     IGC_IS_FLAG_ENABLED(EnableVISABinary) ||
556                     IGC_IS_FLAG_ENABLED(EnableVISADumpCommonISA) ||
557                     GetDebugFlag(DebugFlag::DUMP_AFTER_PASSES) ||
558                     GetDebugFlag(DebugFlag::VISA_OUTPUT) ||
559                     GetDebugFlag(DebugFlag::VISA_BINARY) ||
560                     GetDebugFlag(DebugFlag::VISA_DUMPCOMMONISA) ||
561                     IGC_IS_FLAG_ENABLED(EnableCapsDump))
562                 {
563                     needMkdir = true;
564                 }
565 
566                 char path[MAX_PATH] = { 0 };
567                 bool pidEnabled = IGC_IS_FLAG_DISABLED(ShaderDumpPidDisable);
568 
569                 if (needMkdir)
570                 {
571                     iSTD::CreateAppOutputDir(
572                         path,
573                         MAX_PATH,
574                         GetBaseIGCOutputFolder(),
575                         false,
576                         true,
577                         pidEnabled);
578                 }
579 
580 
581                 g_shaderOutputFolder = path;
582             }
583             else if (IGC_IS_FLAG_ENABLED(DumpToCustomDir))
584             {
585                 char pathBuf[256];
586                 iSTD::CreateAppOutputDir(pathBuf, 256, GetBaseIGCOutputFolder(), false, false, false);
587                 g_shaderOutputFolder = pathBuf;
588             }
589 
590 #endif
591             return g_shaderOutputFolder.c_str();
592 #else
593             return "";
594 #endif
595         }
596 
GetFunctionDebugFile()597         OutputName IGC_DEBUG_API_CALL GetFunctionDebugFile()
598         {
599             if (IGC_GET_FLAG_VALUE(SelectiveFunctionControl) != 0)
600             {
601                 static std::mutex m;
602                 std::lock_guard<std::mutex> lck(m);
603                 static std::string functionDebugFilePath;
604                 if (functionDebugFilePath == "")
605                 {
606                     functionDebugFilePath = std::string(GetBaseIGCOutputFolder()) + "FunctionDebug.txt";
607                 }
608                 return functionDebugFilePath.c_str();
609             }
610             return "";
611         }
612 
GetShaderOutputName()613         OutputName IGC_DEBUG_API_CALL GetShaderOutputName()
614         {
615 #if defined(IGC_DEBUG_VARIABLES)
616             return g_shaderOutputName.c_str();
617 #else
618             return "";
619 #endif
620         }
621 
GetVersionInfo()622         VersionInfo IGC_DEBUG_API_CALL GetVersionInfo()
623         {
624             return g_cBuildInfo;
625         }
626     }
627 }
628