Stop leaking all ScPostIt instances.
[LibreOffice.git] / sc / source / core / opencl / openclwrapper.cxx
blobcf74a4be7418585895724826f52a0b429207fd00
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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/.
8 */
10 #include <config_folders.h>
12 #include "openclwrapper.hxx"
14 #include <rtl/ustring.hxx>
15 #include <rtl/strbuf.hxx>
16 #include <rtl/digest.h>
17 #include <rtl/bootstrap.hxx>
18 #include <boost/scoped_array.hpp>
20 #include "sal/config.h"
21 #include <osl/file.hxx>
22 #include "opencl_device.hxx"
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <cmath>
29 #ifdef WIN32
30 #include <windows.h>
31 #define OPENCL_DLL_NAME "OpenCL.dll"
32 #elif defined(MACOSX)
33 #define OPENCL_DLL_NAME NULL
34 #else
35 #define OPENCL_DLL_NAME "libOpenCL.so"
36 #endif
38 #define DEVICE_NAME_LENGTH 1024
39 #define DRIVER_VERSION_LENGTH 1024
40 #define PLATFORM_VERSION_LENGTH 1024
42 using namespace std;
44 namespace sc { namespace opencl {
46 GPUEnv OpenclDevice::gpuEnv;
47 int OpenclDevice::isInited =0;
49 namespace {
51 OString generateMD5(const void* pData, size_t length)
53 sal_uInt8 pBuffer[RTL_DIGEST_LENGTH_MD5];
54 rtlDigestError aError = rtl_digest_MD5(pData, length,
55 pBuffer, RTL_DIGEST_LENGTH_MD5);
56 SAL_WARN_IF(aError != rtl_Digest_E_None, "sc", "md5 generation failed");
58 OStringBuffer aBuffer;
59 const char* pString = "0123456789ABCDEF";
60 for(size_t i = 0; i < RTL_DIGEST_LENGTH_MD5; ++i)
62 sal_uInt8 val = pBuffer[i];
63 aBuffer.append(pString[val/16]);
64 aBuffer.append(pString[val%16]);
66 return aBuffer.makeStringAndClear();
69 OString getCacheFolder()
71 OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/");
72 rtl::Bootstrap::expandMacros(url);
74 osl::Directory::create(url);
76 return rtl::OUStringToOString(url, RTL_TEXTENCODING_UTF8);
79 void clearCache()
81 #if 0
82 // We used to delete all files that did not end with the hash of
83 // the static kernel source string from oclkernels.hxx. But as
84 // those static kernels were not used for anything, it was
85 // pointless, that hash never changed. The static kernels are now
86 // removed, their hash is not part of the .bin file names any
87 // more. So there is little this function can do until we come up
88 // with some other way to figure out which cached .bin files are
89 // "current".
90 OUString aCacheDirURL(rtl::OStringToOUString(OpenclDevice::maCacheFolder, RTL_TEXTENCODING_UTF8));
91 osl::Directory aCacheDir(aCacheDirURL);
92 osl::FileBase::RC status = aCacheDir.open();
93 if(status != osl::FileBase::E_None)
94 return;
96 osl::DirectoryItem aItem;
97 while(osl::FileBase::E_None == aCacheDir.getNextItem(aItem))
99 osl::FileStatus aFileStatus(osl_FileStatus_Mask_FileName|osl_FileStatus_Mask_FileURL);
100 status = aItem.getFileStatus(aFileStatus);
101 if(status != osl::FileBase::E_None)
102 continue;
104 OUString aFileName = aFileStatus.getFileName();
105 if(aFileName.endsWith(".bin"))
107 if ( file is in some way obsolete )
109 // delete the file
110 OUString aFileUrl = aFileStatus.getFileURL();
111 osl::File::remove(aFileUrl);
115 #endif
120 OString OpenclDevice::maCacheFolder = getCacheFolder();
122 int OpenclDevice::releaseOpenclRunEnv()
124 releaseOpenclEnv( &gpuEnv );
126 return 1;
129 int OpenclDevice::registOpenclKernel()
131 if ( !gpuEnv.mnIsUserCreated )
132 memset( &gpuEnv, 0, sizeof(gpuEnv) );
134 return 0;
137 int OpenclDevice::setKernelEnv( KernelEnv *envInfo )
139 envInfo->mpkContext = gpuEnv.mpContext;
140 envInfo->mpkCmdQueue = gpuEnv.mpCmdQueue;
141 envInfo->mpkProgram = gpuEnv.mpArryPrograms[0];
143 return 1;
146 namespace {
148 OString createFileName(cl_device_id deviceId, const char* clFileName)
150 OString fileName(clFileName);
151 sal_Int32 nIndex = fileName.lastIndexOf(".cl");
152 if(nIndex > 0)
153 fileName = fileName.copy(0, nIndex);
155 char deviceName[DEVICE_NAME_LENGTH] = {0};
156 clGetDeviceInfo(deviceId, CL_DEVICE_NAME,
157 sizeof(deviceName), deviceName, NULL);
159 char driverVersion[DRIVER_VERSION_LENGTH] = {0};
160 clGetDeviceInfo(deviceId, CL_DRIVER_VERSION,
161 sizeof(driverVersion), driverVersion, NULL);
163 cl_platform_id platformId;
164 clGetDeviceInfo(deviceId, CL_DEVICE_PLATFORM,
165 sizeof(platformId), &platformId, NULL);
167 char platformVersion[PLATFORM_VERSION_LENGTH] = {0};
168 clGetPlatformInfo(platformId, CL_PLATFORM_VERSION, sizeof(platformVersion),
169 platformVersion, NULL);
171 // create hash for deviceName + driver version + platform version
172 OString aString = OString(deviceName) + driverVersion + platformVersion;
173 OString aHash = generateMD5(aString.getStr(), aString.getLength());
175 return OpenclDevice::maCacheFolder + fileName + "-" +
176 aHash + ".bin";
181 std::vector<boost::shared_ptr<osl::File> > OpenclDevice::binaryGenerated( const char * clFileName, cl_context context )
183 size_t numDevices=0;
185 std::vector<boost::shared_ptr<osl::File> > aGeneratedFiles;
186 cl_int clStatus = clGetContextInfo( context, CL_CONTEXT_DEVICES,
187 0, NULL, &numDevices );
188 numDevices /= sizeof(numDevices);
190 if(clStatus != CL_SUCCESS)
191 return aGeneratedFiles;
194 // grab the handles to all of the devices in the context.
195 boost::scoped_array<cl_device_id> mpArryDevsID(new cl_device_id[numDevices]);
196 clStatus = clGetContextInfo( context, CL_CONTEXT_DEVICES,
197 sizeof( cl_device_id ) * numDevices, mpArryDevsID.get(), NULL );
199 if(clStatus != CL_SUCCESS)
200 return aGeneratedFiles;
202 for ( size_t i = 0; i < numDevices; i++ )
204 if ( mpArryDevsID[i] != 0 )
206 OString fileName = createFileName(gpuEnv.mpArryDevsID[i], clFileName);
207 osl::File* pNewFile = new osl::File(rtl::OStringToOUString(fileName, RTL_TEXTENCODING_UTF8));
208 if(pNewFile->open(osl_File_OpenFlag_Read) == osl::FileBase::E_None)
210 aGeneratedFiles.push_back(boost::shared_ptr<osl::File>(pNewFile));
211 SAL_INFO("sc.opencl", "Opening binary file '" << fileName << "' for reading: success");
213 else
215 SAL_INFO("sc.opencl", "Opening binary file '" << fileName << "' for reading: FAIL");
216 delete pNewFile;
217 break;
222 return aGeneratedFiles;
225 int OpenclDevice::writeBinaryToFile( const OString& rFileName, const char* binary, size_t numBytes )
227 clearCache();
228 osl::File file(rtl::OStringToOUString(rFileName, RTL_TEXTENCODING_UTF8));
229 osl::FileBase::RC status = file.open(
230 osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
232 if(status != osl::FileBase::E_None)
233 return 0;
235 sal_uInt64 nBytesWritten = 0;
236 file.write( binary, numBytes, nBytesWritten );
238 assert(numBytes == nBytesWritten);
240 return 1;
243 int OpenclDevice::generatBinFromKernelSource( cl_program program, const char * clFileName )
245 cl_uint numDevices;
247 cl_int clStatus = clGetProgramInfo( program, CL_PROGRAM_NUM_DEVICES,
248 sizeof(numDevices), &numDevices, NULL );
249 CHECK_OPENCL( clStatus, "clGetProgramInfo" );
251 std::vector<cl_device_id> mpArryDevsID(numDevices);
252 /* grab the handles to all of the devices in the program. */
253 clStatus = clGetProgramInfo( program, CL_PROGRAM_DEVICES,
254 sizeof(cl_device_id) * numDevices, &mpArryDevsID[0], NULL );
255 CHECK_OPENCL( clStatus, "clGetProgramInfo" );
257 /* figure out the sizes of each of the binaries. */
258 std::vector<size_t> binarySizes(numDevices);
260 clStatus = clGetProgramInfo( program, CL_PROGRAM_BINARY_SIZES,
261 sizeof(size_t) * numDevices, &binarySizes[0], NULL );
262 CHECK_OPENCL( clStatus, "clGetProgramInfo" );
264 /* copy over all of the generated binaries. */
265 boost::scoped_array<char*> binaries(new char*[numDevices]);
267 for ( size_t i = 0; i < numDevices; i++ )
269 if ( binarySizes[i] != 0 )
271 binaries[i] = new char[binarySizes[i]];
273 else
275 binaries[i] = NULL;
279 clStatus = clGetProgramInfo( program, CL_PROGRAM_BINARIES,
280 sizeof(char *) * numDevices, binaries.get(), NULL );
281 CHECK_OPENCL(clStatus,"clGetProgramInfo");
283 /* dump out each binary into its own separate file. */
284 for ( size_t i = 0; i < numDevices; i++ )
287 if ( binarySizes[i] != 0 )
289 OString fileName = createFileName(mpArryDevsID[i], clFileName);
290 if ( !writeBinaryToFile( fileName,
291 binaries[i], binarySizes[i] ) )
292 SAL_INFO("sc.opencl", "Writing binary file '" << fileName << "': FAIL");
293 else
294 SAL_INFO("sc.opencl", "Writing binary file '" << fileName << "': success");
298 // Release all resouces and memory
299 for ( size_t i = 0; i < numDevices; i++ )
301 delete[] binaries[i];
304 return 1;
307 int OpenclDevice::initOpenclAttr( OpenCLEnv * env )
309 if ( gpuEnv.mnIsUserCreated )
310 return 1;
312 gpuEnv.mpContext = env->mpOclContext;
313 gpuEnv.mpPlatformID = env->mpOclPlatformID;
314 gpuEnv.mpDevID = env->mpOclDevsID;
315 gpuEnv.mpCmdQueue = env->mpOclCmdQueue;
317 gpuEnv.mnIsUserCreated = 1;
319 return 0;
322 int OpenclDevice::releaseOpenclEnv( GPUEnv *gpuInfo )
324 if ( !isInited )
326 return 1;
329 if ( gpuEnv.mpCmdQueue )
331 clReleaseCommandQueue( gpuEnv.mpCmdQueue );
332 gpuEnv.mpCmdQueue = NULL;
334 if ( gpuEnv.mpContext )
336 clReleaseContext( gpuEnv.mpContext );
337 gpuEnv.mpContext = NULL;
339 isInited = 0;
340 gpuInfo->mnIsUserCreated = 0;
341 free( gpuInfo->mpArryDevsID );
343 return 1;
346 namespace {
348 bool buildProgram(const char* buildOption, GPUEnv* gpuInfo, int idx)
350 cl_int clStatus;
351 //char options[512];
352 // create a cl program executable for all the devices specified
353 if (!gpuInfo->mnIsUserCreated)
355 clStatus = clBuildProgram(gpuInfo->mpArryPrograms[idx], 1, gpuInfo->mpArryDevsID,
356 buildOption, NULL, NULL);
358 else
360 clStatus = clBuildProgram(gpuInfo->mpArryPrograms[idx], 1, &(gpuInfo->mpDevID),
361 buildOption, NULL, NULL);
364 if ( clStatus != CL_SUCCESS )
366 size_t length;
367 if ( !gpuInfo->mnIsUserCreated )
369 clStatus = clGetProgramBuildInfo( gpuInfo->mpArryPrograms[idx], gpuInfo->mpArryDevsID[0],
370 CL_PROGRAM_BUILD_LOG, 0, NULL, &length );
372 else
374 clStatus = clGetProgramBuildInfo( gpuInfo->mpArryPrograms[idx], gpuInfo->mpDevID,
375 CL_PROGRAM_BUILD_LOG, 0, NULL, &length);
377 if ( clStatus != CL_SUCCESS )
379 return 0;
382 boost::scoped_array<char> buildLog(new char[length]);
383 if ( !gpuInfo->mnIsUserCreated )
385 clStatus = clGetProgramBuildInfo( gpuInfo->mpArryPrograms[idx], gpuInfo->mpArryDevsID[0],
386 CL_PROGRAM_BUILD_LOG, length, buildLog.get(), &length );
388 else
390 clStatus = clGetProgramBuildInfo( gpuInfo->mpArryPrograms[idx], gpuInfo->mpDevID,
391 CL_PROGRAM_BUILD_LOG, length, buildLog.get(), &length );
393 if ( clStatus != CL_SUCCESS )
395 return false;
398 OString aBuildLogFileURL = OpenclDevice::maCacheFolder + "kernel-build.log";
399 osl::File aBuildLogFile(rtl::OStringToOUString(aBuildLogFileURL, RTL_TEXTENCODING_UTF8));
400 osl::FileBase::RC status = aBuildLogFile.open(
401 osl_File_OpenFlag_Write | osl_File_OpenFlag_Create );
403 if(status != osl::FileBase::E_None)
404 return false;
406 sal_uInt64 nBytesWritten = 0;
407 aBuildLogFile.write( buildLog.get(), length, nBytesWritten );
409 return false;
412 return true;
417 bool OpenclDevice::buildProgramFromBinary(const char* buildOption, GPUEnv* gpuInfo, const char* filename, int idx)
419 size_t numDevices;
420 cl_int clStatus = clGetContextInfo( gpuInfo->mpContext, CL_CONTEXT_DEVICES,
421 0, NULL, &numDevices );
422 numDevices /= sizeof(numDevices);
423 CHECK_OPENCL( clStatus, "clGetContextInfo" );
425 std::vector<boost::shared_ptr<osl::File> > aGeneratedFiles = binaryGenerated(
426 filename, gpuInfo->mpContext );
428 if (aGeneratedFiles.size() == numDevices)
430 boost::scoped_array<size_t> length(new size_t[numDevices]);
431 boost::scoped_array<unsigned char*> pBinary(new unsigned char*[numDevices]);
432 for(size_t i = 0; i < numDevices; ++i)
434 sal_uInt64 nSize;
435 aGeneratedFiles[i]->getSize(nSize);
436 unsigned char* binary = new unsigned char[nSize];
437 sal_uInt64 nBytesRead;
438 aGeneratedFiles[i]->read(binary, nSize, nBytesRead);
439 if(nSize != nBytesRead)
440 assert(false);
442 length[i] = nBytesRead;
444 pBinary[i] = binary;
447 // grab the handles to all of the devices in the context.
448 boost::scoped_array<cl_device_id> mpArryDevsID(new cl_device_id[numDevices]);
449 clStatus = clGetContextInfo( gpuInfo->mpContext, CL_CONTEXT_DEVICES,
450 sizeof( cl_device_id ) * numDevices, mpArryDevsID.get(), NULL );
452 if(clStatus != CL_SUCCESS)
454 for(size_t i = 0; i < numDevices; ++i)
456 delete[] pBinary[i];
458 return false;
461 cl_int binary_status;
463 gpuInfo->mpArryPrograms[idx] = clCreateProgramWithBinary( gpuInfo->mpContext,numDevices,
464 mpArryDevsID.get(), length.get(), (const unsigned char**) pBinary.get(),
465 &binary_status, &clStatus );
466 if(clStatus != CL_SUCCESS)
468 // something went wrong, fall back to compiling from source
469 return false;
471 for(size_t i = 0; i < numDevices; ++i)
473 delete[] pBinary[i];
477 if ( !gpuInfo->mpArryPrograms[idx] )
479 return false;
481 return buildProgram(buildOption, gpuInfo, idx);
484 int OpenclDevice::initOpenclRunEnv( int argc )
486 if ( MAX_CLKERNEL_NUM <= 0 )
488 return 1;
490 if ( ( argc > MAX_CLFILE_NUM ) || ( argc < 0 ) )
491 return 1;
493 if ( !isInited )
495 registOpenclKernel();
496 //initialize devices, context, comand_queue
497 int status = initOpenclRunEnv( &gpuEnv );
498 if ( status )
500 return 1;
502 //initialize program, kernelName, kernelCount
503 if( getenv( "SC_FLOAT" ) )
505 gpuEnv.mnKhrFp64Flag = 0;
506 gpuEnv.mnAmdFp64Flag = 0;
508 if( gpuEnv.mnKhrFp64Flag )
510 SAL_INFO("sc.opencl", "Use Khr double");
512 else if( gpuEnv.mnAmdFp64Flag )
514 SAL_INFO("sc.opencl", "Use AMD double type");
516 else
518 SAL_INFO("sc.opencl", "USE float type");
520 isInited = 1;
522 return 0;
525 namespace {
527 void checkDeviceForDoubleSupport(cl_device_id deviceId, bool& bKhrFp64, bool& bAmdFp64)
529 bKhrFp64 = false;
530 bAmdFp64 = false;
532 // Check device extensions for double type
533 size_t aDevExtInfoSize = 0;
535 cl_uint clStatus = clGetDeviceInfo( deviceId, CL_DEVICE_EXTENSIONS, 0, NULL, &aDevExtInfoSize );
536 if( clStatus != CL_SUCCESS )
537 return;
539 boost::scoped_array<char> pExtInfo(new char[aDevExtInfoSize]);
541 clStatus = clGetDeviceInfo( deviceId, CL_DEVICE_EXTENSIONS,
542 sizeof(char) * aDevExtInfoSize, pExtInfo.get(), NULL);
544 if( clStatus != CL_SUCCESS )
545 return;
547 if ( strstr( pExtInfo.get(), "cl_khr_fp64" ) )
549 bKhrFp64 = true;
551 else
553 // Check if cl_amd_fp64 extension is supported
554 if ( strstr( pExtInfo.get(), "cl_amd_fp64" ) )
555 bAmdFp64 = true;
561 int OpenclDevice::initOpenclRunEnv( GPUEnv *gpuInfo )
563 size_t length;
564 cl_int clStatus;
565 cl_uint numPlatforms, numDevices;
566 cl_platform_id *platforms;
568 // Have a look at the available platforms.
570 if ( !gpuInfo->mnIsUserCreated )
572 clStatus = clGetPlatformIDs( 0, NULL, &numPlatforms );
573 CHECK_OPENCL(clStatus, "clGetPlatformIDs");
574 gpuInfo->mpPlatformID = NULL;
576 if ( 0 < numPlatforms )
578 char platformName[256];
579 platforms = (cl_platform_id*) malloc( numPlatforms * sizeof( cl_platform_id ) );
580 if (!platforms)
582 return 1;
584 clStatus = clGetPlatformIDs( numPlatforms, platforms, NULL );
585 CHECK_OPENCL(clStatus, "clGetPlatformIDs");
587 for ( unsigned int i = 0; i < numPlatforms; i++ )
589 clStatus = clGetPlatformInfo( platforms[i], CL_PLATFORM_VENDOR,
590 sizeof( platformName ), platformName, NULL );
592 if ( clStatus != CL_SUCCESS )
594 break;
596 gpuInfo->mpPlatformID = platforms[i];
598 //if (!strcmp(platformName, "Intel(R) Coporation"))
599 //if( !strcmp( platformName, "Advanced Micro Devices, Inc." ))
601 gpuInfo->mpPlatformID = platforms[i];
602 if ( getenv("SC_OPENCLCPU") )
604 clStatus = clGetDeviceIDs(gpuInfo->mpPlatformID, // platform
605 CL_DEVICE_TYPE_CPU, // device_type for CPU device
606 0, // num_entries
607 NULL, // devices
608 &numDevices);
610 else
612 clStatus = clGetDeviceIDs(gpuInfo->mpPlatformID, // platform
613 CL_DEVICE_TYPE_GPU, // device_type for GPU device
614 0, // num_entries
615 NULL, // devices
616 &numDevices);
618 if ( clStatus != CL_SUCCESS )
619 continue;
621 if ( numDevices )
622 break;
625 free( platforms );
626 if ( clStatus != CL_SUCCESS )
627 return 1;
629 if ( NULL == gpuInfo->mpPlatformID )
630 return 1;
632 // Use available platform.
633 cl_context_properties cps[3];
634 cps[0] = CL_CONTEXT_PLATFORM;
635 cps[1] = (cl_context_properties) gpuInfo->mpPlatformID;
636 cps[2] = 0;
637 // Set device type for OpenCL
638 if ( getenv("SC_OPENCLCPU") )
640 gpuInfo->mDevType = CL_DEVICE_TYPE_CPU;
642 else
644 gpuInfo->mDevType = CL_DEVICE_TYPE_GPU;
646 gpuInfo->mpContext = clCreateContextFromType( cps, gpuInfo->mDevType, NULL, NULL, &clStatus );
648 if ( ( gpuInfo->mpContext == (cl_context) NULL) || ( clStatus != CL_SUCCESS ) )
650 gpuInfo->mDevType = CL_DEVICE_TYPE_CPU;
651 gpuInfo->mpContext = clCreateContextFromType( cps, gpuInfo->mDevType, NULL, NULL, &clStatus );
653 if ( ( gpuInfo->mpContext == (cl_context) NULL) || ( clStatus != CL_SUCCESS ) )
655 gpuInfo->mDevType = CL_DEVICE_TYPE_DEFAULT;
656 gpuInfo->mpContext = clCreateContextFromType( cps, gpuInfo->mDevType, NULL, NULL, &clStatus );
658 if ( ( gpuInfo->mpContext == (cl_context) NULL) || ( clStatus != CL_SUCCESS ) )
659 return 1;
660 // Detect OpenCL devices.
661 // First, get the size of device list data
662 clStatus = clGetContextInfo( gpuInfo->mpContext, CL_CONTEXT_DEVICES, 0, NULL, &length );
663 if ( ( clStatus != CL_SUCCESS ) || ( length == 0 ) )
664 return 1;
665 // Now allocate memory for device list based on the size we got earlier
666 gpuInfo->mpArryDevsID = (cl_device_id*) malloc( length );
667 if ( gpuInfo->mpArryDevsID == (cl_device_id*) NULL )
668 return 1;
669 // Now, get the device list data
670 clStatus = clGetContextInfo( gpuInfo->mpContext, CL_CONTEXT_DEVICES, length,
671 gpuInfo->mpArryDevsID, NULL );
672 CHECK_OPENCL(clStatus, "clGetContextInfo");
674 // Create OpenCL command queue.
675 gpuInfo->mpCmdQueue = clCreateCommandQueue( gpuInfo->mpContext, gpuInfo->mpArryDevsID[0], 0, &clStatus );
677 CHECK_OPENCL(clStatus, "clCreateCommandQueue");
679 bool bKhrFp64 = false;
680 bool bAmdFp64 = false;
682 checkDeviceForDoubleSupport(gpuInfo->mpArryDevsID[0], bKhrFp64, bAmdFp64);
684 gpuInfo->mnKhrFp64Flag = bKhrFp64;
685 gpuInfo->mnAmdFp64Flag = bAmdFp64;
687 return 0;
690 void OpenclDevice::setOpenclState( int state )
692 isInited = state;
695 int OpenclDevice::getOpenclState()
697 return isInited;
700 namespace {
702 // based on crashes and hanging during kernel compilation
703 bool checkForKnownBadCompilers(const OpenclDeviceInfo& rInfo)
706 struct {
707 const char* pVendorName; const char* pDriverVersion;
708 } aBadOpenCLCompilers[] = {
709 { "Intel(R) Corporation", "9.17.10.2884" }
712 for(size_t i = 0; i < SAL_N_ELEMENTS(aBadOpenCLCompilers); ++i)
714 if(rInfo.maVendor == OUString::createFromAscii(aBadOpenCLCompilers[i].pVendorName) &&
715 rInfo.maDriver == OUString::createFromAscii(aBadOpenCLCompilers[i].pDriverVersion))
716 return true;
719 return false;
722 void createDeviceInfo(cl_device_id aDeviceId, OpenclPlatformInfo& rPlatformInfo)
724 OpenclDeviceInfo aDeviceInfo;
725 aDeviceInfo.device = aDeviceId;
727 char pName[DEVICE_NAME_LENGTH];
728 cl_int nState = clGetDeviceInfo(aDeviceId, CL_DEVICE_NAME, DEVICE_NAME_LENGTH, pName, NULL);
729 if(nState != CL_SUCCESS)
730 return;
732 aDeviceInfo.maName = OUString::createFromAscii(pName);
734 char pVendor[DEVICE_NAME_LENGTH];
735 nState = clGetDeviceInfo(aDeviceId, CL_DEVICE_VENDOR, DEVICE_NAME_LENGTH, pVendor, NULL);
736 if(nState != CL_SUCCESS)
737 return;
739 aDeviceInfo.maVendor = OUString::createFromAscii(pVendor);
741 cl_ulong nMemSize;
742 nState = clGetDeviceInfo(aDeviceId, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(nMemSize), &nMemSize, NULL);
743 if(nState != CL_SUCCESS)
744 return;
746 aDeviceInfo.mnMemory = nMemSize;
748 cl_uint nClockFrequency;
749 nState = clGetDeviceInfo(aDeviceId, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(nClockFrequency), &nClockFrequency, NULL);
750 if(nState != CL_SUCCESS)
751 return;
753 aDeviceInfo.mnFrequency = nClockFrequency;
755 cl_uint nComputeUnits;
756 nState = clGetDeviceInfo(aDeviceId, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(nComputeUnits), &nComputeUnits, NULL);
757 if(nState != CL_SUCCESS)
758 return;
760 char pDriver[DEVICE_NAME_LENGTH];
761 nState = clGetDeviceInfo(aDeviceId, CL_DRIVER_VERSION, DEVICE_NAME_LENGTH, pDriver, NULL);
763 if(nState != CL_SUCCESS)
764 return;
766 aDeviceInfo.maDriver = OUString::createFromAscii(pDriver);
768 bool bKhrFp64 = false;
769 bool bAmdFp64 = false;
770 checkDeviceForDoubleSupport(aDeviceId, bKhrFp64, bAmdFp64);
772 // only list devices that support double
773 if(!bKhrFp64 && !bAmdFp64)
774 return;
776 aDeviceInfo.mnComputeUnits = nComputeUnits;
778 if(!checkForKnownBadCompilers(aDeviceInfo))
779 rPlatformInfo.maDevices.push_back(aDeviceInfo);
782 bool createPlatformInfo(cl_platform_id nPlatformId, OpenclPlatformInfo& rPlatformInfo)
784 rPlatformInfo.platform = nPlatformId;
785 char pName[64];
786 cl_int nState = clGetPlatformInfo(nPlatformId, CL_PLATFORM_NAME, 64,
787 pName, NULL);
788 if(nState != CL_SUCCESS)
789 return false;
790 rPlatformInfo.maName = OUString::createFromAscii(pName);
792 char pVendor[64];
793 nState = clGetPlatformInfo(nPlatformId, CL_PLATFORM_VENDOR, 64,
794 pVendor, NULL);
795 if(nState != CL_SUCCESS)
796 return false;
798 rPlatformInfo.maVendor = OUString::createFromAscii(pName);
800 cl_uint nDevices;
801 nState = clGetDeviceIDs(nPlatformId, CL_DEVICE_TYPE_ALL, 0, NULL, &nDevices);
802 if(nState != CL_SUCCESS)
803 return false;
805 // memory leak that does not matter
806 // memory is stored in static variable that lives through the whole program
807 cl_device_id* pDevices = new cl_device_id[nDevices];
808 nState = clGetDeviceIDs(nPlatformId, CL_DEVICE_TYPE_ALL, nDevices, pDevices, NULL);
809 if(nState != CL_SUCCESS)
810 return false;
812 for(size_t i = 0; i < nDevices; ++i)
814 createDeviceInfo(pDevices[i], rPlatformInfo);
817 return true;
822 size_t getOpenCLPlatformCount()
824 int status = clewInit(OPENCL_DLL_NAME);
825 if (status < 0)
826 return 0;
828 cl_uint nPlatforms;
829 cl_int nState = clGetPlatformIDs(0, NULL, &nPlatforms);
831 if (nState != CL_SUCCESS)
832 return 0;
834 return nPlatforms;
837 const std::vector<OpenclPlatformInfo>& fillOpenCLInfo()
839 static std::vector<OpenclPlatformInfo> aPlatforms;
840 if(!aPlatforms.empty())
841 return aPlatforms;
843 int status = clewInit(OPENCL_DLL_NAME);
844 if (status < 0)
845 return aPlatforms;
847 cl_uint nPlatforms;
848 cl_int nState = clGetPlatformIDs(0, NULL, &nPlatforms);
850 if(nState != CL_SUCCESS)
851 return aPlatforms;
853 // memory leak that does not matter,
854 // memory is stored in static instance aPlatforms
855 cl_platform_id* pPlatforms = new cl_platform_id[nPlatforms];
856 nState = clGetPlatformIDs(nPlatforms, pPlatforms, NULL);
858 if(nState != CL_SUCCESS)
859 return aPlatforms;
861 for(size_t i = 0; i < nPlatforms; ++i)
863 OpenclPlatformInfo aPlatformInfo;
864 if(createPlatformInfo(pPlatforms[i], aPlatformInfo))
865 aPlatforms.push_back(aPlatformInfo);
868 return aPlatforms;
871 namespace {
873 cl_device_id findDeviceIdByDeviceString(const OUString& rString, const std::vector<OpenclPlatformInfo>& rPlatforms)
875 std::vector<OpenclPlatformInfo>::const_iterator it = rPlatforms.begin(), itEnd = rPlatforms.end();
876 for(; it != itEnd; ++it)
878 std::vector<OpenclDeviceInfo>::const_iterator itr = it->maDevices.begin(), itrEnd = it->maDevices.end();
879 for(; itr != itrEnd; ++itr)
881 OUString aDeviceId = it->maVendor + " " + itr->maName;
882 if(rString == aDeviceId)
884 return static_cast<cl_device_id>(itr->device);
889 return NULL;
892 void findDeviceInfoFromDeviceId(cl_device_id aDeviceId, size_t& rDeviceId, size_t& rPlatformId)
894 cl_platform_id platformId;
895 cl_int nState = clGetDeviceInfo(aDeviceId, CL_DEVICE_PLATFORM,
896 sizeof(platformId), &platformId, NULL);
898 if(nState != CL_SUCCESS)
899 return;
901 const std::vector<OpenclPlatformInfo>& rPlatforms = fillOpenCLInfo();
902 for(size_t i = 0; i < rPlatforms.size(); ++i)
904 cl_platform_id platId = static_cast<cl_platform_id>(rPlatforms[i].platform);
905 if(platId != platformId)
906 continue;
908 for(size_t j = 0; j < rPlatforms[i].maDevices.size(); ++j)
910 cl_device_id id = static_cast<cl_device_id>(rPlatforms[i].maDevices[j].device);
911 if(id == aDeviceId)
913 rDeviceId = j;
914 rPlatformId = i;
915 return;
923 bool switchOpenclDevice(const OUString* pDevice, bool bAutoSelect, bool bForceEvaluation)
925 cl_device_id pDeviceId = NULL;
926 if(pDevice)
927 pDeviceId = findDeviceIdByDeviceString(*pDevice, fillOpenCLInfo());
929 if(!pDeviceId || bAutoSelect)
931 int status = clewInit(OPENCL_DLL_NAME);
932 if (status < 0)
933 return false;
935 OUString url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER "/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/");
936 rtl::Bootstrap::expandMacros(url);
937 OUString path;
938 osl::FileBase::getSystemPathFromFileURL(url,path);
939 OString dsFileName = rtl::OUStringToOString(path, RTL_TEXTENCODING_UTF8);
940 ds_device pSelectedDevice = sc::OpenCLDevice::getDeviceSelection(dsFileName.getStr(), bForceEvaluation);
941 pDeviceId = pSelectedDevice.oclDeviceID;
945 if(OpenclDevice::gpuEnv.mpDevID == pDeviceId)
947 // we don't need to change anything
948 // still the same device
949 return pDeviceId != NULL;
952 cl_platform_id platformId;
953 cl_int nState = clGetDeviceInfo(pDeviceId, CL_DEVICE_PLATFORM,
954 sizeof(platformId), &platformId, NULL);
956 cl_context_properties cps[3];
957 cps[0] = CL_CONTEXT_PLATFORM;
958 cps[1] = (cl_context_properties) platformId;
959 cps[2] = 0;
960 cl_context context = clCreateContext( cps, 1, &pDeviceId, NULL, NULL, &nState );
962 if(nState != CL_SUCCESS || context == NULL)
964 if(context != NULL)
965 clReleaseContext(context);
967 SAL_WARN("sc", "failed to set/switch opencl device");
968 return false;
971 cl_command_queue command_queue = clCreateCommandQueue(
972 context, pDeviceId, 0, &nState);
974 if(command_queue == NULL || nState != CL_SUCCESS)
976 if(command_queue != NULL)
977 clReleaseCommandQueue(command_queue);
979 clReleaseContext(context);
980 SAL_WARN("sc", "failed to set/switch opencl device");
981 return false;
984 OpenclDevice::releaseOpenclEnv(&OpenclDevice::gpuEnv);
985 OpenCLEnv env;
986 env.mpOclPlatformID = platformId;
987 env.mpOclContext = context;
988 env.mpOclDevsID = pDeviceId;
989 env.mpOclCmdQueue = command_queue;
990 OpenclDevice::initOpenclAttr(&env);
992 // why do we need this at all?
993 OpenclDevice::gpuEnv.mpArryDevsID = (cl_device_id*) malloc( sizeof(cl_device_id) );
994 OpenclDevice::gpuEnv.mpArryDevsID[0] = pDeviceId;
995 return !OpenclDevice::initOpenclRunEnv(0);
998 void getOpenCLDeviceInfo(size_t& rDeviceId, size_t& rPlatformId)
1000 int status = clewInit(OPENCL_DLL_NAME);
1001 if (status < 0)
1002 return;
1004 cl_device_id id = OpenclDevice::gpuEnv.mpDevID;
1005 findDeviceInfoFromDeviceId(id, rDeviceId, rPlatformId);
1010 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */