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 <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"
31 #define OPENCL_DLL_NAME "OpenCL.dll"
33 #define OPENCL_DLL_NAME NULL
35 #define OPENCL_DLL_NAME "libOpenCL.so"
38 #define DEVICE_NAME_LENGTH 1024
39 #define DRIVER_VERSION_LENGTH 1024
40 #define PLATFORM_VERSION_LENGTH 1024
44 namespace sc
{ namespace opencl
{
46 GPUEnv
OpenclDevice::gpuEnv
;
47 int OpenclDevice::isInited
=0;
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
);
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
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
)
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
)
104 OUString aFileName
= aFileStatus
.getFileName();
105 if(aFileName
.endsWith(".bin"))
107 if ( file is in some way obsolete
)
110 OUString aFileUrl
= aFileStatus
.getFileURL();
111 osl::File::remove(aFileUrl
);
120 OString
OpenclDevice::maCacheFolder
= getCacheFolder();
122 int OpenclDevice::releaseOpenclRunEnv()
124 releaseOpenclEnv( &gpuEnv
);
129 int OpenclDevice::registOpenclKernel()
131 if ( !gpuEnv
.mnIsUserCreated
)
132 memset( &gpuEnv
, 0, sizeof(gpuEnv
) );
137 int OpenclDevice::setKernelEnv( KernelEnv
*envInfo
)
139 envInfo
->mpkContext
= gpuEnv
.mpContext
;
140 envInfo
->mpkCmdQueue
= gpuEnv
.mpCmdQueue
;
141 envInfo
->mpkProgram
= gpuEnv
.mpArryPrograms
[0];
148 OString
createFileName(cl_device_id deviceId
, const char* clFileName
)
150 OString
fileName(clFileName
);
151 sal_Int32 nIndex
= fileName
.lastIndexOf(".cl");
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
+ "-" +
181 std::vector
<boost::shared_ptr
<osl::File
> > OpenclDevice::binaryGenerated( const char * clFileName
, cl_context context
)
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");
215 SAL_INFO("sc.opencl", "Opening binary file '" << fileName
<< "' for reading: FAIL");
222 return aGeneratedFiles
;
225 int OpenclDevice::writeBinaryToFile( const OString
& rFileName
, const char* binary
, size_t numBytes
)
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
)
235 sal_uInt64 nBytesWritten
= 0;
236 file
.write( binary
, numBytes
, nBytesWritten
);
238 assert(numBytes
== nBytesWritten
);
243 int OpenclDevice::generatBinFromKernelSource( cl_program program
, const char * clFileName
)
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
]];
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");
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
];
307 int OpenclDevice::initOpenclAttr( OpenCLEnv
* env
)
309 if ( gpuEnv
.mnIsUserCreated
)
312 gpuEnv
.mpContext
= env
->mpOclContext
;
313 gpuEnv
.mpPlatformID
= env
->mpOclPlatformID
;
314 gpuEnv
.mpDevID
= env
->mpOclDevsID
;
315 gpuEnv
.mpCmdQueue
= env
->mpOclCmdQueue
;
317 gpuEnv
.mnIsUserCreated
= 1;
322 int OpenclDevice::releaseOpenclEnv( GPUEnv
*gpuInfo
)
329 if ( gpuEnv
.mpCmdQueue
)
331 clReleaseCommandQueue( gpuEnv
.mpCmdQueue
);
332 gpuEnv
.mpCmdQueue
= NULL
;
334 if ( gpuEnv
.mpContext
)
336 clReleaseContext( gpuEnv
.mpContext
);
337 gpuEnv
.mpContext
= NULL
;
340 gpuInfo
->mnIsUserCreated
= 0;
341 free( gpuInfo
->mpArryDevsID
);
348 bool buildProgram(const char* buildOption
, GPUEnv
* gpuInfo
, int idx
)
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
);
360 clStatus
= clBuildProgram(gpuInfo
->mpArryPrograms
[idx
], 1, &(gpuInfo
->mpDevID
),
361 buildOption
, NULL
, NULL
);
364 if ( clStatus
!= CL_SUCCESS
)
367 if ( !gpuInfo
->mnIsUserCreated
)
369 clStatus
= clGetProgramBuildInfo( gpuInfo
->mpArryPrograms
[idx
], gpuInfo
->mpArryDevsID
[0],
370 CL_PROGRAM_BUILD_LOG
, 0, NULL
, &length
);
374 clStatus
= clGetProgramBuildInfo( gpuInfo
->mpArryPrograms
[idx
], gpuInfo
->mpDevID
,
375 CL_PROGRAM_BUILD_LOG
, 0, NULL
, &length
);
377 if ( clStatus
!= CL_SUCCESS
)
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
);
390 clStatus
= clGetProgramBuildInfo( gpuInfo
->mpArryPrograms
[idx
], gpuInfo
->mpDevID
,
391 CL_PROGRAM_BUILD_LOG
, length
, buildLog
.get(), &length
);
393 if ( clStatus
!= CL_SUCCESS
)
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
)
406 sal_uInt64 nBytesWritten
= 0;
407 aBuildLogFile
.write( buildLog
.get(), length
, nBytesWritten
);
417 bool OpenclDevice::buildProgramFromBinary(const char* buildOption
, GPUEnv
* gpuInfo
, const char* filename
, int idx
)
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
)
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
)
442 length
[i
] = nBytesRead
;
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
)
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
471 for(size_t i
= 0; i
< numDevices
; ++i
)
477 if ( !gpuInfo
->mpArryPrograms
[idx
] )
481 return buildProgram(buildOption
, gpuInfo
, idx
);
484 int OpenclDevice::initOpenclRunEnv( int argc
)
486 if ( MAX_CLKERNEL_NUM
<= 0 )
490 if ( ( argc
> MAX_CLFILE_NUM
) || ( argc
< 0 ) )
495 registOpenclKernel();
496 //initialize devices, context, comand_queue
497 int status
= initOpenclRunEnv( &gpuEnv
);
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");
518 SAL_INFO("sc.opencl", "USE float type");
527 void checkDeviceForDoubleSupport(cl_device_id deviceId
, bool& bKhrFp64
, bool& bAmdFp64
)
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
)
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
)
547 if ( strstr( pExtInfo
.get(), "cl_khr_fp64" ) )
553 // Check if cl_amd_fp64 extension is supported
554 if ( strstr( pExtInfo
.get(), "cl_amd_fp64" ) )
561 int OpenclDevice::initOpenclRunEnv( GPUEnv
*gpuInfo
)
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
) );
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
)
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
612 clStatus
= clGetDeviceIDs(gpuInfo
->mpPlatformID
, // platform
613 CL_DEVICE_TYPE_GPU
, // device_type for GPU device
618 if ( clStatus
!= CL_SUCCESS
)
626 if ( clStatus
!= CL_SUCCESS
)
629 if ( NULL
== gpuInfo
->mpPlatformID
)
632 // Use available platform.
633 cl_context_properties cps
[3];
634 cps
[0] = CL_CONTEXT_PLATFORM
;
635 cps
[1] = (cl_context_properties
) gpuInfo
->mpPlatformID
;
637 // Set device type for OpenCL
638 if ( getenv("SC_OPENCLCPU") )
640 gpuInfo
->mDevType
= CL_DEVICE_TYPE_CPU
;
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
) )
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 ) )
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
)
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
;
690 void OpenclDevice::setOpenclState( int state
)
695 int OpenclDevice::getOpenclState()
702 // based on crashes and hanging during kernel compilation
703 bool checkForKnownBadCompilers(const OpenclDeviceInfo
& rInfo
)
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
))
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
)
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
)
739 aDeviceInfo
.maVendor
= OUString::createFromAscii(pVendor
);
742 nState
= clGetDeviceInfo(aDeviceId
, CL_DEVICE_GLOBAL_MEM_SIZE
, sizeof(nMemSize
), &nMemSize
, NULL
);
743 if(nState
!= CL_SUCCESS
)
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
)
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
)
760 char pDriver
[DEVICE_NAME_LENGTH
];
761 nState
= clGetDeviceInfo(aDeviceId
, CL_DRIVER_VERSION
, DEVICE_NAME_LENGTH
, pDriver
, NULL
);
763 if(nState
!= CL_SUCCESS
)
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
)
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
;
786 cl_int nState
= clGetPlatformInfo(nPlatformId
, CL_PLATFORM_NAME
, 64,
788 if(nState
!= CL_SUCCESS
)
790 rPlatformInfo
.maName
= OUString::createFromAscii(pName
);
793 nState
= clGetPlatformInfo(nPlatformId
, CL_PLATFORM_VENDOR
, 64,
795 if(nState
!= CL_SUCCESS
)
798 rPlatformInfo
.maVendor
= OUString::createFromAscii(pName
);
801 nState
= clGetDeviceIDs(nPlatformId
, CL_DEVICE_TYPE_ALL
, 0, NULL
, &nDevices
);
802 if(nState
!= CL_SUCCESS
)
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
)
812 for(size_t i
= 0; i
< nDevices
; ++i
)
814 createDeviceInfo(pDevices
[i
], rPlatformInfo
);
822 size_t getOpenCLPlatformCount()
824 int status
= clewInit(OPENCL_DLL_NAME
);
829 cl_int nState
= clGetPlatformIDs(0, NULL
, &nPlatforms
);
831 if (nState
!= CL_SUCCESS
)
837 const std::vector
<OpenclPlatformInfo
>& fillOpenCLInfo()
839 static std::vector
<OpenclPlatformInfo
> aPlatforms
;
840 if(!aPlatforms
.empty())
843 int status
= clewInit(OPENCL_DLL_NAME
);
848 cl_int nState
= clGetPlatformIDs(0, NULL
, &nPlatforms
);
850 if(nState
!= CL_SUCCESS
)
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
)
861 for(size_t i
= 0; i
< nPlatforms
; ++i
)
863 OpenclPlatformInfo aPlatformInfo
;
864 if(createPlatformInfo(pPlatforms
[i
], aPlatformInfo
))
865 aPlatforms
.push_back(aPlatformInfo
);
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
);
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
)
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
)
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
);
923 bool switchOpenclDevice(const OUString
* pDevice
, bool bAutoSelect
, bool bForceEvaluation
)
925 cl_device_id pDeviceId
= NULL
;
927 pDeviceId
= findDeviceIdByDeviceString(*pDevice
, fillOpenCLInfo());
929 if(!pDeviceId
|| bAutoSelect
)
931 int status
= clewInit(OPENCL_DLL_NAME
);
935 OUString
url("${$BRAND_BASE_DIR/" LIBO_ETC_FOLDER
"/" SAL_CONFIGFILE("bootstrap") ":UserInstallation}/cache/");
936 rtl::Bootstrap::expandMacros(url
);
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
;
960 cl_context context
= clCreateContext( cps
, 1, &pDeviceId
, NULL
, NULL
, &nState
);
962 if(nState
!= CL_SUCCESS
|| context
== NULL
)
965 clReleaseContext(context
);
967 SAL_WARN("sc", "failed to set/switch opencl device");
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");
984 OpenclDevice::releaseOpenclEnv(&OpenclDevice::gpuEnv
);
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
);
1004 cl_device_id id
= OpenclDevice::gpuEnv
.mpDevID
;
1005 findDeviceInfoFromDeviceId(id
, rDeviceId
, rPlatformId
);
1010 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */