1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
10 #include <sal/config.h>
12 #include <unicode/regex.h>
14 #include <comphelper/configuration.hxx>
15 #include <officecfg/Office/Common.hxx>
16 #include <opencl/openclconfig.hxx>
17 #include <opencl/platforminfo.hxx>
18 #include <rtl/ustring.hxx>
19 #include <rtl/ustrbuf.hxx>
20 #include <sal/log.hxx>
21 #include <sal/types.h>
22 #include <o3tl/string_view.hxx>
24 OpenCLConfig::OpenCLConfig() :
27 // This entry we have had for some time (when denylisting was
28 // done elsewhere in the code), so presumably there is a known
29 // good reason for it.
30 maDenyList
.insert(ImplMatcher("Windows", "", "Intel\\(R\\) Corporation", "", "9\\.17\\.10\\.2884"));
31 // This was reported to produce bogus values in unit tests
32 maDenyList
.insert(ImplMatcher("Windows", "", "Intel\\(R\\) Corporation", "", "27\\.20\\.100\\.8681"));
34 // For now, assume that AMD, Intel and NVIDIA drivers are good
35 maAllowList
.insert(ImplMatcher("", "", "Advanced Micro Devices, Inc\\.", "", ""));
36 maAllowList
.insert(ImplMatcher("", "", "Intel\\(R\\) Corporation", "", ""));
37 maAllowList
.insert(ImplMatcher("", "", "NVIDIA Corporation", "", ""));
40 bool OpenCLConfig::operator== (const OpenCLConfig
& r
) const
42 return (mbUseOpenCL
== r
.mbUseOpenCL
&&
43 maDenyList
== r
.maDenyList
&&
44 maAllowList
== r
.maAllowList
);
47 bool OpenCLConfig::operator!= (const OpenCLConfig
& r
) const
49 return !operator== (r
);
54 css::uno::Sequence
<OUString
> SetOfImplMatcherToStringSequence(const OpenCLConfig::ImplMatcherSet
& rSet
)
56 css::uno::Sequence
<OUString
> result(rSet
.size());
57 auto resultRange
= asNonConstRange(result
);
59 for (const auto& rItem
: rSet
)
62 rItem
.maOS
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
63 rItem
.maOSVersion
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
64 rItem
.maPlatformVendor
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
65 rItem
.maDevice
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
66 rItem
.maDriverVersion
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B");
72 OUString
getToken(std::u16string_view string
, sal_Int32
& index
)
74 std::u16string_view
token(o3tl::getToken(string
, 0, '/', index
));
75 OUStringBuffer result
;
78 while ((p
= token
.find('%', i
)) != std::u16string_view::npos
)
80 if (static_cast<sal_Int32
>(p
) > i
)
81 result
.append(token
.substr(i
, p
- i
));
82 if (p
< token
.size() - 2)
84 result
.append(sal_Unicode(o3tl::toInt32(token
.substr(p
+1, 2), 16)));
92 result
.append(token
.substr(i
));
94 return result
.makeStringAndClear();
97 OpenCLConfig::ImplMatcherSet
StringSequenceToSetOfImplMatcher(const css::uno::Sequence
<OUString
>& rSequence
)
99 OpenCLConfig::ImplMatcherSet result
;
101 for (const auto& rItem
: rSequence
)
103 OpenCLConfig::ImplMatcher m
;
105 m
.maOS
= getToken(rItem
, index
);
106 m
.maOSVersion
= getToken(rItem
, index
);
107 m
.maPlatformVendor
= getToken(rItem
, index
);
108 m
.maDevice
= getToken(rItem
, index
);
109 m
.maDriverVersion
= getToken(rItem
, index
);
117 bool match(const OUString
& rPattern
, const OUString
& rInput
)
119 if (rPattern
.isEmpty())
122 UErrorCode
nIcuError(U_ZERO_ERROR
);
123 icu::UnicodeString
sIcuPattern(reinterpret_cast<const UChar
*>(rPattern
.getStr()), rPattern
.getLength());
124 icu::UnicodeString
sIcuInput(reinterpret_cast<const UChar
*>(rInput
.getStr()), rInput
.getLength());
125 icu::RegexMatcher
aMatcher(sIcuPattern
, sIcuInput
, 0, nIcuError
);
127 return U_SUCCESS(nIcuError
) && aMatcher
.matches(nIcuError
) && U_SUCCESS(nIcuError
);
130 bool match(const OpenCLConfig::ImplMatcher
& rListEntry
, const OpenCLPlatformInfo
& rPlatform
, const OpenCLDeviceInfo
& rDevice
)
133 if (!rListEntry
.maOS
.isEmpty() && rListEntry
.maOS
!= "Windows")
136 if (!rListEntry
.maOS
.isEmpty() && rListEntry
.maOS
!= "Linux")
139 if (!rListEntry
.maOS
.isEmpty() && rListEntry
.maOS
!= "OS X")
143 // OS version check not yet implemented
145 if (!match(rListEntry
.maPlatformVendor
, rPlatform
.maVendor
))
148 if (!match(rListEntry
.maDevice
, rDevice
.maName
))
151 if (!match(rListEntry
.maDriverVersion
, rDevice
.maDriver
))
157 bool match(const OpenCLConfig::ImplMatcherSet
& rList
, const OpenCLPlatformInfo
& rPlatform
, const OpenCLDeviceInfo
& rDevice
, const char* sKindOfList
)
159 for (const auto& rListEntry
: rList
)
161 SAL_INFO("opencl", "Looking for match for platform=" << rPlatform
<< ", device=" << rDevice
<<
162 " in " << sKindOfList
<< " entry=" << rListEntry
);
164 if (match(rListEntry
, rPlatform
, rDevice
))
166 SAL_INFO("opencl", "Match!");
173 } // anonymous namespace
175 OpenCLConfig
OpenCLConfig::get()
179 result
.mbUseOpenCL
= officecfg::Office::Common::Misc::UseOpenCL::get();
181 result
.maDenyList
= StringSequenceToSetOfImplMatcher(officecfg::Office::Common::Misc::OpenCLDenyList::get());
182 result
.maAllowList
= StringSequenceToSetOfImplMatcher(officecfg::Office::Common::Misc::OpenCLAllowList::get());
187 void OpenCLConfig::set()
189 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
191 officecfg::Office::Common::Misc::UseOpenCL::set(mbUseOpenCL
, batch
);
192 officecfg::Office::Common::Misc::OpenCLDenyList::set(SetOfImplMatcherToStringSequence(maDenyList
), batch
);
193 officecfg::Office::Common::Misc::OpenCLAllowList::set(SetOfImplMatcherToStringSequence(maAllowList
), batch
);
198 bool OpenCLConfig::checkImplementation(const OpenCLPlatformInfo
& rPlatform
, const OpenCLDeviceInfo
& rDevice
) const
200 // Check denylist of known bad OpenCL implementations
201 if (match(maDenyList
, rPlatform
, rDevice
, "denylist"))
203 SAL_INFO("opencl", "Rejecting");
207 // Check for allowlist of known good OpenCL implementations
208 if (match(maAllowList
, rPlatform
, rDevice
, "allowlist"))
210 SAL_INFO("opencl", "Approving");
215 SAL_INFO("opencl", "Fallback: rejecting platform=" << rPlatform
<< ", device=" << rDevice
);
219 std::ostream
& operator<<(std::ostream
& rStream
, const OpenCLConfig
& rConfig
)
222 "UseOpenCL=" << (rConfig
.mbUseOpenCL
? "YES" : "NO") << ","
223 "DenyList=" << rConfig
.maDenyList
<< ","
224 "AllowList=" << rConfig
.maAllowList
<<
229 std::ostream
& operator<<(std::ostream
& rStream
, const OpenCLConfig::ImplMatcher
& rImpl
)
232 "OS=" << rImpl
.maOS
<< ","
233 "OSVersion=" << rImpl
.maOSVersion
<< ","
234 "PlatformVendor=" << rImpl
.maPlatformVendor
<< ","
235 "Device=" << rImpl
.maDevice
<< ","
236 "DriverVersion=" << rImpl
.maDriverVersion
<<
242 std::ostream
& operator<<(std::ostream
& rStream
, const OpenCLConfig::ImplMatcherSet
& rSet
)
245 for (auto i
= rSet
.cbegin(); i
!= rSet
.cend(); ++i
)
247 if (i
!= rSet
.cbegin())
255 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */