[Libreoffice-commits] core.git: Branch 'feature/calc-pluggable-opencl' - 3 commits - officecfg/registry sc/inc sc/source

Markus Mohrhard markus.mohrhard at googlemail.com
Mon Sep 16 05:02:07 PDT 2013


 officecfg/registry/schema/org/openoffice/Office/Calc.xcs |    7 
 sc/inc/calcconfig.hxx                                    |    3 
 sc/inc/formulagroup.hxx                                  |    1 
 sc/source/core/opencl/formulagroupcl.cxx                 |   16 -
 sc/source/core/opencl/openclwrapper.cxx                  |  131 +++++++++++++--
 sc/source/core/opencl/openclwrapper.hxx                  |   14 +
 sc/source/core/tool/calcconfig.cxx                       |    3 
 sc/source/core/tool/formulagroup.cxx                     |   90 ++++++----
 sc/source/core/tool/formulaopt.cxx                       |   24 ++
 sc/source/ui/app/scmod.cxx                               |    3 
 sc/source/ui/optdlg/calcoptionsdlg.cxx                   |    1 
 11 files changed, 231 insertions(+), 62 deletions(-)

New commits:
commit 9f1002adea6c88d6553cf9ef4fc382e92b095200
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Mon Sep 16 13:52:51 2013 +0200

    store the opencl device id and propagate it from the ui to opencl code
    
    Change-Id: I47ed4add16c804e598feebd84ae823a45d2f8dd9

diff --git a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
index 5950597..25fe724 100644
--- a/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
+++ b/officecfg/registry/schema/org/openoffice/Office/Calc.xcs
@@ -1344,6 +1344,13 @@
           </info>
           <value>true</value>
         </prop>
+        <prop oor:name="OpenCLAutoDevice" oor:type="xs:string" oor:nillable="false">
+          <!-- UIHints: Tools - Options  Spreadsheet  Formula -->
+          <info>
+            <desc>The Device ID of the OpenCL device selected if OpenCLAutoSelect is false</desc>
+          </info>
+          <value></value>
+        </prop>
       </group>
       <group oor:name="Syntax">
         <info>
diff --git a/sc/inc/calcconfig.hxx b/sc/inc/calcconfig.hxx
index 1477874..94a72cc 100644
--- a/sc/inc/calcconfig.hxx
+++ b/sc/inc/calcconfig.hxx
@@ -13,6 +13,8 @@
 #include "scdllapi.h"
 #include "formula/grammar.hxx"
 
+#include "rtl/ustring.hxx"
+
 // have to match the registry values
 enum ScRecalcOptions
 {
@@ -30,6 +32,7 @@ struct SC_DLLPUBLIC ScCalcConfig
     bool mbEmptyStringAsZero:1;
     bool mbOpenCLEnabled:1;
     bool mbOpenCLAutoSelect:1;
+    OUString maOpenCLDevice;
 
     ScCalcConfig();
 
diff --git a/sc/source/core/opencl/openclwrapper.cxx b/sc/source/core/opencl/openclwrapper.cxx
index 72d1ab3..ea2d754 100644
--- a/sc/source/core/opencl/openclwrapper.cxx
+++ b/sc/source/core/opencl/openclwrapper.cxx
@@ -2773,6 +2773,20 @@ namespace {
 
 cl_device_id findDeviceIdByDeviceString(const OUString& rString, const std::vector<OpenclPlatformInfo>& rPlatforms)
 {
+    std::vector<OpenclPlatformInfo>::const_iterator it = rPlatforms.begin(), itEnd = rPlatforms.end();
+    for(; it != itEnd; ++it)
+    {
+        std::vector<OpenclDeviceInfo>::const_iterator itr = it->maDevices.begin(), itrEnd = it->maDevices.end();
+        for(; itr != itrEnd; ++itr)
+        {
+            OUString aDeviceId = it->maVendor + " " + itr->maName;
+            if(rString == aDeviceId)
+            {
+                return static_cast<cl_device_id>(itr->device);
+            }
+        }
+    }
+
     return NULL;
 }
 
@@ -2851,6 +2865,10 @@ bool switchOpenclDevice(const OUString* pDevice, bool bAutoSelect)
     env.mpOclDevsID = pDeviceId;
     env.mpOclCmdQueue = command_queue;
     OpenclDevice::initOpenclAttr(&env);
+
+    // why do we need this at all?
+    OpenclDevice::gpuEnv.mpArryDevsID = (cl_device_id*) malloc( 1 );
+    OpenclDevice::gpuEnv.mpArryDevsID[0] = pDeviceId;
     return !OpenclDevice::initOpenclRunEnv(0);
 }
 
diff --git a/sc/source/core/tool/calcconfig.cxx b/sc/source/core/tool/calcconfig.cxx
index 1278402..f910bb1 100644
--- a/sc/source/core/tool/calcconfig.cxx
+++ b/sc/source/core/tool/calcconfig.cxx
@@ -27,7 +27,8 @@ bool ScCalcConfig::operator== (const ScCalcConfig& r) const
     return meStringRefAddressSyntax == r.meStringRefAddressSyntax &&
            mbEmptyStringAsZero == r.mbEmptyStringAsZero &&
            mbOpenCLEnabled == r.mbOpenCLEnabled &&
-           mbOpenCLAutoSelect == r.mbOpenCLAutoSelect;
+           mbOpenCLAutoSelect == r.mbOpenCLAutoSelect &&
+           maOpenCLDevice == r.maOpenCLDevice;
 }
 
 bool ScCalcConfig::operator!= (const ScCalcConfig& r) const
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 9b3ab9a..dd765a8 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -427,7 +427,7 @@ void FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool
     if (!pModule)
         return;
 
