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 <string_view>
14 #include <unicode/regex.h>
16 #include <comphelper/configuration.hxx>
17 #include <officecfg/Office/Common.hxx>
18 #include <opencl/openclconfig.hxx>
19 #include <opencl/platforminfo.hxx>
20 #include <rtl/ustring.hxx>
21 #include <rtl/ustrbuf.hxx>
22 #include <sal/log.hxx>
23 #include <sal/types.h>
25 OpenCLConfig::OpenCLConfig() :
28 // This entry we have had for some time (when denylisting was
29 // done elsewhere in the code), so presumably there is a known
30 // good reason for it.
31 maDenyList
.insert(ImplMatcher("Windows", "", "Intel\\(R\\) Corporation", "", "9\\.17\\.10\\.2884"));
32 // This was reported to produce bogus values in unit tests
33 maDenyList
.insert(ImplMatcher("Windows", "", "Intel\\(R\\) Corporation", "", "27\\.20\\.100\\.8681"));
35 // For now, assume that AMD, Intel and NVIDIA drivers are good
36 maAllowList
.insert(ImplMatcher("", "", "Advanced Micro Devices, Inc\\.", "", ""));
37 maAllowList
.insert(ImplMatcher("", "", "Intel\\(R\\) Corporation", "", ""));
38 maAllowList
.insert(ImplMatcher("", "", "NVIDIA Corporation", "", ""));
41 bool OpenCLConfig::operator== (const OpenCLConfig
& r
) const
43 return (mbUseOpenCL
== r
.mbUseOpenCL
&&
44 maDenyList
== r
.maDenyList
&&
45 maAllowList
== r
.maAllowList
);
48 bool OpenCLConfig::operator!= (const OpenCLConfig
& r
) const
50 return !operator== (r
);
55 css::uno::Sequence
<OUString
> SetOfImplMatcherToStringSequence(const OpenCLConfig::ImplMatcherSet
& rSet
)
57 css::uno::Sequence
<OUString
> result(rSet
.size());
58 auto resultRange
= asNonConstRange(result
);
60 for (const auto& rItem
: rSet
)
63 rItem
.maOS
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
64 rItem
.maOSVersion
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
65 rItem
.maPlatformVendor
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
66 rItem
.maDevice
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
67 rItem
.maDriverVersion
.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B");
73 OUString
getToken(const OUString
& string
, sal_Int32
& index
)
75 OUString
token(string
.getToken(0, '/', index
));
76 OUStringBuffer result
;
79 while ((p
= token
.indexOf('%', i
)) >= 0)
82 result
.append(token
.subView(i
, p
- i
));
83 if (p
< token
.getLength() - 2)
85 result
.append(sal_Unicode(token
.copy(p
+1, 2).toInt32(16)));
90 i
= token
.getLength();
93 result
.append(token
.subView(i
));
95 return result
.makeStringAndClear();
98 OpenCLConfig::ImplMatcherSet
StringSequenceToSetOfImplMatcher(const css::uno::Sequence
<OUString
>& rSequence
)
100 OpenCLConfig::ImplMatcherSet result
;
102 for (const auto& rItem
: rSequence
)
104 OpenCLConfig::ImplMatcher m
;
106 m
.maOS
= getToken(rItem
, index
);
107 m
.maOSVersion
= getToken(rItem
, index
);
108 m
.maPlatformVendor
= getToken(rItem
, index
);
109 m
.maDevice
= getToken(rItem
, index
);
110 m
.maDriverVersion
= getToken(rItem
, index
);
118 bool match(const OUString
& rPattern
, const OUString
& rInput
)
120 if (rPattern
.isEmpty())
123 UErrorCode
nIcuError(U_ZERO_ERROR
);
124 icu::UnicodeString
sIcuPattern(reinterpret_cast<const UChar
*>(rPattern
.getStr()), rPattern
.getLength());
125 icu::UnicodeString
sIcuInput(reinterpret_cast<const UChar
*>(rInput
.getStr()), rInput
.getLength());
126 icu::RegexMatcher
aMatcher(sIcuPattern
, sIcuInput
, 0, nIcuError
);
128 return U_SUCCESS(nIcuError
) && aMatcher
.matches(nIcuError
) && U_SUCCESS(nIcuError
);
131 bool match(const OpenCLConfig::ImplMatcher
& rListEntry
, const OpenCLPlatformInfo
& rPlatform
, const OpenCLDeviceInfo
& rDevice
)
134 if (!rListEntry
.maOS
.isEmpty() && rListEntry
.maOS
!= "Windows")
137 if (!rListEntry
.maOS
.isEmpty() && rListEntry
.maOS
!= "Linux")
140 if (!rListEntry
.maOS
.isEmpty() && rListEntry
.maOS
!= "OS X")
144 // OS version check not yet implemented
146 if (!match(rListEntry
.maPlatformVendor
, rPlatform
.maVendor
))
149 if (!match(rListEntry
.maDevice
, rDevice
.maName
))
152 if (!match(rListEntry
.maDriverVersion
, rDevice
.maDriver
))
158 bool match(const OpenCLConfig::ImplMatcherSet
& rList
, const OpenCLPlatformInfo
& rPlatform
, const OpenCLDeviceInfo
& rDevice
, const char* sKindOfList
)
160 for (const auto& rListEntry
: rList
)
162 SAL_INFO("opencl", "Looking for match for platform=" << rPlatform
<< ", device=" << rDevice
<<
163 " in " << sKindOfList
<< " entry=" << rListEntry
);
165 if (match(rListEntry
, rPlatform
, rDevice
))
167 SAL_INFO("opencl", "Match!");
174 } // anonymous namespace
176 OpenCLConfig
OpenCLConfig::get()
180 result
.mbUseOpenCL
= officecfg::Office::Common::Misc::UseOpenCL::get();
182 result
.maDenyList
= StringSequenceToSetOfImplMatcher(officecfg::Office::Common::Misc::OpenCLDenyList::get());
183 result
.maAllowList
= StringSequenceToSetOfImplMatcher(officecfg::Office::Common::Misc::OpenCLAllowList::get());
188 void OpenCLConfig::set()
190 std::shared_ptr
<comphelper::ConfigurationChanges
> batch(comphelper::ConfigurationChanges::create());
192 officecfg::Office::Common::Misc::UseOpenCL::set(mbUseOpenCL
, batch
);
193 officecfg::Office::Common::Misc::OpenCLDenyList::set(SetOfImplMatcherToStringSequence(maDenyList
), batch
);
194 officecfg::Office::Common::Misc::OpenCLAllowList::set(SetOfImplMatcherToStringSequence(maAllowList
), batch
);
199 bool OpenCLConfig::checkImplementation(const OpenCLPlatformInfo
& rPlatform
, const OpenCLDeviceInfo
& rDevice
) const
201 // Check denylist of known bad OpenCL implementations
202 if (match(maDenyList
, rPlatform
, rDevice
, "denylist"))
204 SAL_INFO("opencl", "Rejecting");
208 // Check for allowlist of known good OpenCL implementations
209 if (match(maAllowList
, rPlatform
, rDevice
, "allowlist"))
211 SAL_INFO("opencl", "Approving");
216 SAL_INFO("opencl", "Fallback: rejecting platform=" << rPlatform
<< ", device=" << rDevice
);
220 std::ostream
& operator<<(std::ostream
& rStream
, const OpenCLConfig
& rConfig
)
223 "UseOpenCL=" << (rConfig
.mbUseOpenCL
? "YES" : "NO") << ","
224 "DenyList=" << rConfig
.maDenyList
<< ","
225 "AllowList=" << rConfig
.maAllowList
<<
230 std::ostream
& operator<<(std::ostream
& rStream
, const OpenCLConfig::ImplMatcher
& rImpl
)
233 "OS=" << rImpl
.maOS
<< ","
234 "OSVersion=" << rImpl
.maOSVersion
<< ","
235 "PlatformVendor=" << rImpl
.maPlatformVendor
<< ","
236 "Device=" << rImpl
.maDevice
<< ","
237 "DriverVersion=" << rImpl
.maDriverVersion
<<
243 std::ostream
& operator<<(std::ostream
& rStream
, const OpenCLConfig::ImplMatcherSet
& rSet
)
246 for (auto i
= rSet
.cbegin(); i
!= rSet
.cend(); ++i
)
248 if (i
!= rSet
.cbegin())
256 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */