1#include "blocklist_driver.h"
2
3#include <base/detect.h>
4#include <base/str.h>
5
6#include <cstddef>
7
8#define VERSION_PARTS 4
9
10struct SVersion
11{
12 int m_aParts[VERSION_PARTS];
13
14 bool operator<=(const SVersion &Other) const
15 {
16 for(int i = 0; i < VERSION_PARTS; i++)
17 {
18 if(m_aParts[i] < Other.m_aParts[i])
19 return true;
20 if(m_aParts[i] > Other.m_aParts[i])
21 return false;
22 }
23 return true;
24 }
25};
26
27enum EBackendDriverBlockListType
28{
29 BACKEND_DRIVER_BLOCKLIST_TYPE_VERSION = 0,
30 BACKEND_DRIVER_BLOCKLIST_TYPE_VENDOR,
31};
32
33/* TODO: generalize it more for other drivers / vendors */
34struct SBackEndDriverBlockList
35{
36 EBackendDriverBlockListType m_BlockListType;
37
38 SVersion m_VersionMin;
39 SVersion m_VersionMax;
40
41 const char *m_pVendorName;
42
43 // the OpenGL version, that is supported
44 int m_AllowedMajor;
45 int m_AllowedMinor;
46 int m_AllowedPatch;
47
48 const char *m_pReason;
49
50 bool m_DisplayReason;
51 const char *m_pOSName;
52};
53
54static SBackEndDriverBlockList gs_aBlockList[] = {
55 {.m_BlockListType: BACKEND_DRIVER_BLOCKLIST_TYPE_VENDOR, .m_VersionMin: {26, 20, 100, 7800}, .m_VersionMax: {27, 20, 100, 8853}, .m_pVendorName: "Intel", .m_AllowedMajor: 2, .m_AllowedMinor: 0, .m_AllowedPatch: 0, .m_pReason: "This Intel driver version can cause crashes, please update it to a newer version.", .m_DisplayReason: false, .m_pOSName: "windows"}};
56
57const char *ParseBlocklistDriverVersions(const char *pVendorStr, const char *pVersionStr, int &BlocklistMajor, int &BlocklistMinor, int &BlocklistPatch, bool &RequiresWarning)
58{
59 if(str_find_nocase(haystack: pVendorStr, needle: "Intel") == nullptr)
60 return nullptr;
61
62 const char *pVersionStrStart = str_find_nocase(haystack: pVersionStr, needle: "Build ");
63 if(pVersionStrStart == nullptr)
64 return nullptr;
65
66 // ignore "Build ", after that, it should directly start with the driver version
67 pVersionStrStart += (ptrdiff_t)str_length(str: "Build ");
68
69 char aVersionStrHelper[512]; // the size is random, but shouldn't be too small probably
70
71 SVersion Version;
72 for(int &VersionPart : Version.m_aParts)
73 {
74 pVersionStrStart = str_next_token(str: pVersionStrStart, delim: ".", buffer: aVersionStrHelper, buffer_size: sizeof(aVersionStrHelper));
75 if(pVersionStrStart == nullptr)
76 return nullptr;
77
78 VersionPart = str_toint(str: aVersionStrHelper);
79 }
80
81 for(const auto &BlockListItem : gs_aBlockList)
82 {
83 if(str_comp(a: BlockListItem.m_pOSName, CONF_FAMILY_STRING) == 0)
84 {
85 bool DriverBlocked = false;
86 if(BlockListItem.m_BlockListType == BACKEND_DRIVER_BLOCKLIST_TYPE_VENDOR)
87 {
88 if(str_find_nocase(haystack: pVendorStr, needle: BlockListItem.m_pVendorName) != nullptr)
89 {
90 DriverBlocked = true;
91 }
92 }
93 else if(BlockListItem.m_BlockListType == BACKEND_DRIVER_BLOCKLIST_TYPE_VERSION)
94 {
95 if(BlockListItem.m_VersionMin <= Version && Version <= BlockListItem.m_VersionMax)
96 {
97 DriverBlocked = true;
98 }
99 }
100
101 if(DriverBlocked)
102 {
103 RequiresWarning = BlockListItem.m_DisplayReason;
104 BlocklistMajor = BlockListItem.m_AllowedMajor;
105 BlocklistMinor = BlockListItem.m_AllowedMinor;
106 BlocklistPatch = BlockListItem.m_AllowedPatch;
107 return BlockListItem.m_pReason;
108 }
109 }
110 }
111
112 return nullptr;
113}
114