-    oslGenericFunction fn = pModule->getFunctionSymbol("switchOpenclDevice");
+    oslGenericFunction fn = pModule->getFunctionSymbol("switchOpenClDevice");
     if (!fn)
         return;
 
diff --git a/sc/source/core/tool/formulaopt.cxx b/sc/source/core/tool/formulaopt.cxx
index bf6b385..4c926e9 100644
--- a/sc/source/core/tool/formulaopt.cxx
+++ b/sc/source/core/tool/formulaopt.cxx
@@ -15,6 +15,7 @@
 #include "formulaopt.hxx"
 #include "miscuno.hxx"
 #include "global.hxx"
+#include "formulagroup.hxx"
 
 using namespace utl;
 using namespace com::sun::star::uno;
@@ -197,7 +198,8 @@ SfxPoolItem* ScTpFormulaItem::Clone( SfxItemPool * ) const
 #define SCFORMULAOPT_ODF_RECALC           8
 #define SCFORMULAOPT_OPENCL_ENABLED       9
 #define SCFORMULAOPT_OPENCL_AUTOSELECT   10
-#define SCFORMULAOPT_COUNT               11
+#define SCFORMULAOPT_OPENCL_DEVICE       11
+#define SCFORMULAOPT_COUNT               12
 
 Sequence<OUString> ScFormulaCfg::GetPropertyNames()
 {
@@ -213,7 +215,8 @@ Sequence<OUString> ScFormulaCfg::GetPropertyNames()
         "Load/OOXMLRecalcMode",          // SCFORMULAOPT_OOXML_RECALC
         "Load/ODFRecalcMode",            // SCFORMULAOPT_ODF_RECALC
         "Calculation/OpenCL",            // SCFORMULAOPT_OPENCL_ENABLED
-        "Calculation/OpenCLAutoSelect"   // SCFORMULAOPT_OPENCL_AUTOSELECT
+        "Calculation/OpenCLAutoSelect",  // SCFORMULAOPT_OPENCL_AUTOSELECT
+        "Calculation/OpenCLDevice"       // SCFORMULAOPT_OPENCL_DEVICE
     };
     Sequence<OUString> aNames(SCFORMULAOPT_COUNT);
     OUString* pNames = aNames.getArray();
@@ -226,7 +229,7 @@ Sequence<OUString> ScFormulaCfg::GetPropertyNames()
 ScFormulaCfg::PropsToIds ScFormulaCfg::GetPropNamesToId()
 {
     Sequence<OUString> aPropNames = GetPropertyNames();
-    static sal_uInt16 aVals[] = { SCFORMULAOPT_GRAMMAR, SCFORMULAOPT_ENGLISH_FUNCNAME, SCFORMULAOPT_SEP_ARG, SCFORMULAOPT_SEP_ARRAY_ROW, SCFORMULAOPT_SEP_ARRAY_COL, SCFORMULAOPT_STRING_REF_SYNTAX, SCFORMULAOPT_EMPTY_STRING_AS_ZERO, SCFORMULAOPT_OOXML_RECALC, SCFORMULAOPT_ODF_RECALC, SCFORMULAOPT_OPENCL_ENABLED, SCFORMULAOPT_OPENCL_AUTOSELECT };
+    static sal_uInt16 aVals[] = { SCFORMULAOPT_GRAMMAR, SCFORMULAOPT_ENGLISH_FUNCNAME, SCFORMULAOPT_SEP_ARG, SCFORMULAOPT_SEP_ARRAY_ROW, SCFORMULAOPT_SEP_ARRAY_COL, SCFORMULAOPT_STRING_REF_SYNTAX, SCFORMULAOPT_EMPTY_STRING_AS_ZERO, SCFORMULAOPT_OOXML_RECALC, SCFORMULAOPT_ODF_RECALC, SCFORMULAOPT_OPENCL_ENABLED, SCFORMULAOPT_OPENCL_AUTOSELECT, SCFORMULAOPT_OPENCL_DEVICE };
     OSL_ENSURE( SAL_N_ELEMENTS(aVals) == aPropNames.getLength(), "Properties and ids are out of Sync");
     PropsToIds aPropIdMap;
     for ( sal_uInt16 i=0; i<aPropNames.getLength(); ++i )
@@ -418,6 +421,13 @@ void ScFormulaCfg::UpdateFromProperties( const Sequence<OUString>& aNames )
                     pValues[nProp] >>= bVal;
                     GetCalcConfig().mbOpenCLAutoSelect = bVal;
                 }
+                break;
+                case SCFORMULAOPT_OPENCL_DEVICE:
+                {
+                    OUString aOpenCLDevice = GetCalcConfig().maOpenCLDevice;
+                    pValues[nProp] >>= aOpenCLDevice;
+                    GetCalcConfig().maOpenCLDevice = aOpenCLDevice;
+                }
                 default:
                     ;
                 }
@@ -532,6 +542,14 @@ void ScFormulaCfg::Commit()
                 pValues[nProp] <<= bVal;
             }
             break;
+            case SCFORMULAOPT_OPENCL_DEVICE:
+            {
+                OUString aOpenCLDevice = GetCalcConfig().maOpenCLDevice;
+                pValues[nProp] <<= aOpenCLDevice;
+                sc::FormulaGroupInterpreter::switchOpenCLDevice(
+                        aOpenCLDevice, GetCalcConfig().mbOpenCLAutoSelect);
+            }
+            break;
             default:
                 ;
         }
diff --git a/sc/source/ui/app/scmod.cxx b/sc/source/ui/app/scmod.cxx
index 2fe4540..00a9748 100644
--- a/sc/source/ui/app/scmod.cxx
+++ b/sc/source/ui/app/scmod.cxx
@@ -179,9 +179,6 @@ ScModule::ScModule( SfxObjectFactory* pFact ) :
     ScGlobal::InitTextHeight( pMessagePool );
 
     StartListening( *SFX_APP() );       // for SFX_HINT_DEINITIALIZING
-
-    // initialize formula grouping
-    sc::FormulaGroupInterpreter::getStatic();
 }
 
 ScModule::~ScModule()
diff --git a/sc/source/ui/optdlg/calcoptionsdlg.cxx b/sc/source/ui/optdlg/calcoptionsdlg.cxx
index 652090b..6dd78fe 100644
--- a/sc/source/ui/optdlg/calcoptionsdlg.cxx
+++ b/sc/source/ui/optdlg/calcoptionsdlg.cxx
@@ -371,6 +371,7 @@ void ScCalcOptionsDialog::SelectedDeviceChanged()
     mpFtFrequency->SetText(OUString::number(pInfo->mnFrequency));
     mpFtComputeUnits->SetText(OUString::number(pInfo->mnComputeUnits));
     mpFtMemory->SetText(OUString::number(pInfo->mnMemory/1024/1024));
