Line data Source code
1 : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : /*
3 : * This file is part of the LibreOffice project.
4 : *
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/.
8 : */
9 :
10 : #include <boost/shared_ptr.hpp>
11 : #include <unicode/regex.h>
12 :
13 : #include <comphelper/configuration.hxx>
14 : #include <officecfg/Office/Common.hxx>
15 : #include <opencl/openclconfig.hxx>
16 : #include <opencl/platforminfo.hxx>
17 : #include <rtl/ustring.hxx>
18 : #include <sal/log.hxx>
19 : #include <sal/types.h>
20 :
21 0 : OpenCLConfig::OpenCLConfig() :
22 0 : mbUseOpenCL(true)
23 : {
24 : // This entry we have had for some time (when blacklisting was
25 : // done elsewhere in the code), so presumably there is a known
26 : // good reason for it.
27 0 : maBlackList.insert(ImplMatcher("Windows", "", "Intel\\(R\\) Corporation", "", "9\\.17\\.10\\.2884"));
28 :
29 : // This is what I have tested on Linux and it works for our unit tests.
30 0 : maWhiteList.insert(ImplMatcher("Linux", "", "Advanced Micro Devices, Inc\\.", "", "1445\\.5 \\(sse2,avx\\)"));
31 :
32 : // For now, assume that AMD, Intel and NVIDIA drivers are good
33 0 : maWhiteList.insert(ImplMatcher("", "", "Advanced Micro Devices, Inc\\.", "", ""));
34 0 : maWhiteList.insert(ImplMatcher("", "", "Intel\\(R\\) Corporation", "", ""));
35 0 : maWhiteList.insert(ImplMatcher("", "", "NVIDIA Corporation", "", ""));
36 0 : }
37 :
38 0 : bool OpenCLConfig::operator== (const OpenCLConfig& r) const
39 : {
40 0 : return (mbUseOpenCL == r.mbUseOpenCL &&
41 0 : maBlackList == r.maBlackList &&
42 0 : maWhiteList == r.maWhiteList &&
43 0 : true);
44 : }
45 :
46 0 : bool OpenCLConfig::operator!= (const OpenCLConfig& r) const
47 : {
48 0 : return !operator== (r);
49 : }
50 :
51 : namespace {
52 :
53 0 : css::uno::Sequence<OUString> SetOfImplMatcherToStringSequence(const OpenCLConfig::ImplMatcherSet& rSet)
54 : {
55 0 : css::uno::Sequence<OUString> result(rSet.size());
56 :
57 0 : size_t n(0);
58 0 : for (auto i = rSet.cbegin(); i != rSet.cend(); ++i)
59 : {
60 0 : result[n++] =
61 0 : (*i).maOS.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
62 0 : (*i).maOSVersion.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
63 0 : (*i).maPlatformVendor.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
64 0 : (*i).maDevice.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B") + "/" +
65 0 : (*i).maDriverVersion.replaceAll("%", "%25").replaceAll("/", "%2F").replaceAll(";", "%3B");
66 : }
67 :
68 0 : return result;
69 : }
70 :
71 0 : OUString getToken(const OUString& string, sal_Int32& index)
72 : {
73 0 : OUString token(string.getToken(0, '/', index));
74 0 : OUString result;
75 0 : sal_Int32 i(0);
76 : sal_Int32 p;
77 0 : while ((p = token.indexOf('%', i)) >= 0)
78 : {
79 0 : if (p > i)
80 0 : result += token.copy(i, p - i);
81 0 : if (p < token.getLength() - 2)
82 : {
83 0 : result += OUString(static_cast<sal_Unicode>(token.copy(p+1, 2).toInt32(16)));
84 0 : i = p + 3;
85 : }
86 : else
87 : {
88 0 : i = token.getLength();
89 : }
90 : }
91 0 : result += token.copy(i);
92 :
93 0 : return result;
94 : }
95 :
96 0 : OpenCLConfig::ImplMatcherSet StringSequenceToSetOfImplMatcher(const css::uno::Sequence<OUString>& rSequence)
97 : {
98 0 : OpenCLConfig::ImplMatcherSet result;
99 :
100 0 : for (auto i = rSequence.begin(); i != rSequence.end(); ++i)
101 : {
102 0 : OpenCLConfig::ImplMatcher m;
103 0 : sal_Int32 index(0);
104 0 : m.maOS = getToken(*i, index);
105 0 : m.maOSVersion = getToken(*i, index);
106 0 : m.maPlatformVendor = getToken(*i, index);
107 0 : m.maDevice = getToken(*i, index);
108 0 : m.maDriverVersion = getToken(*i, index);
109 :
110 0 : result.insert(m);
111 0 : }
112 :
113 0 : return result;
114 : }
115 :
116 0 : bool match(const OUString& rPattern, const OUString& rInput)
117 : {
118 0 : if (rPattern.isEmpty())
119 0 : return true;
120 :
121 0 : UErrorCode nIcuError(U_ZERO_ERROR);
122 0 : icu::UnicodeString sIcuPattern(reinterpret_cast<const UChar*>(rPattern.getStr()), rPattern.getLength());
123 0 : icu::UnicodeString sIcuInput(reinterpret_cast<const UChar*>(rInput.getStr()), rInput.getLength());
124 0 : RegexMatcher aMatcher(sIcuPattern, sIcuInput, 0, nIcuError);
125 :
126 0 : if (U_SUCCESS(nIcuError) && aMatcher.matches(nIcuError) && U_SUCCESS(nIcuError))
127 0 : return true;
128 :
129 0 : return false;
130 : }
131 :
132 0 : bool match(const OpenCLConfig::ImplMatcher& rListEntry, const OpenCLPlatformInfo& rPlatform, const OpenCLDeviceInfo& rDevice)
133 : {
134 : #if defined WNT
135 : if (!rListEntry.maOS.isEmpty() && rListEntry.maOS != "Windows")
136 : return false;
137 : #elif defined LINUX
138 0 : if (!rListEntry.maOS.isEmpty() && rListEntry.maOS != "Linux")
139 0 : return false;
140 : #elif defined MACOSX
141 : if (!rListEntry.maOS.isEmpty() && rListEntry.maOS != "OS X")
142 : return false;
143 : #endif
144 :
145 : // OS version check not yet implemented
146 :
147 0 : if (!match(rListEntry.maPlatformVendor, rPlatform.maVendor))
148 0 : return false;
149 :
150 0 : if (!match(rListEntry.maDevice, rDevice.maName))
151 0 : return false;
152 :
153 0 : if (!match(rListEntry.maDriverVersion, rDevice.maDriver))
154 0 : return false;
155 :
156 0 : return true;
157 : }
158 :
159 0 : bool match(const OpenCLConfig::ImplMatcherSet& rList, const OpenCLPlatformInfo& rPlatform, const OpenCLDeviceInfo& rDevice, const char* sKindOfList)
160 : {
161 0 : for (auto i = rList.cbegin(); i != rList.end(); ++i)
162 : {
163 : SAL_INFO("opencl", "Looking for match for platform=" << rPlatform << ", device=" << rDevice <<
164 : " in " << sKindOfList << " entry=" << *i);
165 :
166 0 : if (match(*i, rPlatform, rDevice))
167 : {
168 : SAL_INFO("opencl", "Match!");
169 0 : return true;
170 : }
171 : }
172 0 : return false;
173 : }
174 :
175 : } // anonymous namespace
176 :
177 0 : OpenCLConfig OpenCLConfig::get()
178 : {
179 0 : OpenCLConfig result;
180 :
181 0 : result.mbUseOpenCL = officecfg::Office::Common::Misc::UseOpenCL::get();
182 :
183 0 : result.maBlackList = StringSequenceToSetOfImplMatcher(officecfg::Office::Common::Misc::OpenCLBlackList::get());
184 0 : result.maWhiteList = StringSequenceToSetOfImplMatcher(officecfg::Office::Common::Misc::OpenCLWhiteList::get());
185 :
186 0 : return result;
187 : }
188 :
189 0 : void OpenCLConfig::set()
190 : {
191 0 : std::shared_ptr<comphelper::ConfigurationChanges> batch(comphelper::ConfigurationChanges::create());
192 :
193 0 : officecfg::Office::Common::Misc::UseOpenCL::set(mbUseOpenCL, batch);
194 0 : officecfg::Office::Common::Misc::OpenCLBlackList::set(SetOfImplMatcherToStringSequence(maBlackList), batch);
195 0 : officecfg::Office::Common::Misc::OpenCLWhiteList::set(SetOfImplMatcherToStringSequence(maWhiteList), batch);
196 :
197 0 : batch->commit();
198 0 : }
199 :
200 0 : bool OpenCLConfig::checkImplementation(const OpenCLPlatformInfo& rPlatform, const OpenCLDeviceInfo& rDevice) const
201 : {
202 : // Check blacklist of known bad OpenCL implementations
203 0 : if (match(maBlackList, rPlatform, rDevice, "blacklist"))
204 : {
205 : SAL_INFO("opencl", "Rejecting");
206 0 : return true;
207 : }
208 :
209 : // Check for whitelist of known good OpenCL implementations
210 0 : if (match(maWhiteList, rPlatform, rDevice, "whitelist"))
211 : {
212 : SAL_INFO("opencl", "Approving");
213 0 : return false;
214 : }
215 :
216 : // Fallback: reject
217 : SAL_INFO("opencl", "Fallback: rejecting platform=" << rPlatform << ", device=" << rDevice);
218 0 : return true;
219 : }
220 :
221 0 : std::ostream& operator<<(std::ostream& rStream, const OpenCLConfig& rConfig)
222 : {
223 : rStream << "{"
224 0 : "UseOpenCL=" << (rConfig.mbUseOpenCL ? "YES" : "NO") << ","
225 0 : "BlackList=" << rConfig.maBlackList << ","
226 0 : "WhiteList=" << rConfig.maWhiteList <<
227 0 : "}";
228 0 : return rStream;
229 : }
230 :
231 0 : std::ostream& operator<<(std::ostream& rStream, const OpenCLConfig::ImplMatcher& rImpl)
232 : {
233 : rStream << "{"
234 0 : "OS=" << rImpl.maOS << ","
235 0 : "OSVersion=" << rImpl.maOSVersion << ","
236 0 : "PlatformVendor=" << rImpl.maPlatformVendor << ","
237 0 : "Device=" << rImpl.maDevice << ","
238 0 : "DriverVersion=" << rImpl.maDriverVersion <<
239 0 : "}";
240 :
241 0 : return rStream;
242 : }
243 :
244 0 : std::ostream& operator<<(std::ostream& rStream, const OpenCLConfig::ImplMatcherSet& rSet)
245 : {
246 0 : rStream << "{";
247 0 : for (auto i = rSet.cbegin(); i != rSet.cend(); ++i)
248 : {
249 0 : if (i != rSet.cbegin())
250 0 : rStream << ",";
251 0 : rStream << *i;
252 : }
253 0 : rStream << "}";
254 0 : return rStream;
255 : }
256 :
257 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|