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 <config_features.h>
11 :
12 : #include "formulagroup.hxx"
13 : #include "document.hxx"
14 : #include "formulacell.hxx"
15 : #include "tokenarray.hxx"
16 : #include "compiler.hxx"
17 : #include "interpre.hxx"
18 : #include "scmatrix.hxx"
19 : #include "globalnames.hxx"
20 :
21 : #include "formula/vectortoken.hxx"
22 : #include "rtl/bootstrap.hxx"
23 :
24 : #include <vector>
25 : #include <boost/scoped_array.hpp>
26 : #include <boost/unordered_map.hpp>
27 :
28 : #define USE_DUMMY_INTERPRETER 0
29 :
30 : #include <cstdio>
31 :
32 : #if HAVE_FEATURE_OPENCL
33 : #ifdef DISABLE_DYNLOADING
34 :
35 : extern "C" size_t getOpenCLPlatformCount(void);
36 : extern "C" void fillOpenCLInfo(sc::OpenclPlatformInfo*, size_t);
37 : extern "C" bool switchOpenClDevice(const OUString*, bool, bool);
38 : extern "C" sc::FormulaGroupInterpreter* createFormulaGroupOpenCLInterpreter();
39 : extern "C" void getOpenCLDeviceInfo(size_t*, size_t*);
40 :
41 : #endif
42 : #endif
43 :
44 : namespace sc {
45 :
46 0 : FormulaGroupEntry::FormulaGroupEntry( ScFormulaCell** pCells, size_t nRow, size_t nLength ) :
47 0 : mpCells(pCells), mnRow(nRow), mnLength(nLength), mbShared(true) {}
48 :
49 0 : FormulaGroupEntry::FormulaGroupEntry( ScFormulaCell* pCell, size_t nRow ) :
50 0 : mpCell(pCell), mnRow(nRow), mnLength(0), mbShared(false) {}
51 :
52 0 : size_t FormulaGroupContext::ColKey::Hash::operator ()( const FormulaGroupContext::ColKey& rKey ) const
53 : {
54 0 : return rKey.mnTab * MAXCOLCOUNT + rKey.mnCol;
55 : }
56 :
57 0 : FormulaGroupContext::ColKey::ColKey( SCTAB nTab, SCCOL nCol ) : mnTab(nTab), mnCol(nCol) {}
58 :
59 0 : bool FormulaGroupContext::ColKey::operator== ( const ColKey& r ) const
60 : {
61 0 : return mnTab == r.mnTab && mnCol == r.mnCol;
62 : }
63 :
64 0 : bool FormulaGroupContext::ColKey::operator!= ( const ColKey& r ) const
65 : {
66 0 : return !operator==(r);
67 : }
68 :
69 0 : FormulaGroupContext::ColArray::ColArray( NumArrayType* pNumArray, StrArrayType* pStrArray ) :
70 0 : mpNumArray(pNumArray), mpStrArray(pStrArray), mnSize(0)
71 : {
72 0 : if (mpNumArray)
73 0 : mnSize = mpNumArray->size();
74 0 : else if (mpStrArray)
75 0 : mnSize = mpStrArray->size();
76 0 : }
77 :
78 0 : FormulaGroupContext::ColArray* FormulaGroupContext::getCachedColArray( SCTAB nTab, SCCOL nCol, size_t nSize )
79 : {
80 0 : ColArraysType::iterator itColArray = maColArrays.find(ColKey(nTab, nCol));
81 0 : if (itColArray == maColArrays.end())
82 : // Not cached for this column.
83 0 : return NULL;
84 :
85 0 : ColArray& rCached = itColArray->second;
86 0 : if (nSize > rCached.mnSize)
87 : // Cached data array is not long enough for the requested range.
88 0 : return NULL;
89 :
90 0 : return &rCached;
91 : }
92 :
93 0 : FormulaGroupContext::ColArray* FormulaGroupContext::setCachedColArray(
94 : SCTAB nTab, SCCOL nCol, NumArrayType* pNumArray, StrArrayType* pStrArray )
95 : {
96 0 : ColArraysType::iterator it = maColArrays.find(ColKey(nTab, nCol));
97 0 : if (it == maColArrays.end())
98 : {
99 : std::pair<ColArraysType::iterator,bool> r =
100 : maColArrays.insert(
101 0 : ColArraysType::value_type(ColKey(nTab, nCol), ColArray(pNumArray, pStrArray)));
102 :
103 0 : if (!r.second)
104 : // Somehow the insertion failed.
105 0 : return NULL;
106 :
107 0 : return &r.first->second;
108 : }
109 :
110 : // Prior array exists for this column. Overwrite it.
111 0 : ColArray& rArray = it->second;
112 0 : rArray = ColArray(pNumArray, pStrArray);
113 0 : return &rArray;
114 : }
115 :
116 0 : void FormulaGroupContext::ensureStrArray( ColArray& rColArray, size_t nArrayLen )
117 : {
118 0 : if (rColArray.mpStrArray)
119 0 : return;
120 :
121 : maStrArrays.push_back(
122 0 : new sc::FormulaGroupContext::StrArrayType(nArrayLen, NULL));
123 0 : rColArray.mpStrArray = &maStrArrays.back();
124 : }
125 :
126 0 : void FormulaGroupContext::ensureNumArray( ColArray& rColArray, size_t nArrayLen )
127 : {
128 0 : if (rColArray.mpNumArray)
129 0 : return;
130 :
131 : double fNan;
132 0 : rtl::math::setNan(&fNan);
133 :
134 : maNumArrays.push_back(
135 0 : new sc::FormulaGroupContext::NumArrayType(nArrayLen, fNan));
136 0 : rColArray.mpNumArray = &maNumArrays.back();
137 : }
138 :
139 0 : FormulaGroupContext::FormulaGroupContext()
140 : {
141 0 : }
142 :
143 0 : FormulaGroupContext::~FormulaGroupContext()
144 : {
145 0 : }
146 :
147 : namespace {
148 :
149 : /**
150 : * Input double array consists of segments of NaN's and normal values.
151 : * Insert only the normal values into the matrix while skipping the NaN's.
152 : */
153 0 : void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, size_t nLen )
154 : {
155 0 : const double* pNum = pNums;
156 0 : const double* pNumEnd = pNum + nLen;
157 0 : const double* pNumHead = NULL;
158 0 : for (; pNum != pNumEnd; ++pNum)
159 : {
160 0 : if (!rtl::math::isNan(*pNum))
161 : {
162 0 : if (!pNumHead)
163 : // Store the first non-NaN position.
164 0 : pNumHead = pNum;
165 :
166 0 : continue;
167 : }
168 :
169 0 : if (pNumHead)
170 : {
171 : // Flush this non-NaN segment to the matrix.
172 0 : rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
173 0 : pNumHead = NULL;
174 : }
175 : }
176 :
177 0 : if (pNumHead)
178 : {
179 : // Flush last non-NaN segment to the matrix.
180 0 : rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
181 : }
182 0 : }
183 :
184 0 : void flushStrSegment(
185 : ScMatrix& rMat, size_t nCol, rtl_uString** pHead, rtl_uString** pCur, rtl_uString** pTop )
186 : {
187 0 : size_t nOffset = pHead - pTop;
188 0 : std::vector<svl::SharedString> aStrs;
189 0 : aStrs.reserve(pCur - pHead);
190 0 : for (; pHead != pCur; ++pHead)
191 0 : aStrs.push_back(svl::SharedString(*pHead, *pHead));
192 :
193 0 : rMat.PutString(&aStrs[0], aStrs.size(), nCol, nOffset);
194 0 : }
195 :
196 0 : void fillMatrix( ScMatrix& rMat, size_t nCol, rtl_uString** pStrs, size_t nLen )
197 : {
198 0 : rtl_uString** p = pStrs;
199 0 : rtl_uString** pEnd = p + nLen;
200 0 : rtl_uString** pHead = NULL;
201 0 : for (; p != pEnd; ++p)
202 : {
203 0 : if (*p)
204 : {
205 0 : if (!pHead)
206 : // Store the first non-empty string position.
207 0 : pHead = p;
208 :
209 0 : continue;
210 : }
211 :
212 0 : if (pHead)
213 : {
214 : // Flush this non-empty segment to the matrix.
215 0 : flushStrSegment(rMat, nCol, pHead, p, pStrs);
216 0 : pHead = NULL;
217 : }
218 : }
219 :
220 0 : if (pHead)
221 : {
222 : // Flush last non-empty segment to the matrix.
223 0 : flushStrSegment(rMat, nCol, pHead, p, pStrs);
224 : }
225 0 : }
226 :
227 0 : void fillMatrix( ScMatrix& rMat, size_t nCol, const double* pNums, rtl_uString** pStrs, size_t nLen )
228 : {
229 0 : if (!pStrs)
230 : {
231 0 : fillMatrix(rMat, nCol, pNums, nLen);
232 0 : return;
233 : }
234 :
235 0 : const double* pNum = pNums;
236 0 : const double* pNumHead = NULL;
237 0 : rtl_uString** pStr = pStrs;
238 0 : rtl_uString** pStrEnd = pStr + nLen;
239 0 : rtl_uString** pStrHead = NULL;
240 :
241 0 : for (; pStr != pStrEnd; ++pStr, ++pNum)
242 : {
243 0 : if (*pStr)
244 : {
245 : // String cell exists.
246 :
247 0 : if (pNumHead)
248 : {
249 : // Flush this numeric segment to the matrix.
250 0 : rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
251 0 : pNumHead = NULL;
252 : }
253 :
254 0 : if (!pStrHead)
255 : // Store the first non-empty string position.
256 0 : pStrHead = pStr;
257 :
258 0 : continue;
259 : }
260 :
261 : // No string cell. Check the numeric cell value.
262 :
263 0 : if (pStrHead)
264 : {
265 : // Flush this non-empty string segment to the matrix.
266 0 : flushStrSegment(rMat, nCol, pStrHead, pStr, pStrs);
267 0 : pStrHead = NULL;
268 : }
269 :
270 0 : if (!rtl::math::isNan(*pNum))
271 : {
272 : // Numeric cell exists.
273 0 : if (!pNumHead)
274 : // Store the first non-NaN position.
275 0 : pNumHead = pNum;
276 :
277 0 : continue;
278 : }
279 :
280 : // Empty cell. No action required.
281 : }
282 :
283 0 : if (pStrHead)
284 : {
285 : // Flush the last non-empty segment to the matrix.
286 0 : flushStrSegment(rMat, nCol, pStrHead, pStr, pStrs);
287 : }
288 0 : else if (pNumHead)
289 : {
290 : // Flush the last numeric segment to the matrix.
291 0 : rMat.PutDouble(pNumHead, pNum - pNumHead, nCol, pNumHead - pNums);
292 : }
293 : }
294 :
295 : }
296 :
297 0 : CompiledFormula::CompiledFormula() {}
298 :
299 0 : CompiledFormula::~CompiledFormula() {}
300 :
301 0 : FormulaGroupInterpreterSoftware::FormulaGroupInterpreterSoftware() : FormulaGroupInterpreter()
302 : {
303 0 : }
304 :
305 0 : ScMatrixRef FormulaGroupInterpreterSoftware::inverseMatrix(const ScMatrix& /*rMat*/)
306 : {
307 0 : return ScMatrixRef();
308 : }
309 :
310 0 : CompiledFormula* FormulaGroupInterpreterSoftware::createCompiledFormula(ScDocument& /* rDoc */,
311 : const ScAddress& /* rTopPos */,
312 : ScFormulaCellGroup& /* rGroup */,
313 : ScTokenArray& /* rCode */)
314 : {
315 0 : return NULL;
316 : }
317 :
318 0 : bool FormulaGroupInterpreterSoftware::interpret(ScDocument& rDoc, const ScAddress& rTopPos,
319 : ScFormulaCellGroupRef& xGroup,
320 : ScTokenArray& rCode)
321 : {
322 : typedef boost::unordered_map<const formula::FormulaToken*, formula::FormulaTokenRef> CachedTokensType;
323 :
324 : // Decompose the group into individual cells and calculate them individually.
325 :
326 : // The caller must ensure that the top position is the start position of
327 : // the group.
328 :
329 0 : ScAddress aTmpPos = rTopPos;
330 0 : std::vector<formula::FormulaTokenRef> aResults;
331 0 : aResults.reserve(xGroup->mnLength);
332 0 : CachedTokensType aCachedTokens;
333 :
334 : double fNan;
335 0 : rtl::math::setNan(&fNan);
336 :
337 0 : for (SCROW i = 0; i < xGroup->mnLength; ++i, aTmpPos.IncRow())
338 : {
339 0 : ScTokenArray aCode2;
340 0 : for (const formula::FormulaToken* p = rCode.First(); p; p = rCode.Next())
341 : {
342 0 : CachedTokensType::iterator it = aCachedTokens.find(p);
343 0 : if (it != aCachedTokens.end())
344 : {
345 : // This token is cached. Use the cached one.
346 0 : aCode2.AddToken(*it->second);
347 0 : continue;
348 : }
349 :
350 0 : switch (p->GetType())
351 : {
352 : case formula::svSingleVectorRef:
353 : {
354 0 : const formula::SingleVectorRefToken* p2 = static_cast<const formula::SingleVectorRefToken*>(p);
355 0 : const formula::VectorRefArray& rArray = p2->GetArray();
356 :
357 0 : rtl_uString* pStr = NULL;
358 0 : double fVal = fNan;
359 0 : if (static_cast<size_t>(i) < p2->GetArrayLength())
360 : {
361 0 : if (rArray.mpStringArray)
362 : // See if the cell is of string type.
363 0 : pStr = rArray.mpStringArray[i];
364 :
365 0 : if (!pStr && rArray.mpNumericArray)
366 0 : fVal = rArray.mpNumericArray[i];
367 : }
368 :
369 0 : if (pStr)
370 : // This is a string cell.
371 0 : aCode2.AddString(OUString(pStr));
372 0 : else if (rtl::math::isNan(fVal))
373 : // Value of NaN represents an empty cell.
374 0 : aCode2.AddToken(ScEmptyCellToken(false, false));
375 : else
376 : // Numeric cell.
377 0 : aCode2.AddDouble(fVal);
378 : }
379 0 : break;
380 : case formula::svDoubleVectorRef:
381 : {
382 0 : const formula::DoubleVectorRefToken* p2 = static_cast<const formula::DoubleVectorRefToken*>(p);
383 0 : const std::vector<formula::VectorRefArray>& rArrays = p2->GetArrays();
384 0 : size_t nColSize = rArrays.size();
385 0 : size_t nRowStart = p2->IsStartFixed() ? 0 : i;
386 0 : size_t nRowEnd = p2->GetRefRowSize() - 1;
387 0 : if (!p2->IsEndFixed())
388 0 : nRowEnd += i;
389 0 : size_t nRowSize = nRowEnd - nRowStart + 1;
390 0 : ScMatrixRef pMat(new ScMatrix(nColSize, nRowSize));
391 :
392 0 : size_t nDataRowEnd = p2->GetArrayLength() - 1;
393 0 : if (nRowStart > nDataRowEnd)
394 : // Referenced rows are all empty.
395 0 : nRowSize = 0;
396 0 : else if (nRowEnd > nDataRowEnd)
397 : // Data array is shorter than the row size of the reference. Truncate it to the data.
398 0 : nRowSize -= nRowEnd - nDataRowEnd;
399 :
400 0 : for (size_t nCol = 0; nCol < nColSize; ++nCol)
401 : {
402 0 : const formula::VectorRefArray& rArray = rArrays[nCol];
403 0 : if (rArray.mpStringArray)
404 : {
405 0 : if (rArray.mpNumericArray)
406 : {
407 : // Mixture of string and numeric values.
408 0 : const double* pNums = rArray.mpNumericArray;
409 0 : pNums += nRowStart;
410 0 : rtl_uString** pStrs = rArray.mpStringArray;
411 0 : pStrs += nRowStart;
412 0 : fillMatrix(*pMat, nCol, pNums, pStrs, nRowSize);
413 : }
414 : else
415 : {
416 : // String cells only.
417 0 : rtl_uString** pStrs = rArray.mpStringArray;
418 0 : pStrs += nRowStart;
419 0 : fillMatrix(*pMat, nCol, pStrs, nRowSize);
420 : }
421 : }
422 0 : else if (rArray.mpNumericArray)
423 : {
424 : // Numeric cells only.
425 0 : const double* pNums = rArray.mpNumericArray;
426 0 : pNums += nRowStart;
427 0 : fillMatrix(*pMat, nCol, pNums, nRowSize);
428 : }
429 : }
430 :
431 0 : if (p2->IsStartFixed() && p2->IsEndFixed())
432 : {
433 : // Cached the converted token for absolute range referene.
434 : ScComplexRefData aRef;
435 0 : ScRange aRefRange = rTopPos;
436 0 : aRefRange.aEnd.SetRow(rTopPos.Row() + nRowEnd);
437 0 : aRef.InitRange(aRefRange);
438 0 : formula::FormulaTokenRef xTok(new ScMatrixRangeToken(pMat, aRef));
439 0 : aCachedTokens.insert(CachedTokensType::value_type(p, xTok));
440 0 : aCode2.AddToken(*xTok);
441 : }
442 : else
443 : {
444 0 : ScMatrixToken aTok(pMat);
445 0 : aCode2.AddToken(aTok);
446 0 : }
447 : }
448 0 : break;
449 : default:
450 0 : aCode2.AddToken(*p);
451 : }
452 : }
453 :
454 0 : ScFormulaCell* pDest = rDoc.GetFormulaCell(aTmpPos);
455 0 : if (!pDest)
456 0 : return false;
457 :
458 0 : ScCompiler aComp(&rDoc, aTmpPos, aCode2);
459 0 : aComp.CompileTokenArray();
460 0 : ScInterpreter aInterpreter(pDest, &rDoc, aTmpPos, aCode2);
461 0 : aInterpreter.Interpret();
462 0 : aResults.push_back(aInterpreter.GetResultToken());
463 0 : } // for loop end (xGroup->mnLength)
464 :
465 0 : if (!aResults.empty())
466 0 : rDoc.SetFormulaResults(rTopPos, &aResults[0], aResults.size());
467 :
468 0 : return true;
469 : }
470 :
471 : #if USE_DUMMY_INTERPRETER
472 : class FormulaGroupInterpreterDummy : public FormulaGroupInterpreter
473 : {
474 : enum Mode {
475 : WRITE_OUTPUT = 0
476 : };
477 : Mode meMode;
478 : public:
479 : FormulaGroupInterpreterDummy()
480 : {
481 : const char *pValue = getenv("FORMULA_GROUP_DUMMY");
482 : meMode = static_cast<Mode>(OString(pValue, strlen(pValue)).toInt32());
483 : fprintf(stderr, "Using Dummy Formula Group interpreter mode %d\n", (int)meMode);
484 : }
485 :
486 : virtual ScMatrixRef inverseMatrix(const ScMatrix& /*rMat*/)
487 : {
488 : return ScMatrixRef();
489 : }
490 :
491 : virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos,
492 : const ScFormulaCellGroupRef& xGroup,
493 : ScTokenArray& rCode)
494 : {
495 : (void)rCode;
496 :
497 : // Write simple data back into the sheet
498 : if (meMode == WRITE_OUTPUT)
499 : {
500 : boost::scoped_array<double> pDoubles(new double[xGroup->mnLength]);
501 : for (sal_Int32 i = 0; i < xGroup->mnLength; i++)
502 : pDoubles[i] = 42.0 + i;
503 : rDoc.SetFormulaResults(rTopPos, pDoubles.get(), xGroup->mnLength);
504 : }
505 : return true;
506 : }
507 : };
508 :
509 : #endif
510 :
511 : #ifndef DISABLE_DYNLOADING
512 :
513 : class FormulaGroupInterpreterOpenCLMissing : public FormulaGroupInterpreter
514 : {
515 : public:
516 0 : FormulaGroupInterpreterOpenCLMissing() : FormulaGroupInterpreter() {}
517 0 : virtual ~FormulaGroupInterpreterOpenCLMissing() {}
518 0 : virtual ScMatrixRef inverseMatrix(const ScMatrix&) SAL_OVERRIDE { return ScMatrixRef(); }
519 0 : virtual CompiledFormula* createCompiledFormula(ScDocument&, const ScAddress&, ScFormulaCellGroup&, ScTokenArray&) SAL_OVERRIDE { return NULL; }
520 0 : virtual bool interpret(ScDocument&, const ScAddress&, ScFormulaCellGroupRef&, ScTokenArray&) SAL_OVERRIDE { return false; }
521 : };
522 :
523 0 : static void SAL_CALL thisModule() {}
524 :
525 : typedef FormulaGroupInterpreter* (*__createFormulaGroupOpenCLInterpreter)(void);
526 : typedef size_t (*__getOpenCLPlatformCount)(void);
527 : typedef void (*__fillOpenCLInfo)(OpenclPlatformInfo*, size_t);
528 : typedef bool (*__switchOpenClDevice)(const OUString*, bool, bool);
529 : typedef void (*__getOpenCLDeviceInfo)(size_t*, size_t*);
530 :
531 : #endif
532 :
533 : FormulaGroupInterpreter *FormulaGroupInterpreter::msInstance = NULL;
534 :
535 : #ifndef DISABLE_DYNLOADING
536 :
537 0 : osl::Module* getOpenCLModule()
538 : {
539 0 : static osl::Module aModule;
540 0 : if (aModule.is())
541 : // Already loaded.
542 0 : return &aModule;
543 :
544 0 : OUString aLibName(SVLIBRARY("scopencl"));
545 0 : bool bLoaded = aModule.loadRelative(&thisModule, aLibName);
546 0 : if (!bLoaded)
547 0 : bLoaded = aModule.load(aLibName);
548 :
549 0 : return bLoaded ? &aModule : NULL;
550 : }
551 :
552 : #endif
553 :
554 : /// load and/or configure the correct formula group interpreter
555 0 : FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
556 : {
557 : #if USE_DUMMY_INTERPRETER
558 : if (getenv("FORMULA_GROUP_DUMMY"))
559 : {
560 : delete msInstance;
561 : return msInstance = new sc::FormulaGroupInterpreterDummy();
562 : }
563 : #endif
564 :
565 0 : if ( !msInstance )
566 : {
567 0 : const ScCalcConfig& rConfig = ScInterpreter::GetGlobalConfig();
568 0 : if (rConfig.mbOpenCLEnabled)
569 0 : switchOpenCLDevice(rConfig.maOpenCLDevice, rConfig.mbOpenCLAutoSelect, false);
570 :
571 0 : if ( !msInstance ) // software fallback
572 : {
573 0 : fprintf(stderr, "Create S/W interp\n");
574 0 : msInstance = new sc::FormulaGroupInterpreterSoftware();
575 : }
576 : }
577 :
578 0 : return msInstance;
579 : }
580 :
581 0 : void FormulaGroupInterpreter::fillOpenCLInfo(std::vector<OpenclPlatformInfo>& rPlatforms)
582 : {
583 : #if !HAVE_FEATURE_OPENCL
584 : (void) rPlatforms;
585 : #else
586 : #ifndef DISABLE_DYNLOADING
587 0 : osl::Module* pModule = getOpenCLModule();
588 0 : if (!pModule)
589 0 : return;
590 :
591 0 : oslGenericFunction fn = pModule->getFunctionSymbol("getOpenCLPlatformCount");
592 0 : if (!fn)
593 0 : return;
594 :
595 0 : size_t nPlatforms = reinterpret_cast<__getOpenCLPlatformCount>(fn)();
596 0 : if (!nPlatforms)
597 0 : return;
598 :
599 0 : fn = pModule->getFunctionSymbol("fillOpenCLInfo");
600 0 : if (!fn)
601 0 : return;
602 :
603 0 : std::vector<OpenclPlatformInfo> aPlatforms(nPlatforms);
604 0 : reinterpret_cast<__fillOpenCLInfo>(fn)(&aPlatforms[0], aPlatforms.size());
605 0 : rPlatforms.swap(aPlatforms);
606 : #else
607 : size_t nPlatforms = getOpenCLPlatformCount();
608 : if (!nPlatforms)
609 : return;
610 :
611 : std::vector<OpenclPlatformInfo> aPlatforms(nPlatforms);
612 : ::fillOpenCLInfo(&aPlatforms[0], aPlatforms.size());
613 : rPlatforms.swap(aPlatforms);
614 : #endif
615 : #endif
616 : }
617 :
618 0 : bool FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool bAutoSelect, bool bForceEvaluation)
619 : {
620 0 : bool bOpenCLEnabled = ScInterpreter::GetGlobalConfig().mbOpenCLEnabled;
621 0 : if (!bOpenCLEnabled || rDeviceId == OPENCL_SOFTWARE_DEVICE_CONFIG_NAME)
622 : {
623 0 : if(msInstance)
624 : {
625 : // if we already have a software interpreter don't delete it
626 0 : if(dynamic_cast<sc::FormulaGroupInterpreterSoftware*>(msInstance))
627 0 : return true;
628 :
629 0 : delete msInstance;
630 : }
631 :
632 0 : msInstance = new sc::FormulaGroupInterpreterSoftware();
633 0 : return true;
634 : }
635 : #if HAVE_FEATURE_OPENCL
636 : #ifndef DISABLE_DYNLOADING
637 0 : osl::Module* pModule = getOpenCLModule();
638 0 : if (!pModule)
639 0 : return false;
640 :
641 0 : oslGenericFunction fn = pModule->getFunctionSymbol("switchOpenClDevice");
642 0 : if (!fn)
643 0 : return false;
644 :
645 0 : bool bSuccess = reinterpret_cast<__switchOpenClDevice>(fn)(&rDeviceId, bAutoSelect, bForceEvaluation);
646 0 : if(!bSuccess)
647 0 : return false;
648 : #else
649 : bool bSuccess = switchOpenClDevice(&rDeviceId, bAutoSelect, bForceEvaluation);
650 : if(!bSuccess)
651 : return false;
652 : #endif
653 : #else
654 : (void) bAutoSelect;
655 : #endif
656 :
657 0 : delete msInstance;
658 0 : msInstance = NULL;
659 :
660 : #if HAVE_FEATURE_OPENCL
661 0 : if ( ScInterpreter::GetGlobalConfig().mbOpenCLEnabled )
662 : {
663 : #ifdef DISABLE_DYNLOADING
664 : msInstance = createFormulaGroupOpenCLInterpreter();
665 : return msInstance != NULL;
666 : #else
667 : // Dynamically load scopencl shared object, and instantiate the opencl interpreter.
668 0 : bSuccess = false;
669 0 : fn = pModule->getFunctionSymbol("createFormulaGroupOpenCLInterpreter");
670 0 : if (fn)
671 : {
672 0 : msInstance = reinterpret_cast<__createFormulaGroupOpenCLInterpreter>(fn)();
673 0 : bSuccess = msInstance != NULL;
674 : }
675 :
676 0 : if (!msInstance)
677 0 : msInstance = new sc::FormulaGroupInterpreterOpenCLMissing();
678 :
679 0 : return bSuccess;
680 : #endif
681 : }
682 : #else
683 : (void) bForceEvaluation;
684 : #endif
685 0 : return false;
686 : }
687 :
688 0 : void FormulaGroupInterpreter::getOpenCLDeviceInfo(sal_Int32& rDeviceId, sal_Int32& rPlatformId)
689 : {
690 0 : rDeviceId = -1;
691 0 : rPlatformId = -1;
692 0 : bool bOpenCLEnabled = ScInterpreter::GetGlobalConfig().mbOpenCLEnabled;
693 0 : if(!bOpenCLEnabled)
694 0 : return;
695 :
696 : #if HAVE_FEATURE_OPENCL
697 :
698 0 : size_t aDeviceId = -1;
699 0 : size_t aPlatformId = -1;
700 :
701 : #ifndef DISABLE_DYNLOADING
702 0 : osl::Module* pModule = getOpenCLModule();
703 0 : if (!pModule)
704 0 : return;
705 :
706 0 : oslGenericFunction fn = pModule->getFunctionSymbol("getOpenCLDeviceInfo");
707 0 : if (!fn)
708 0 : return;
709 :
710 0 : reinterpret_cast<__getOpenCLDeviceInfo>(fn)(&aDeviceId, &aPlatformId);
711 : #else
712 : getOpenCLDeviceInfo(&aDeviceId, &aPlatformId);
713 : #endif
714 0 : rDeviceId = aDeviceId;
715 0 : rPlatformId = aPlatformId;
716 : #endif
717 : }
718 :
719 0 : void FormulaGroupInterpreter::enableOpenCL(bool bEnable)
720 : {
721 0 : ScCalcConfig aConfig = ScInterpreter::GetGlobalConfig();
722 0 : aConfig.mbOpenCLEnabled = bEnable;
723 0 : ScInterpreter::SetGlobalConfig(aConfig);
724 0 : }
725 :
726 : } // namespace sc
727 :
728 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|