+    maConfig.maOpenCLDevice = dynamic_cast<SvLBoxString*>(pEntry->GetItem(1))->GetText();
 #endif
 }
 
commit 1c336382f4e2a6db05caa0a95c7e48f10b496eca
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sat Sep 14 16:07:42 2013 +0200

    add a way to change the opencl device
    
    We also use this method now to init OpenCL. It respects the auto select
    settings and will later take care of choosing the stored opencl device
    
    Change-Id: Ib3710851ac5f8d50796e4bba3b25ade77b36d204

diff --git a/sc/inc/formulagroup.hxx b/sc/inc/formulagroup.hxx
index ef9adbb..bfd4bbc 100644
--- a/sc/inc/formulagroup.hxx
+++ b/sc/inc/formulagroup.hxx
@@ -55,6 +55,7 @@ class SC_DLLPUBLIC FormulaGroupInterpreter
  public:
     static FormulaGroupInterpreter *getStatic();
     static void fillOpenCLInfo(std::vector<OpenclPlatformInfo>& rPlatforms);
+    static void switchOpenCLDevice(const OUString& rDeviceId, bool bAutoSelect);
 
     virtual ScMatrixRef inverseMatrix(const ScMatrix& rMat) = 0;
     virtual bool interpret(ScDocument& rDoc, const ScAddress& rTopPos, const ScFormulaCellGroupRef& xGroup, ScTokenArray& rCode) = 0;
diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index 06e2202..370a72d 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -132,11 +132,9 @@ public:
         mnOperatorCount = 0;
         mnPositonLen = 0;
         mnDoublePtrCount = 0;
-        OclCalc::initEnv();
     }
     virtual ~FormulaGroupInterpreterOpenCL()
     {
-        OclCalc::releaseOpenclRunEnv();
     }
 
     virtual ScMatrixRef inverseMatrix( const ScMatrix& rMat );
@@ -959,11 +957,9 @@ public:
         FormulaGroupInterpreterSoftware()
     {
         fprintf(stderr,"\n\n ***** Groundwater Backend *****\n\n\n");
-        OclCalc::initEnv();
     }
     virtual ~FormulaGroupInterpreterGroundwater()
     {
-        OclCalc::releaseOpenclRunEnv();
     }
 
     virtual ScMatrixRef inverseMatrix(const ScMatrix& /* rMat */) { return ScMatrixRef(); }
@@ -1093,6 +1089,11 @@ SAL_DLLPUBLIC_EXPORT void SAL_CALL fillOpenCLInfo(sc::OpenclPlatformInfo* pInfos
         pInfos[i] = rPlatforms[i];
 }
 
+SAL_DLLPUBLIC_EXPORT bool SAL_CALL switchOpenClDevice(const OUString* pDeviceId, bool bAutoSelect)
+{
+    sc::opencl::switchOpenclDevice(pDeviceId, bAutoSelect);
+}
+
 }
 
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
diff --git a/sc/source/core/opencl/openclwrapper.cxx b/sc/source/core/opencl/openclwrapper.cxx
index 6d1d25d..72d1ab3 100644
--- a/sc/source/core/opencl/openclwrapper.cxx
+++ b/sc/source/core/opencl/openclwrapper.cxx
@@ -2769,9 +2769,21 @@ const std::vector<OpenclPlatformInfo>& fillOpenCLInfo()
     return aPlatforms;
 }
 
