Ark Server API (ASA) - Wiki
Loading...
Searching...
No Matches
GenericPlatformDriver.h
Go to the documentation of this file.
1// Copyright Epic Games, Inc. All Rights Reserved.
2
3#pragma once
4
5#include "CoreTypes.h"
6#include "Misc/AssertionMacros.h"
7#include "Containers/Array.h"
8#include "Math/UnrealMathUtility.h"
9#include "Containers/UnrealString.h"
10#include "Misc/DateTime.h"
11#include "Misc/Parse.h"
12#include "Misc/ConfigCacheIni.h"
13
14// TSize integer values separated by '.' e.g. "120.210.11.22"
15// made to compare different GPU driver versions
16// handles whitespace
17// if there are to too many numbers we take the left most ones
18// comparison operators (for driver comparison)
19template <int32 TSize>
21{
22public:
23 // constructor
25 {
26 for(uint32 i = 0; i < Size; ++i)
27 {
28 Value[i] = 0;
29 }
30 }
31
32 FMultiInt(const TCHAR* In)
33 {
34 Parse(In);
35 }
36
37 // like Parse but it doesn't alter the pointer
38 void GetValue(const TCHAR* In)
39 {
40 const TCHAR* Cpy = In;
41
42 Parse(Cpy);
43 }
44 // @param In "123.456" "132", pointer is advanced to be after the data
45 // if there isn't enough input values, the rightmost value gets set
46 void Parse(const TCHAR*& In)
47 {
48 check(In);
49 // clear
50 *this = FMultiInt();
51
52 // find out how many numbers we have
54 {
55 const TCHAR* p = In;
56
57 while(!IsSeparator(*p))
58 {
59 // '.' separates numbers
60 if(*p == TCHAR('.'))
61 {
63 }
64 ++p;
65 }
66 }
67
69
70 // parse the data
71 {
72 const TCHAR* p = In;
73 for(uint32 i = 0; i < NumberCount; ++i)
74 {
76
77 // go to next '.', operator or end
78 while(!IsSeparator(*p) && *p != TCHAR('.'))
79 {
80 ++p;
81 }
82
83 // jump over '.'
84 if(*p == TCHAR('.'))
85 {
86 ++p;
87 }
88 }
89
90 In = p;
91 }
92 }
93
94 // the base comparison operator, we derive the others from it
95 bool operator>(const FMultiInt<TSize>& rhs) const
96 {
97 for(uint32 i = 0 ; i < Size; ++i)
98 {
99 if(Value[i] > rhs.Value[i])
100 {
101 return true;
102 }
103 if(Value[i] < rhs.Value[i])
104 {
105 return false;
106 }
107 }
108
109 return false;
110 }
111 // could be optimized but doesn't have to be fast
112 bool operator==(const FMultiInt<TSize>& rhs) const
113 {
114 // map to existing operators
115 return !(*this > rhs) && !(rhs > *this);
116 }
117 // could be optimized but doesn't have to be fast
118 bool operator<(const FMultiInt<TSize>& rhs) const
119 {
120 // map to existing operators
121 return rhs > *this;
122 }
123 // could be optimized but doesn't have to be fast
124 bool operator!=(const FMultiInt<TSize>& rhs) const
125 {
126 // map to existing operators
127 return !(*this == rhs);
128 }
129 // could be optimized but doesn't have to be fast
130 bool operator>=(const FMultiInt<TSize>& rhs) const
131 {
132 // map to existing operators
133 return (*this == rhs) || (*this > rhs);
134 }
135 // could be optimized but doesn't have to be fast
136 bool operator<=(const FMultiInt<TSize>& rhs) const
137 {
138 // map to existing operators
139 return (*this == rhs) || (*this < rhs);
140 }
141
142 static constexpr uint32 Size = TSize;
143
144 // [0]:left .. [Size-1]:right
145 uint32 Value[Size];
146
147private:
148 bool IsSeparator(const TCHAR c)
149 {
150 // comparison operators are considered separators (e.g. "1.21 < 0.121")
151 return c == 0
152 || c == TCHAR('=')
153 || c == TCHAR('!')
154 || c == TCHAR('<')
155 || c == TCHAR('&')
156 || c == TCHAR('|')
157 || c == TCHAR('>');
158 }
159};
160
161// used to compare driver versions in Hardware.ini
163{
166
167// Find the comparison enum based on input text
168// @param In pointer is advanced to be after the data
169inline EComparisonOp ParseComparisonOp(const TCHAR*& In)
170{
171 if(In[0] == '=' && In[1] == '=')
172 {
173 In += 2;
174 return ECO_Equal;
175 }
176 if(In[0] == '!' && In[1] == '=')
177 {
178 In += 2;
179 return ECO_NotEqual;
180 }
181 if(*In == '>')
182 {
183 ++In;
184 if(*In == '=')
185 {
186 ++In;
187 return ECO_LargerThan;
188 }
189 return ECO_Larger;
190 }
191 if(*In == '<')
192 {
193 ++In;
194 if(*In == '=')
195 {
196 ++In;
197 return ECO_SmallerThan;
198 }
199 return ECO_Smaller;
200 }
201
202 return ECO_Unknown;
203}
204
205// general comparison with the comparison operator given as enum
206template <class T> bool Compare(const T& A, EComparisonOp Op, const T& B)
207{
208 switch(Op)
209 {
210 case ECO_Equal: return A == B;
211 case ECO_NotEqual: return A != B;
212 case ECO_Larger: return A > B;
213 case ECO_LargerThan: return A >= B;
214 case ECO_Smaller: return A < B;
215 case ECO_SmallerThan: return A <= B;
216 }
217 check(0);
218 return false;
219}
220
221// useful to express very simple math, later we might extend to express a range e.g. ">10 && <12.121"
222// @param InOpWithVersion e.g. "<=220.2"
223// @param CurrentVersion e.g. "219.1"
224inline bool CompareStringOp(const TCHAR* InOpWithMultiInt, const TCHAR* CurrentMultiInt)
225{
226 const TCHAR* p = InOpWithMultiInt;
227
229
230 // it makes sense to compare for equal if there is no operator
231 if(Op == ECO_Unknown)
232 {
233 Op = ECO_Equal;
234 }
235
236 FMultiInt<6> A, B;
237
238 A.GetValue(CurrentMultiInt);
239 B.Parse(p);
240
241 return Compare(A, Op, B);
242}
243
244
245// video driver details
247{
249 : VendorId(0)
250 {
251 }
252
253 // DirectX VendorId, 0 if not set, use functions below to set/get
254 uint32 VendorId;
255 // e.g. "NVIDIA GeForce GTX 680" or "AMD Radeon R9 200 / HD 7900 Series"
257 // e.g. "NVIDIA" or "Advanced Micro Devices, Inc."
259 // e.g. "15.200.1062.1004"(AMD)
260 // e.g. "9.18.13.4788"(NVIDIA) first number is Windows version (e.g. 7:Vista, 6:XP, 4:Me, 9:Win8(1), 10:Win7), last 5 have the UserDriver version encoded
261 // also called technical version number (https://wiki.mozilla.org/Blocklisting/Blocked_Graphics_Drivers)
262 // TEXT("Unknown") if driver detection failed
264 // e.g. "Catalyst 15.7.1"(AMD) or "Crimson 15.7.1"(AMD) or "347.88"(NVIDIA)
265 // also called commercial version number (https://wiki.mozilla.org/Blocklisting/Blocked_Graphics_Drivers)
267 // e.g. 3-13-2015
269 // e.g. D3D11, D3D12
271
272 bool IsValid() const
273 {
274 return !DeviceDescription.IsEmpty()
275 && VendorId
276 && (InternalDriverVersion != TEXT("Unknown")) // if driver detection code fails
277 && (InternalDriverVersion != TEXT("")); // if running on non Windows platform we don't fill in the driver version, later we need to check for the OS as well.
278 }
279
280 // set VendorId
281 void SetAMD() { VendorId = 0x1002; }
282 // set VendorId
283 void SetIntel() { VendorId = 0x8086; }
284 // set VendorId
285 void SetNVIDIA() { VendorId = 0x10DE; }
286 // get VendorId
287 bool IsAMD() const { return VendorId == 0x1002; }
288 // get VendorId
289 bool IsIntel() const { return VendorId == 0x8086; }
290 // get VendorId
291 bool IsNVIDIA() const { return VendorId == 0x10DE; }
292
293 bool IsSameDriverVersionGeneration(const TCHAR* InOpWithMultiInt) const
294 {
295 if (IsIntel())
296 {
297 const TCHAR* p = InOpWithMultiInt;
298 FString DriverVersion = GetUnifiedDriverVersion();
299
301
302 FMultiInt<6> A, B;
303
304 A.GetValue(*DriverVersion);
305 B.Parse(p);
306
307 // https://www.intel.com/content/www/us/en/support/articles/000005654/graphics.html
308 // Version format changed in April 2018 starting with xx.xx.100.xxxx
309 if (!((A.Value[4] >= 100) ^ (B.Value[4] >= 100)))
310 {
311 return true;
312 }
313 else
314 {
315 return false;
316 }
317 }
318
319 return true;
320 }
321
322 static FString TrimNVIDIAInternalVersion(const FString& InternalVersion)
323 {
324 // on the internal driver number: https://forums.geforce.com/default/topic/378546/confusion-over-driver-version-numbers/
325 // The first 7 shows u that is a Vista driver, 6 that is an XP and 4 that is Me
326 // we don't care about the windows version so we don't look at the front part of the driver version
327 // "9.18.13.4788" -> "347.88"
328 // "10.18.13.4788" -> "347.88"
329 // the following code works with the current numbering scheme, if needed we have to update that
330
331 // we don't care about the windows version so we don't look at the front part of the driver version
332 // e.g. 36.143
333 FString RightPart = InternalVersion.Right(6);
334
335 // move the dot
336 RightPart = RightPart.Replace(TEXT("."), TEXT(""));
337 RightPart.InsertAt(3, TEXT("."));
338 return RightPart;
339 }
340
342 {
343 // we use the internal version, not the user version to avoid problem where the name was altered
344 const FString& FullVersion = InternalDriverVersion;
345
346 if(IsNVIDIA() && (InternalDriverVersion != UserDriverVersion))
347 {
348 return TrimNVIDIAInternalVersion(FullVersion);
349 }
350 else if(IsAMD())
351 {
352 // examples for AMD: "13.12" "15.101.1007" "13.351"
353 }
354 else if(IsIntel())
355 {
356 // https://www.intel.com/content/www/us/en/support/articles/000005654/graphics.html
357 // Drop off the OS and DirectX version
358 // 27.20.100.8935 -> 100.8935
360 if (DotIndex != INDEX_NONE)
361 {
362 DotIndex = FullVersion.Find(TEXT("."), ESearchCase::CaseSensitive, ESearchDir::FromStart, DotIndex + 1);
363 if (DotIndex != INDEX_NONE)
364 {
365 return FullVersion.RightChop(DotIndex + 1);
366 }
367 }
368 }
369 return FullVersion;
370 }
371};
372
373// one entry in the Hardware.ini file
375{
376 // optional, e.g. "<=223.112.21.1", might includes comparison operators, later even things multiple ">12.22 <=12.44"
378 // optional, e.g. "<=MM-DD-YYYY"
380 // optional, e.g. "D3D11", "D3D12"
382 // required
384
385 // @param e.g. "DriverVersion=\"361.43\", Reason=\"UE-25096 Viewport flashes black and white when moving in the scene on latest Nvidia drivers\""
386 // At least one specifier of driver date or version is required to check for a match
387 void LoadFromINIString(const TCHAR* In)
388 {
389 FParse::Value(In, TEXT("DriverVersion="), DriverVersionString);
390 FParse::Value(In, TEXT("DriverDate="), DriverDateString);
391 ensure(!DriverVersionString.IsEmpty() || !DriverDateString.IsEmpty());
392
393 FParse::Value(In, TEXT("RHI="), RHIName);
394
395
396 // later:
397// FParse::Value(In, TEXT("DeviceId="), DeviceId);
398// FParse::Value(In, TEXT("API="), API);
399// ensure(API == TEXT("DX11"));
400
401 FParse::Value(In, TEXT("Reason="), Reason);
402 ensure(!Reason.IsEmpty());
403 }
404
405 // test if the given driver version is mentioned in the this entry
406 // @return true:yes, inform used, false otherwise
407 bool Test(const FGPUDriverInfo& Info) const
408 {
409 if (IsValid())
410 {
411 // If RHI specified, ignore if mismatched
412 if (!RHIName.IsEmpty() && RHIName != Info.RHIName)
413 {
414 return false;
415 }
416
417 if (!DriverVersionString.IsEmpty())
418 {
419 if (Info.IsSameDriverVersionGeneration(*DriverVersionString))
420 {
421 return CompareStringOp(*DriverVersionString, *Info.GetUnifiedDriverVersion());
422 }
423 else
424 {
425 return false;
426 }
427 }
428 else
429 {
430 FString TempDay, TempMonth, TempMonthDay, TempYear;
431
432 // Trim 1-2 character operator then reformat for comparison
433 int32 OpLength = FChar::IsDigit((*DriverDateString)[1]) ? 1 : 2;
434
435 const TCHAR* DriverDateStringChars = *DriverDateString;
436 EComparisonOp Op = ParseComparisonOp(DriverDateStringChars);
437 if (Op == ECO_Unknown)
438 {
439 Op = ECO_Equal;
440 }
441
442 FString DriverDateComparisonOp = DriverDateString.Left(OpLength);
443 FString TrimmedDriverDateString = DriverDateString.RightChop(OpLength);
444 TrimmedDriverDateString.Split(TEXT("-"), &TempMonthDay, &TempYear, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
445 TempMonthDay.Split(TEXT("-"), &TempMonth, &TempDay, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
446
447 FDateTime TestDate(FCString::Atoi(*TempYear), FCString::Atoi(*TempMonth), FCString::Atoi(*TempDay));
448
449 Info.DriverDate.Split(TEXT("-"), &TempMonthDay, &TempYear, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
450 TempMonthDay.Split(TEXT("-"), &TempMonth, &TempDay, ESearchCase::CaseSensitive, ESearchDir::FromEnd);
451
452 FDateTime InfoDate(FCString::Atoi(*TempYear), FCString::Atoi(*TempMonth), FCString::Atoi(*TempDay));
453
454 return Compare(InfoDate, Op, TestDate);
455 }
456 }
457
458 return true;
459 }
460
461 bool IsValid() const
462 {
463 return DriverVersionString.Len() > 1 || DriverDateString.Len() > 1;
464 }
465
466 /**
467 * Returns true if the latest version of the driver is denied by this entry,
468 * i.e. the comparison op is > or >=.
469 */
470 bool IsLatestDenied() const
471 {
472 bool bLatestDenied = false;
473 if (IsValid())
474 {
475 const TCHAR* DriverVersionTchar = !DriverVersionString.IsEmpty() ? *DriverVersionString : *DriverDateString;
476 EComparisonOp ComparisonOp = ParseComparisonOp(DriverVersionTchar);
477 bLatestDenied = (ComparisonOp == ECO_Larger) || (ComparisonOp == ECO_LargerThan);
478 }
479 return bLatestDenied;
480 }
481};
482
484{
485 // const as this is set in the constructor to be conveniently available
487
488 // constructor
489 FGPUHardware(const FGPUDriverInfo InDriverInfo)
491 {
492 // tests (should be very fast)
494 {
495 FMultiInt<2> A;
496 check(A.Value[0] == 0 && A.Value[1] == 0 && A.Size == 2);
497 A.GetValue(TEXT("18.98"));
498 check(A.Value[0] == 18 && A.Value[1] == 98);
499 A.GetValue(TEXT(""));
500 check(A.Value[0] == 0 && A.Value[1] == 0);
501 A.GetValue(TEXT("98"));
502 check(A.Value[0] == 0 && A.Value[1] == 98);
503 A.GetValue(TEXT("98.34.56"));
504 check(A.Value[0] == 98 && A.Value[1] == 34);
505 A.GetValue(TEXT(" 98 . 034 "));
506 check(A.Value[0] == 98 && A.Value[1] == 34);
507 A.GetValue(TEXT("\t 98\t.\t34\t"));
508 check(A.Value[0] == 98 && A.Value[1] == 34);
509
510 check(FMultiInt<2>(TEXT("3.07")) == FMultiInt<2>(TEXT("3.07")));
511 check(FMultiInt<2>(TEXT("3.05")) < FMultiInt<2>(TEXT("3.07")));
512 check(FMultiInt<2>(TEXT("3.05")) <= FMultiInt<2>(TEXT("3.07")));
513 check(FMultiInt<2>(TEXT("3.07")) <= FMultiInt<2>(TEXT("3.07")));
514 check(FMultiInt<2>(TEXT("3.08")) > FMultiInt<2>(TEXT("3.07")));
515 check(FMultiInt<2>(TEXT("3.08")) >= FMultiInt<2>(TEXT("3.07")));
516 check(FMultiInt<2>(TEXT("3.07")) >= FMultiInt<2>(TEXT("3.07")));
517 check(FMultiInt<2>(TEXT("3.05")) != FMultiInt<2>(TEXT("3.07")));
518 check(FMultiInt<2>(TEXT("4.05")) > FMultiInt<2>(TEXT("3.07")));
519 check(FMultiInt<2>(TEXT("4.05")) >= FMultiInt<2>(TEXT("3.07")));
520 check(FMultiInt<2>(TEXT("2.05")) < FMultiInt<2>(TEXT("3.07")));
521 check(FMultiInt<2>(TEXT("2.05")) <= FMultiInt<2>(TEXT("3.07")));
522
523 check(Compare(10, ECO_Equal, 10));
524 check(Compare(10, ECO_NotEqual, 20));
525 check(Compare(20, ECO_Larger, 10));
526 check(Compare(20, ECO_LargerThan, 10));
527 check(Compare(10, ECO_LargerThan, 10));
528 check(Compare(10, ECO_Smaller, 20));
529 check(Compare(10, ECO_SmallerThan, 10));
530
531 check(CompareStringOp(TEXT("<20.10"), TEXT("19.12")));
532 check(CompareStringOp(TEXT("<=20.10"), TEXT("19.12")));
533 check(CompareStringOp(TEXT("<=19.12"), TEXT("19.12")));
534 check(CompareStringOp(TEXT("==19.12"), TEXT("19.12")));
535 check(CompareStringOp(TEXT(">=19.12"), TEXT("19.12")));
536 check(CompareStringOp(TEXT(">=10.12"), TEXT("19.12")));
537 check(CompareStringOp(TEXT("!=20.12"), TEXT("19.12")));
538 check(CompareStringOp(TEXT(">10.12"), TEXT("19.12")));
539
540 {
541 FGPUDriverInfo Version;
542 Version.SetNVIDIA();
543 check(Version.IsNVIDIA());
544 check(!Version.IsAMD());
545 check(!Version.IsIntel());
546 Version.InternalDriverVersion = TEXT("10.18.13.4788");
547 check(Version.GetUnifiedDriverVersion() == TEXT("347.88"));
548 }
549 {
550 FGPUDriverInfo Version;
551 Version.SetAMD();
552 check(Version.IsAMD());
553 check(!Version.IsNVIDIA());
554 check(!Version.IsIntel());
555 Version.InternalDriverVersion = TEXT("15.200.1062.1004");
556 check(Version.GetUnifiedDriverVersion() == TEXT("15.200.1062.1004"));
557 }
558 {
559 FGPUDriverInfo Version;
560 Version.SetIntel();
561 check(Version.IsIntel());
562 check(!Version.IsAMD());
563 check(!Version.IsNVIDIA());
564 Version.DeviceDescription = TEXT("Intel(R) HD Graphics 4600");
565 Version.InternalDriverVersion = TEXT("9.18.10.3310");
566 Version.DriverDate = TEXT("9-17-2013");
567 check(Version.GetUnifiedDriverVersion() == TEXT("10.3310"));
568 }
569 }
570#endif// !(UE_BUILD_SHIPPING || UE_BUILD_TEST)
571 }
572
573 // @return a driver version intended to be shown to the user e.g. "15.30.1025.1001 12/17/2015 (Crimson Edition 15.12)"
575 {
576 const FString Section = GetVendorSectionName();
577
578 FString Ret;
579
580 if(!Section.IsEmpty())
581 {
582 TArray<FString> SuggestedDriverVersions;
583 GConfig->GetArray(*Section, TEXT("SuggestedDriverVersion"), SuggestedDriverVersions, GHardwareIni);
584
585 // Find specific RHI version first
586 if (InRHIName.Len() > 0)
587 {
588 for (const FString& SuggestedVersion : SuggestedDriverVersions)
589 {
590 int32 Found = SuggestedVersion.Find(InRHIName);
591 if (Found != INDEX_NONE && Found > 0 && SuggestedVersion[Found - 1] == ';')
592 {
593 Ret = SuggestedVersion.Left(Found - 1);
594 return Ret;
595 }
596 }
597 }
598
599 // Return the first generic one
600 for (const FString& SuggestedVersion : SuggestedDriverVersions)
601 {
602 int32 Found = 0;
603 if (!SuggestedVersion.FindChar(TEXT(';'), Found))
604 {
605 return SuggestedVersion;
606 }
607 }
608 }
609
610 return Ret;
611 }
612
613 // @return 0 if there is none
615 {
616 const FString Section = GetVendorSectionName();
617
618 if(!Section.IsEmpty())
619 {
620 TArray<FString> DenyListStrings;
621 GConfig->GetArray(*Section, TEXT("DriverDenyList"), DenyListStrings, GHardwareIni);
622
623 for(int32 i = 0; i < DenyListStrings.Num(); ++i)
624 {
625 FDriverDenyListEntry Entry;
626
627 const TCHAR* Line = *DenyListStrings[i];
628
629 ensure(Line[0] == TCHAR('('));
630
631 Entry.LoadFromINIString(&Line[1]);
632
633 if(Entry.Test(DriverInfo))
634 {
635 return Entry;
636 }
637 }
638 }
639
640 return FDriverDenyListEntry();
641 }
642
643 /**
644 * Returns true if the latest version of the driver is on the deny list.
645 */
646 bool IsLatestDenied() const
647 {
648 bool bLatestDenied = false;
649 const FString Section = GetVendorSectionName();
650
651 if(!Section.IsEmpty())
652 {
653 TArray<FString> DenyListStrings;
654 GConfig->GetArray(*Section, TEXT("DriverDenyList"), DenyListStrings, GHardwareIni);
655
656 for(int32 i = 0; !bLatestDenied && i < DenyListStrings.Num(); ++i)
657 {
658 FDriverDenyListEntry Entry;
659
660 const TCHAR* Line = *DenyListStrings[i];
661
662 ensure(Line[0] == TCHAR('('));
663
664 Entry.LoadFromINIString(&Line[1]);
665
666 bLatestDenied |= Entry.IsLatestDenied();
667 }
668 }
669 return bLatestDenied;
670 }
671
672 // to get a section name in the Hardware.ini file
673 // @return 0 if not found
675 {
676 const TCHAR* Section = nullptr;
677
678 if(DriverInfo.IsNVIDIA())
679 {
680 Section = TEXT("GPU_NVIDIA");
681 }
682 if(DriverInfo.IsAMD())
683 {
684 Section = TEXT("GPU_AMD");
685 }
686 else if(DriverInfo.IsIntel())
687 {
688 Section = TEXT("GPU_Intel");
689 }
690 // more GPU vendors can be added on demand
691 if (!Section)
692 {
693 return TEXT("");
694 }
695
696 return FString::Printf(TEXT("%s %s"), Section, ANSI_TO_TCHAR(FPlatformProperties::IniPlatformName()));
697 }
698};
#define check(expr)
#define ensure( InExpression)
#define UE_BUILD_TEST
Definition Build.h:23
#define UE_BUILD_SHIPPING
Definition Build.h:4
@ INDEX_NONE
EComparisonOp
Definition Enums.h:21655
bool CompareStringOp(const TCHAR *InOpWithMultiInt, const TCHAR *CurrentMultiInt)
@ ECO_SmallerThan
EComparisonOp ParseComparisonOp(const TCHAR *&In)
bool Compare(const T &A, EComparisonOp Op, const T &B)
#define TEXT(x)
Definition Platform.h:1108
#define ANSI_TO_TCHAR(str)
Definition StringConv.h:961
bool operator<(const FMultiInt< TSize > &rhs) const
bool IsSeparator(const TCHAR c)
FMultiInt(const TCHAR *In)
bool operator!=(const FMultiInt< TSize > &rhs) const
void Parse(const TCHAR *&In)
bool operator>(const FMultiInt< TSize > &rhs) const
bool operator>=(const FMultiInt< TSize > &rhs) const
static constexpr uint32 Size
void GetValue(const TCHAR *In)
bool operator<=(const FMultiInt< TSize > &rhs) const
bool operator==(const FMultiInt< TSize > &rhs) const
uint32 Value[Size]
UE_NODISCARD FORCEINLINE FString Right(int32 Count) const &
UE_NODISCARD FString RightChop(int32 Count) const &
FString & operator=(FString &&)=default
UE_NODISCARD FORCEINLINE int32 Len() const
bool Split(const FString &InS, FString *LeftS, FString *RightS, ESearchCase::Type SearchCase, ESearchDir::Type SearchDir=ESearchDir::FromStart) const
Definition String.cpp:384
UE_NODISCARD FORCEINLINE bool IsEmpty() const
UE_NODISCARD int32 Find(const FString &SubStr, ESearchCase::Type SearchCase=ESearchCase::IgnoreCase, ESearchDir::Type SearchDir=ESearchDir::FromStart, int32 StartPosition=INDEX_NONE) const
void InsertAt(int32 Index, const FString &Characters)
Definition String.cpp:469
@ CaseSensitive
Definition CString.h:25
@ FromStart
Definition CString.h:38
bool Test(const FGPUDriverInfo &Info) const
FString DriverDateString
bool IsLatestDenied() const
void LoadFromINIString(const TCHAR *In)
FString DriverVersionString
FString Reason
FString RHIName
bool IsValid() const
FString GetUnifiedDriverVersion() const
static FString TrimNVIDIAInternalVersion(const FString &InternalVersion)
bool IsSameDriverVersionGeneration(const TCHAR *InOpWithMultiInt) const
FString GetVendorSectionName() const
FDriverDenyListEntry FindDriverDenyListEntry() const
FGPUHardware(const FGPUDriverInfo InDriverInfo)
const FGPUDriverInfo DriverInfo
bool IsLatestDenied() const
FString GetSuggestedDriverVersion(const FString &InRHIName) const