-void switchOpenclDevice(void* pDevice, bool bAutoSelect)
+namespace {
+
+cl_device_id findDeviceIdByDeviceString(const OUString& rString, const std::vector<OpenclPlatformInfo>& rPlatforms)
+{
+    return NULL;
+}
+
+}
+
+bool switchOpenclDevice(const OUString* pDevice, bool bAutoSelect)
 {
-    cl_device_id pDeviceId = reinterpret_cast<cl_device_id>(pDevice);
+    cl_device_id pDeviceId = NULL;
+    if(pDevice)
+        pDeviceId = findDeviceIdByDeviceString(*pDevice, fillOpenCLInfo());
+
     if(!pDeviceId || bAutoSelect)
     {
         size_t nComputeUnits = 0;
@@ -2797,7 +2809,7 @@ void switchOpenclDevice(void* pDevice, bool bAutoSelect)
     {
         // we don't need to change anything
         // still the same device
-        return;
+        return true;
     }
 
     cl_platform_id platformId;
@@ -2816,7 +2828,7 @@ void switchOpenclDevice(void* pDevice, bool bAutoSelect)
             clReleaseContext(context);
 
         SAL_WARN("sc", "failed to set/switch opencl device");
-        return;
+        return false;
     }
 
     cl_command_queue command_queue = clCreateCommandQueue(
@@ -2828,6 +2840,8 @@ void switchOpenclDevice(void* pDevice, bool bAutoSelect)
             clReleaseCommandQueue(command_queue);
 
         clReleaseContext(context);
+        SAL_WARN("sc", "failed to set/switch opencl device");
+        return false;
     }
 
     OpenclDevice::releaseOpenclEnv(&OpenclDevice::gpuEnv);
@@ -2837,7 +2851,7 @@ void switchOpenclDevice(void* pDevice, bool bAutoSelect)
     env.mpOclDevsID = pDeviceId;
     env.mpOclCmdQueue = command_queue;
     OpenclDevice::initOpenclAttr(&env);
-    OpenclDevice::initOpenclRunEnv(&OpenclDevice::gpuEnv);
+    return !OpenclDevice::initOpenclRunEnv(0);
 }
 
 }}
diff --git a/sc/source/core/opencl/openclwrapper.hxx b/sc/source/core/opencl/openclwrapper.hxx
index d1a62c0..e11bdfb 100644
--- a/sc/source/core/opencl/openclwrapper.hxx
+++ b/sc/source/core/opencl/openclwrapper.hxx
@@ -288,8 +288,10 @@ const std::vector<OpenclPlatformInfo>& fillOpenCLInfo();
  *
  * @param pDeviceId the id of the opencl device of type cl_device_id, NULL means use software calculation
  * @param bAutoSelect use the algorithm to select the best OpenCL device
+ *
+ * @return returns true if there is a valid opencl device that has been set up
  */
-void switchOpenclDevice(void* pDeviceId, bool bAutoSelect);
+bool switchOpenclDevice(const OUString* pDeviceId, bool bAutoSelect);
 
 }}
 
diff --git a/sc/source/core/tool/formulagroup.cxx b/sc/source/core/tool/formulagroup.cxx
index 3b3001d..9b3ab9a 100644
--- a/sc/source/core/tool/formulagroup.cxx
+++ b/sc/source/core/tool/formulagroup.cxx
@@ -337,6 +337,7 @@ static void SAL_CALL thisModule() {}
 typedef FormulaGroupInterpreter* (*__createFormulaGroupOpenCLInterpreter)(void);
 typedef size_t (*__getOpenCLPlatformCount)(void);
 typedef void (*__fillOpenCLInfo)(OpenclPlatformInfo*, size_t);
+typedef bool (*__switchOpenClDevice)(const OUString*, bool);
 
 #endif
 
@@ -360,8 +361,6 @@ osl::Module* getOpenCLModule()
 /// load and/or configure the correct formula group interpreter
 FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
 {
-    static bool bOpenCLEnabled = false;
-
 #if USE_DUMMY_INTERPRETER
     if (getenv("FORMULA_GROUP_DUMMY"))
     {
@@ -370,42 +369,9 @@ FormulaGroupInterpreter *FormulaGroupInterpreter::getStatic()
     }
 #endif
 
-    if ( msInstance &&
-         bOpenCLEnabled != ScInterpreter::GetGlobalConfig().mbOpenCLEnabled )
-    {
-        bOpenCLEnabled = ScInterpreter::GetGlobalConfig().mbOpenCLEnabled;
-        delete msInstance;
-        msInstance = NULL;
-    }
-
     if ( !msInstance )
     {
-#if HAVE_FEATURE_OPENCL
-
-        bool bSoftware = false;
-        OUString aVal;
-        if (rtl::Bootstrap::get("SC_SOFTWARE", aVal) && aVal == "1")
-            bSoftware = true;
-
-        if ( ScInterpreter::GetGlobalConfig().mbOpenCLEnabled && !bSoftware)
-        {
-#ifdef DISABLE_DYNLOADING
-            msInstance = createFormulaGroupOpenCLInterpreter();
-#else
-            // Dynamically load scopencl shared object, and instantiate the opencl interpreter.
-            osl::Module* pModule = getOpenCLModule();
-            if (pModule)
-            {
-                oslGenericFunction fn = pModule->getFunctionSymbol("createFormulaGroupOpenCLInterpreter");
-                if (fn)
-                    msInstance = reinterpret_cast<__createFormulaGroupOpenCLInterpreter>(fn)();
-            }
-
-            if (!msInstance)
-                msInstance = new sc::FormulaGroupInterpreterOpenCLMissing();
-#endif
-        }
-#endif
+        switchOpenCLDevice(OUString(), ScInterpreter::GetGlobalConfig().mbOpenCLEnabled);
         if ( !msInstance ) // software fallback
         {
             fprintf(stderr, "Create S/W interp\n");
@@ -439,6 +405,58 @@ void FormulaGroupInterpreter::fillOpenCLInfo(std::vector<OpenclPlatformInfo>& rP
     rPlatforms.swap(aPlatforms);
 }
 
+void FormulaGroupInterpreter::switchOpenCLDevice(const OUString& rDeviceId, bool bAutoSelect)
+{
+    bool bOpenCLEnabled = ScInterpreter::GetGlobalConfig().mbOpenCLEnabled;
+    if(!bOpenCLEnabled || rDeviceId == "Software")
+    {
+        if(msInstance)
+        {
+            // if we already have a software interpreter don't delete it
+            if(dynamic_cast<sc::FormulaGroupInterpreterSoftware*>(msInstance))
+                return;
+
+            delete msInstance;
+        }
+
+        msInstance = new sc::FormulaGroupInterpreterSoftware();
+        return;
+    }
+
+    osl::Module* pModule = getOpenCLModule();
+    if (!pModule)
+        return;
+
+    oslGenericFunction fn = pModule->getFunctionSymbol("switchOpenclDevice");
+    if (!fn)
+        return;
+
+    bool bSuccess = reinterpret_cast<__switchOpenClDevice>(fn)(&rDeviceId, bAutoSelect);
+    if(!bSuccess)
+        return;
+
+    delete msInstance;
+    msInstance = NULL;
+
+#if HAVE_FEATURE_OPENCL
+
+    if ( ScInterpreter::GetGlobalConfig().mbOpenCLEnabled )
+    {
+#ifdef DISABLE_DYNLOADING
+        msInstance = createFormulaGroupOpenCLInterpreter();
+#else
+        // Dynamically load scopencl shared object, and instantiate the opencl interpreter.
+        fn = pModule->getFunctionSymbol("createFormulaGroupOpenCLInterpreter");
+        if (fn)
+            msInstance = reinterpret_cast<__createFormulaGroupOpenCLInterpreter>(fn)();
+
+        if (!msInstance)
+            msInstance = new sc::FormulaGroupInterpreterOpenCLMissing();
+#endif
+    }
+#endif
+}
+
 void FormulaGroupInterpreter::generateRPNCode(ScDocument& rDoc, const ScAddress& rPos, ScTokenArray& rCode)
 {
     // First, generate an RPN (reverse polish notation) token array.
commit 808b3475eea49c2b080bdcd2d9626ff590cc2041
Author: Markus Mohrhard <markus.mohrhard at googlemail.com>
Date:   Sat Sep 14 01:22:41 2013 +0200

    implement method for switching opencl devices
    
    Change-Id: I00f00618e7bf3eb256a2fcef16520927b53dfc9a

diff --git a/sc/source/core/opencl/formulagroupcl.cxx b/sc/source/core/opencl/formulagroupcl.cxx
index ce5f568..06e2202 100644
--- a/sc/source/core/opencl/formulagroupcl.cxx
+++ b/sc/source/core/opencl/formulagroupcl.cxx
@@ -1087,11 +1087,10 @@ SAL_DLLPUBLIC_EXPORT size_t getOpenCLPlatformCount()
 
 SAL_DLLPUBLIC_EXPORT void SAL_CALL fillOpenCLInfo(sc::OpenclPlatformInfo* pInfos, size_t nInfoSize)
 {
-    std::vector<sc::OpenclPlatformInfo> aPlatforms;
-    sc::opencl::fillOpenCLInfo(aPlatforms);
-    size_t n = std::min(aPlatforms.size(), nInfoSize);
+    const std::vector<sc::OpenclPlatformInfo>& rPlatforms = sc::opencl::fillOpenCLInfo();
+    size_t n = std::min(rPlatforms.size(), nInfoSize);
     for (size_t i = 0; i < n; ++i)
-        pInfos[i] = aPlatforms[i];
+        pInfos[i] = rPlatforms[i];
 }
 
 }
diff --git a/sc/source/core/opencl/openclwrapper.cxx b/sc/source/core/opencl/openclwrapper.cxx
index f508758..6d1d25d 100644
--- a/sc/source/core/opencl/openclwrapper.cxx
+++ b/sc/source/core/opencl/openclwrapper.cxx
@@ -2703,8 +2703,10 @@ bool createPlatformInfo(cl_platform_id nPlatformId, OpenclPlatformInfo& rPlatfor
     if(nState != CL_SUCCESS)
         return false;
 
-    boost::scoped_array<cl_device_id> pDevices(new cl_device_id[nDevices]);
-    nState = clGetDeviceIDs(nPlatformId, CL_DEVICE_TYPE_ALL, nDevices, pDevices.get(), NULL);
+    // memory leak that does not matter
+    // memory is stored in static variable that lives through the whole program
+    cl_device_id* pDevices = new cl_device_id[nDevices];
+    nState = clGetDeviceIDs(nPlatformId, CL_DEVICE_TYPE_ALL, nDevices, pDevices, NULL);
     if(nState != CL_SUCCESS)
         return false;
 
@@ -2733,30 +2735,109 @@ size_t getOpenCLPlatformCount()
     return nPlatforms;
 }
 
-void fillOpenCLInfo(std::vector<OpenclPlatformInfo>& rPlatforms)
+const std::vector<OpenclPlatformInfo>& fillOpenCLInfo()
 {
+    static std::vector<OpenclPlatformInfo> aPlatforms;
+    if(!aPlatforms.empty())
+        return aPlatforms;
+
     int status = clewInit(OPENCL_DLL_NAME);
     if (status < 0)
-        return;
+        return aPlatforms;
 
     cl_uint nPlatforms;
     cl_int nState = clGetPlatformIDs(0, NULL, &nPlatforms);
 
     if(nState != CL_SUCCESS)
-        return;
+        return aPlatforms;
 
-    boost::scoped_array<cl_platform_id> pPlatforms(new cl_platform_id[nPlatforms]);
-    nState = clGetPlatformIDs(nPlatforms, pPlatforms.get(), NULL);
+    // memory leak that does not matter,
+    // memory is stored in static instance aPlatforms
+    cl_platform_id* pPlatforms = new cl_platform_id[nPlatforms];
+    nState = clGetPlatformIDs(nPlatforms, pPlatforms, NULL);
 
     if(nState != CL_SUCCESS)
-        return;
+        return aPlatforms;
 
     for(size_t i = 0; i < nPlatforms; ++i)
     {
         OpenclPlatformInfo aPlatformInfo;
         if(createPlatformInfo(pPlatforms[i], aPlatformInfo))
-            rPlatforms.push_back(aPlatformInfo);
+            aPlatforms.push_back(aPlatformInfo);
+    }
+
+    return aPlatforms;
+}
+
+void switchOpenclDevice(void* pDevice, bool bAutoSelect)
+{
+    cl_device_id pDeviceId = reinterpret_cast<cl_device_id>(pDevice);
+    if(!pDeviceId || bAutoSelect)
+    {
+        size_t nComputeUnits = 0;
+        // clever algorithm
+        const std::vector<OpenclPlatformInfo>& rPlatform = fillOpenCLInfo();
+        for(std::vector<OpenclPlatformInfo>::const_iterator it =
+                rPlatform.begin(), itEnd = rPlatform.end(); it != itEnd; ++it)
+        {
+            for(std::vector<OpenclDeviceInfo>::const_iterator itr =
+                    it->maDevices.begin(), itrEnd = it->maDevices.end();
+                    itr != itrEnd; ++itr)
+            {
+                if(itr->mnComputeUnits > nComputeUnits)
+                {
+                    pDeviceId = reinterpret_cast<cl_device_id>(itr->device);
+                    nComputeUnits = itr->mnComputeUnits;
+                }
+            }
+        }
+    }
+
+    if(OpenclDevice::gpuEnv.mpDevID == pDeviceId)
+    {
+        // we don't need to change anything
+        // still the same device
+        return;
     }
+
+    cl_platform_id platformId;
+    cl_int nState = clGetDeviceInfo(pDeviceId, CL_DEVICE_PLATFORM,
+            sizeof(platformId), &platformId, NULL);
+
+    cl_context_properties cps[3];
+    cps[0] = CL_CONTEXT_PLATFORM;
+    cps[1] = (cl_context_properties) platformId;
+    cps[2] = 0;
+    cl_context context = clCreateContext( cps, 1, &pDeviceId, NULL, NULL, &nState );
+
+    if(nState != CL_SUCCESS || context == NULL)
+    {
+        if(context != NULL)
+            clReleaseContext(context);
+
+        SAL_WARN("sc", "failed to set/switch opencl device");
+        return;
+    }
+
+    cl_command_queue command_queue = clCreateCommandQueue(
+            context, pDeviceId, 0, &nState);
+
+    if(command_queue == NULL || nState != CL_SUCCESS)
+    {
+        if(command_queue != NULL)
+            clReleaseCommandQueue(command_queue);
+
+        clReleaseContext(context);
+    }
+
+    OpenclDevice::releaseOpenclEnv(&OpenclDevice::gpuEnv);
+    OpenCLEnv env;
+    env.mpOclPlatformID = platformId;
+    env.mpOclContext = context;
+    env.mpOclDevsID = pDeviceId;
+    env.mpOclCmdQueue = command_queue;
+    OpenclDevice::initOpenclAttr(&env);
+    OpenclDevice::initOpenclRunEnv(&OpenclDevice::gpuEnv);
 }
 
 }}
diff --git a/sc/source/core/opencl/openclwrapper.hxx b/sc/source/core/opencl/openclwrapper.hxx
index 4d509c5..d1a62c0 100644
--- a/sc/source/core/opencl/openclwrapper.hxx
+++ b/sc/source/core/opencl/openclwrapper.hxx
@@ -195,7 +195,7 @@ public:
     static int binaryGenerated( const char * clFileName, FILE ** fhandle );
     static int compileKernelFile( const char *filename, GPUEnv *gpuInfo, const char *buildOption );
 
-    int initOpenclAttr( OpenCLEnv * env );
+    static int initOpenclAttr( OpenCLEnv * env );
     int releaseKernel( KernelEnv * env );
     int setKernelEnv( KernelEnv *envInfo );
     int createKernel( char * kernelname, KernelEnv * env );
@@ -281,7 +281,15 @@ public:
 };
 
 size_t getOpenCLPlatformCount();
-void fillOpenCLInfo(std::vector<OpenclPlatformInfo>& rPlatforms);
+const std::vector<OpenclPlatformInfo>& fillOpenCLInfo();
+
+/**
+ * Used to set or switch between OpenCL devices.
+ *
+ * @param pDeviceId the id of the opencl device of type cl_device_id, NULL means use software calculation
+ * @param bAutoSelect use the algorithm to select the best OpenCL device
+ */
+void switchOpenclDevice(void* pDeviceId, bool bAutoSelect);
 
 }}
 


More information about the Libreoffice-commits mailing list