Initialize libbullet git in 2.0_beta.
[platform/upstream/libbullet.git] / Extras / RigidBodyGpuPipeline / opencl / basic_initialize / btOpenCLUtils.cpp
1 /*
2 Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org
3 Copyright (C) 2006 - 2011 Sony Computer Entertainment Inc. 
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose, 
8 including commercial applications, and to alter it and redistribute it freely, 
9 subject to the following restrictions:
10
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15
16 //original author: Roman Ponomarev
17 //cleanup by Erwin Coumans
18
19 #include <string.h>
20
21 #include "btOpenCLUtils.h"
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #define BT_MAX_CL_DEVICES 16 //who needs 16 devices?
26
27 #ifdef _WIN32
28 #include <Windows.h>
29 #include <assert.h>
30
31 #define btAssert assert
32 #endif
33
34 //Set the preferred platform vendor using the OpenCL SDK
35 static char* spPlatformVendor = 
36 #if defined(CL_PLATFORM_MINI_CL)
37 "MiniCL, SCEA";
38 #elif defined(CL_PLATFORM_AMD)
39 "Advanced Micro Devices, Inc.";
40 #elif defined(CL_PLATFORM_NVIDIA)
41 "NVIDIA Corporation";
42 #elif defined(CL_PLATFORM_INTEL)
43 "Intel(R) Corporation";
44 #else
45 "Unknown Vendor";
46 #endif
47
48 #ifndef CL_PLATFORM_MINI_CL
49 #ifdef _WIN32
50 #include "CL/cl_gl.h"
51 #endif //_WIN32
52 #endif
53
54 int btOpenCLUtils::getNumPlatforms(cl_int* pErrNum)
55 {
56         cl_uint numPlatforms=0;
57         cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms);
58
59         if(ciErrNum != CL_SUCCESS)
60         {
61                 if(pErrNum != NULL) 
62                         *pErrNum = ciErrNum;
63         }
64         return numPlatforms;
65 }
66
67 const char* btOpenCLUtils::getSdkVendorName()
68 {
69         return spPlatformVendor;
70 }
71
72 cl_platform_id btOpenCLUtils::getPlatform(int platformIndex, cl_int* pErrNum)
73 {
74         cl_platform_id platform = 0;
75
76         cl_uint numPlatforms;
77         cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms);
78         
79         if (platformIndex>=0 && platformIndex<numPlatforms)
80         {
81                 cl_platform_id* platforms = new cl_platform_id[numPlatforms];
82                 ciErrNum = clGetPlatformIDs(numPlatforms, platforms, NULL);
83                 if(ciErrNum != CL_SUCCESS)
84                 {
85                         if(pErrNum != NULL) 
86                                 *pErrNum = ciErrNum;
87                         return platform;
88                 }
89
90                 platform = platforms[platformIndex];
91
92                 delete[] platforms;
93         }
94
95         return platform;
96 }
97
98 void btOpenCLUtils::getPlatformInfo(cl_platform_id platform, btOpenCLPlatformInfo& platformInfo)
99 {
100         cl_int ciErrNum;
101
102         ciErrNum = clGetPlatformInfo(   platform,CL_PLATFORM_VENDOR,BT_MAX_STRING_LENGTH,platformInfo.m_platformVendor,NULL);
103         oclCHECKERROR(ciErrNum,CL_SUCCESS);
104         ciErrNum = clGetPlatformInfo(   platform,CL_PLATFORM_NAME,BT_MAX_STRING_LENGTH,platformInfo.m_platformName,NULL);
105         oclCHECKERROR(ciErrNum,CL_SUCCESS);
106         ciErrNum = clGetPlatformInfo(   platform,CL_PLATFORM_VERSION,BT_MAX_STRING_LENGTH,platformInfo.m_platformVersion,NULL);
107         oclCHECKERROR(ciErrNum,CL_SUCCESS);
108 }
109
110 cl_context btOpenCLUtils::createContextFromPlatform(cl_platform_id platform, cl_device_type deviceType, cl_int* pErrNum, void* pGLContext, void* pGLDC, int preferredDeviceIndex, int preferredPlatformIndex)
111 {
112         cl_context retContext = 0;
113         cl_int ciErrNum=0;
114
115         /*     
116         * If we could find our platform, use it. Otherwise pass a NULL and get whatever the     
117         * implementation thinks we should be using.     
118         */
119         cl_context_properties cps[7] = {0,0,0,0,0,0,0};
120         cps[0] = CL_CONTEXT_PLATFORM;
121         cps[1] = (cl_context_properties)platform;
122         if (pGLContext && pGLDC)
123         {
124                 cps[2] = CL_GL_CONTEXT_KHR;
125                 cps[3] = (cl_context_properties)pGLContext;
126                 cps[4] = CL_WGL_HDC_KHR;
127                 cps[5] = (cl_context_properties)pGLDC;
128         }
129
130         cl_uint num_entries = BT_MAX_CL_DEVICES;
131         cl_device_id devices[BT_MAX_CL_DEVICES];
132
133         cl_uint num_devices=-1;
134
135         ciErrNum = clGetDeviceIDs(      
136                 platform,
137                 deviceType,
138                 num_entries,
139                 devices,
140                 &num_devices);
141
142         cl_context_properties* cprops = (NULL == platform) ? NULL : cps;
143
144         if (pGLContext)
145         {
146                 //search for the GPU that relates to the OpenCL context
147                 for (int i=0;i<num_devices;i++)
148                 {
149                         retContext = clCreateContext(cprops,1,&devices[i],NULL,NULL,&ciErrNum);
150                         if (ciErrNum==CL_SUCCESS)
151                                 break;
152                 }
153         }
154         else
155         {
156                 if (preferredDeviceIndex>=0 && preferredDeviceIndex<num_devices)
157                 {
158                         //create a context of the preferred device index
159                         retContext = clCreateContext(cprops,1,&devices[preferredDeviceIndex],NULL,NULL,&ciErrNum);
160                 } else
161                 {
162                         //create a context of all devices
163                         retContext = clCreateContext(cprops,num_devices,devices,NULL,NULL,&ciErrNum);
164                 }
165         }
166         if(pErrNum != NULL) 
167         {
168                 *pErrNum = ciErrNum;
169         };
170
171         return retContext;
172 }
173
174 cl_context btOpenCLUtils::createContextFromType(cl_device_type deviceType, cl_int* pErrNum, void* pGLContext, void* pGLDC , int preferredDeviceIndex, int preferredPlatformIndex)
175 {
176         cl_uint numPlatforms;
177         cl_context retContext = 0;
178         
179         cl_int ciErrNum = clGetPlatformIDs(0, NULL, &numPlatforms);
180         if(ciErrNum != CL_SUCCESS)
181         {
182                 if(pErrNum != NULL) *pErrNum = ciErrNum;
183                 return NULL;
184         }
185         if(numPlatforms > 0)     
186         {        
187                 cl_platform_id* platforms = new cl_platform_id[numPlatforms];
188                 ciErrNum = clGetPlatformIDs(numPlatforms, platforms, NULL);
189                 if(ciErrNum != CL_SUCCESS)
190                 {
191                         if(pErrNum != NULL) *pErrNum = ciErrNum;
192                         return NULL;
193                 }
194                 int i;
195
196
197                 for ( i = 0; i < numPlatforms; ++i)         
198                 {            
199                         char pbuf[128];            
200                         ciErrNum = clGetPlatformInfo(   platforms[i],
201                                 CL_PLATFORM_VENDOR,                                       
202                                 sizeof(pbuf),                                       
203                                 pbuf,                                       
204                                 NULL);
205                         if(ciErrNum != CL_SUCCESS)
206                         {
207                                 if(pErrNum != NULL) *pErrNum = ciErrNum;
208                                 return NULL;
209                         }
210
211                         if (preferredPlatformIndex>=0 && i==preferredPlatformIndex)
212                         {
213                                 cl_platform_id tmpPlatform = platforms[0];
214                                 platforms[0] = platforms[i];
215                                 platforms[i] = tmpPlatform;
216                                 break;
217                         } else
218                         {
219                                 if(!strcmp(pbuf, spPlatformVendor))
220                                 {
221                                         cl_platform_id tmpPlatform = platforms[0];
222                                         platforms[0] = platforms[i];
223                                         platforms[i] = tmpPlatform;
224                                         break;
225                                 }
226                         }
227                 }
228
229                 for (i = 0; i < numPlatforms; ++i)         
230                 {
231                         cl_platform_id platform = platforms[i];
232                         assert(platform);
233
234                         retContext = btOpenCLUtils::createContextFromPlatform(platform,deviceType,pErrNum,pGLContext,pGLDC,preferredDeviceIndex);
235
236                         if (retContext)
237                         {
238 //                              printf("OpenCL platform details:\n");
239                                 btOpenCLPlatformInfo platformInfo;
240
241                                 btOpenCLUtils::getPlatformInfo(platform, platformInfo);
242
243                                 printf("  CL_PLATFORM_VENDOR: \t\t\t%s\n",platformInfo.m_platformVendor);
244                                 printf("  CL_PLATFORM_NAME: \t\t\t%s\n",platformInfo.m_platformName);
245                                 printf("  CL_PLATFORM_VERSION: \t\t\t%s\n",platformInfo.m_platformVersion);
246
247                                 break;
248                         }
249                 }
250
251                 delete[] platforms;    
252         }
253         return retContext;
254 }
255
256
257 //////////////////////////////////////////////////////////////////////////////
258 //! Gets the id of the nth device from the context
259 //!
260 //! @return the id or -1 when out of range
261 //! @param cxMainContext         OpenCL context
262 //! @param device_idx            index of the device of interest
263 //////////////////////////////////////////////////////////////////////////////
264 cl_device_id btOpenCLUtils::getDevice(cl_context cxMainContext, int deviceIndex)
265 {
266         size_t szParmDataBytes;
267         cl_device_id* cdDevices;
268
269         // get the list of devices associated with context
270         clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, 0, NULL, &szParmDataBytes);
271
272         if( szParmDataBytes / sizeof(cl_device_id) < deviceIndex ) {
273                 return (cl_device_id)-1;
274         }
275
276         cdDevices = (cl_device_id*) malloc(szParmDataBytes);
277
278         clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, szParmDataBytes, cdDevices, NULL);
279
280         cl_device_id device = cdDevices[deviceIndex];
281         free(cdDevices);
282
283         return device;
284 }
285
286 int btOpenCLUtils::getNumDevices(cl_context cxMainContext)
287 {
288         size_t szParamDataBytes;
289         clGetContextInfo(cxMainContext, CL_CONTEXT_DEVICES, 0, NULL, &szParamDataBytes);
290         int device_count = (int) szParamDataBytes/ sizeof(cl_device_id);
291         return device_count;
292 }
293
294 void btOpenCLUtils::printDeviceInfo(cl_device_id device)
295 {
296         btOpenCLDeviceInfo info;
297         getDeviceInfo(device,info);
298
299         printf("  CL_DEVICE_NAME: \t\t\t%s\n", info.m_deviceName);
300         printf("  CL_DEVICE_VENDOR: \t\t\t%s\n", info.m_deviceVendor);
301         printf("  CL_DRIVER_VERSION: \t\t\t%s\n", info.m_driverVersion);
302
303         if( info.m_deviceType & CL_DEVICE_TYPE_CPU )
304                 printf("  CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_CPU");
305         if( info.m_deviceType & CL_DEVICE_TYPE_GPU )
306                 printf("  CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_GPU");
307         if( info.m_deviceType & CL_DEVICE_TYPE_ACCELERATOR )
308                 printf("  CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_ACCELERATOR");
309         if( info.m_deviceType & CL_DEVICE_TYPE_DEFAULT )
310                 printf("  CL_DEVICE_TYPE:\t\t\t%s\n", "CL_DEVICE_TYPE_DEFAULT");
311
312         printf("  CL_DEVICE_MAX_COMPUTE_UNITS:\t\t%u\n", info.m_computeUnits);
313         printf("  CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS:\t%u\n", info.m_workitemDims);
314         printf("  CL_DEVICE_MAX_WORK_ITEM_SIZES:\t%u / %u / %u \n", info.m_workItemSize[0], info.m_workItemSize[1], info.m_workItemSize[2]);
315         printf("  CL_DEVICE_MAX_WORK_GROUP_SIZE:\t%u\n", info.m_workgroupSize);
316         printf("  CL_DEVICE_MAX_CLOCK_FREQUENCY:\t%u MHz\n", info.m_clockFrequency);
317         printf("  CL_DEVICE_ADDRESS_BITS:\t\t%u\n", info.m_addressBits);
318         printf("  CL_DEVICE_MAX_MEM_ALLOC_SIZE:\t\t%u MByte\n", (unsigned int)(info.m_maxMemAllocSize/ (1024 * 1024)));
319         printf("  CL_DEVICE_GLOBAL_MEM_SIZE:\t\t%u MByte\n", (unsigned int)(info.m_globalMemSize/ (1024 * 1024)));
320         printf("  CL_DEVICE_ERROR_CORRECTION_SUPPORT:\t%s\n", info.m_errorCorrectionSupport== CL_TRUE ? "yes" : "no");
321         printf("  CL_DEVICE_LOCAL_MEM_TYPE:\t\t%s\n", info.m_localMemType == 1 ? "local" : "global");
322         printf("  CL_DEVICE_LOCAL_MEM_SIZE:\t\t%u KByte\n", (unsigned int)(info.m_localMemSize / 1024));
323         printf("  CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE:\t%u KByte\n", (unsigned int)(info.m_constantBufferSize / 1024));
324         if( info.m_queueProperties  & CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE )
325                 printf("  CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE");    
326         if( info.m_queueProperties & CL_QUEUE_PROFILING_ENABLE )
327                 printf("  CL_DEVICE_QUEUE_PROPERTIES:\t\t%s\n", "CL_QUEUE_PROFILING_ENABLE");
328
329         printf("  CL_DEVICE_IMAGE_SUPPORT:\t\t%u\n", info.m_imageSupport);
330
331         printf("  CL_DEVICE_MAX_READ_IMAGE_ARGS:\t%u\n", info.m_maxReadImageArgs);
332         printf("  CL_DEVICE_MAX_WRITE_IMAGE_ARGS:\t%u\n", info.m_maxWriteImageArgs);
333         printf("\n  CL_DEVICE_IMAGE <dim>"); 
334         printf("\t\t\t2D_MAX_WIDTH\t %u\n", info.m_image2dMaxWidth);
335         printf("\t\t\t\t\t2D_MAX_HEIGHT\t %u\n", info.m_image2dMaxHeight);
336         printf("\t\t\t\t\t3D_MAX_WIDTH\t %u\n", info.m_image3dMaxWidth);
337         printf("\t\t\t\t\t3D_MAX_HEIGHT\t %u\n", info.m_image3dMaxHeight);
338         printf("\t\t\t\t\t3D_MAX_DEPTH\t %u\n", info.m_image3dMaxDepth);
339         if (info.m_deviceExtensions != 0) 
340                 printf("\n  CL_DEVICE_EXTENSIONS:%s\n",info.m_deviceExtensions);
341         else 
342                 printf("  CL_DEVICE_EXTENSIONS: None\n");
343         printf("  CL_DEVICE_PREFERRED_VECTOR_WIDTH_<t>\t"); 
344         printf("CHAR %u, SHORT %u, INT %u,LONG %u, FLOAT %u, DOUBLE %u\n\n\n", 
345                 info.m_vecWidthChar, info.m_vecWidthShort, info.m_vecWidthInt, info.m_vecWidthLong,info.m_vecWidthFloat, info.m_vecWidthDouble); 
346
347
348 }
349
350 void btOpenCLUtils::getDeviceInfo(cl_device_id device, btOpenCLDeviceInfo& info)
351 {
352
353         // CL_DEVICE_NAME
354         clGetDeviceInfo(device, CL_DEVICE_NAME, BT_MAX_STRING_LENGTH, &info.m_deviceName, NULL);
355
356         // CL_DEVICE_VENDOR
357         clGetDeviceInfo(device, CL_DEVICE_VENDOR, BT_MAX_STRING_LENGTH, &info.m_deviceVendor, NULL);
358
359         // CL_DRIVER_VERSION
360         clGetDeviceInfo(device, CL_DRIVER_VERSION, BT_MAX_STRING_LENGTH, &info.m_driverVersion, NULL);
361
362         // CL_DEVICE_INFO
363         clGetDeviceInfo(device, CL_DEVICE_TYPE, sizeof(cl_device_type), &info.m_deviceType, NULL);
364
365         // CL_DEVICE_MAX_COMPUTE_UNITS
366         clGetDeviceInfo(device, CL_DEVICE_MAX_COMPUTE_UNITS, sizeof(info.m_computeUnits), &info.m_computeUnits, NULL);
367
368         // CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS
369         clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS, sizeof(info.m_workitemDims), &info.m_workitemDims, NULL);
370
371         // CL_DEVICE_MAX_WORK_ITEM_SIZES
372         clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_ITEM_SIZES, sizeof(info.m_workItemSize), &info.m_workItemSize, NULL);
373
374         // CL_DEVICE_MAX_WORK_GROUP_SIZE
375         clGetDeviceInfo(device, CL_DEVICE_MAX_WORK_GROUP_SIZE, sizeof(info.m_workgroupSize), &info.m_workgroupSize, NULL);
376
377         // CL_DEVICE_MAX_CLOCK_FREQUENCY
378         clGetDeviceInfo(device, CL_DEVICE_MAX_CLOCK_FREQUENCY, sizeof(info.m_clockFrequency), &info.m_clockFrequency, NULL);
379
380         // CL_DEVICE_ADDRESS_BITS
381         clGetDeviceInfo(device, CL_DEVICE_ADDRESS_BITS, sizeof(info.m_addressBits), &info.m_addressBits, NULL);
382
383         // CL_DEVICE_MAX_MEM_ALLOC_SIZE
384         clGetDeviceInfo(device, CL_DEVICE_MAX_MEM_ALLOC_SIZE, sizeof(info.m_maxMemAllocSize), &info.m_maxMemAllocSize, NULL);
385
386         // CL_DEVICE_GLOBAL_MEM_SIZE
387         clGetDeviceInfo(device, CL_DEVICE_GLOBAL_MEM_SIZE, sizeof(info.m_globalMemSize), &info.m_globalMemSize, NULL);
388
389         // CL_DEVICE_ERROR_CORRECTION_SUPPORT
390         clGetDeviceInfo(device, CL_DEVICE_ERROR_CORRECTION_SUPPORT, sizeof(info.m_errorCorrectionSupport), &info.m_errorCorrectionSupport, NULL);
391
392         // CL_DEVICE_LOCAL_MEM_TYPE
393         clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_TYPE, sizeof(info.m_localMemType), &info.m_localMemType, NULL);
394
395         // CL_DEVICE_LOCAL_MEM_SIZE
396         clGetDeviceInfo(device, CL_DEVICE_LOCAL_MEM_SIZE, sizeof(info.m_localMemSize), &info.m_localMemSize, NULL);
397
398         // CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE
399         clGetDeviceInfo(device, CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE, sizeof(info.m_constantBufferSize), &info.m_constantBufferSize, NULL);
400
401         // CL_DEVICE_QUEUE_PROPERTIES
402         clGetDeviceInfo(device, CL_DEVICE_QUEUE_PROPERTIES, sizeof(info.m_queueProperties), &info.m_queueProperties, NULL);
403
404         // CL_DEVICE_IMAGE_SUPPORT
405         clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(info.m_imageSupport), &info.m_imageSupport, NULL);
406
407         // CL_DEVICE_MAX_READ_IMAGE_ARGS
408         clGetDeviceInfo(device, CL_DEVICE_MAX_READ_IMAGE_ARGS, sizeof(info.m_maxReadImageArgs), &info.m_maxReadImageArgs, NULL);
409
410         // CL_DEVICE_MAX_WRITE_IMAGE_ARGS
411         clGetDeviceInfo(device, CL_DEVICE_MAX_WRITE_IMAGE_ARGS, sizeof(info.m_maxWriteImageArgs), &info.m_maxWriteImageArgs, NULL);
412
413         // CL_DEVICE_IMAGE2D_MAX_WIDTH, CL_DEVICE_IMAGE2D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_WIDTH, CL_DEVICE_IMAGE3D_MAX_HEIGHT, CL_DEVICE_IMAGE3D_MAX_DEPTH
414         clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_WIDTH, sizeof(size_t), &info.m_image2dMaxWidth, NULL);
415         clGetDeviceInfo(device, CL_DEVICE_IMAGE2D_MAX_HEIGHT, sizeof(size_t), &info.m_image2dMaxHeight, NULL);
416         clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_WIDTH, sizeof(size_t), &info.m_image3dMaxWidth, NULL);
417         clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_HEIGHT, sizeof(size_t), &info.m_image3dMaxHeight, NULL);
418         clGetDeviceInfo(device, CL_DEVICE_IMAGE3D_MAX_DEPTH, sizeof(size_t), &info.m_image3dMaxDepth, NULL);
419
420         // CL_DEVICE_EXTENSIONS: get device extensions, and if any then parse & log the string onto separate lines
421         clGetDeviceInfo(device, CL_DEVICE_EXTENSIONS, BT_MAX_STRING_LENGTH, &info.m_deviceExtensions, NULL);
422
423         // CL_DEVICE_PREFERRED_VECTOR_WIDTH_<type>
424         clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR, sizeof(cl_uint), &info.m_vecWidthChar, NULL);
425         clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT, sizeof(cl_uint), &info.m_vecWidthShort, NULL);
426         clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT, sizeof(cl_uint), &info.m_vecWidthInt, NULL);
427         clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG, sizeof(cl_uint), &info.m_vecWidthLong, NULL);
428         clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT, sizeof(cl_uint), &info.m_vecWidthFloat, NULL);
429         clGetDeviceInfo(device, CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE, sizeof(cl_uint), &info.m_vecWidthDouble, NULL);
430 }
431
432 static const char* strip2(const char* name, const char* pattern)
433 {
434           size_t const patlen = strlen(pattern);
435         size_t patcnt = 0;
436           const char * oriptr;
437           const char * patloc;
438                 // find how many times the pattern occurs in the original string
439           for (oriptr = name; patloc = strstr(oriptr, pattern); oriptr = patloc + patlen)
440           {
441                 patcnt++;
442           }
443           return oriptr;
444 }
445
446 cl_program btOpenCLUtils::compileCLProgramFromString(cl_context clContext, cl_device_id device, const char* kernelSource, cl_int* pErrNum, const char* additionalMacros , const char* clFileNameForCaching)
447 {
448
449         cl_program m_cpProgram=0;
450         cl_int status;
451
452         char binaryFileName[522];
453
454         if (clFileNameForCaching)
455         {
456                 
457                 char deviceName[256];
458                 char driverVersion[256];
459                 clGetDeviceInfo(device, CL_DEVICE_NAME, 256, &deviceName, NULL);
460                 clGetDeviceInfo(device, CL_DRIVER_VERSION, 256, &driverVersion, NULL);
461
462                 
463                 const char* strippedName = strip2(clFileNameForCaching,"\\");
464                 strippedName = strip2(strippedName,"/");
465
466                 sprintf_s(binaryFileName,"cache/%s.%s.%s.bin",strippedName, deviceName,driverVersion );
467                 //printf("searching for %s\n", binaryFileName);
468
469                 bool fileUpToDate = false;
470                 bool binaryFileValid=false;
471
472                 FILETIME modtimeBinary; 
473
474 #ifdef _WIN32
475                 CreateDirectory("cache",0);
476                 {
477                         
478                         HANDLE binaryFileHandle = CreateFile(binaryFileName,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
479                         if (binaryFileHandle ==INVALID_HANDLE_VALUE)
480                         {
481                                 DWORD errorCode;
482                                 errorCode = GetLastError();
483                                 switch (errorCode)
484                                 {
485                                 case ERROR_FILE_NOT_FOUND:
486                                         {
487                                                 printf("\nCached file not found %s\n", binaryFileName);
488                                                 break;
489                                         }
490                                 case ERROR_PATH_NOT_FOUND:
491                                         {
492                                                 printf("\nCached file path not found %s\n", binaryFileName);
493                                                 break;
494                                         }
495                                 default:
496                                         {
497                                                 printf("\nFailed reading cached file with errorCode = %d\n", errorCode);
498                                         }
499                                 }
500                         } else
501                         {
502                                 if (GetFileTime(binaryFileHandle, NULL, NULL, &modtimeBinary)==0)
503                                 {
504                                         DWORD errorCode;
505                                         errorCode = GetLastError();
506                                         printf("\nGetFileTime errorCode = %d\n", errorCode);
507                                 } else
508                                 {
509                                         binaryFileValid = true;
510                                 }
511                                 CloseHandle(binaryFileHandle);
512                         }
513
514                         if (binaryFileValid)
515                         {
516                                 HANDLE srcFileHandle = CreateFile(clFileNameForCaching,GENERIC_READ,0,0,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,0);
517                                 if (srcFileHandle!=INVALID_HANDLE_VALUE)
518                                 {
519                                         FILETIME modtimeSrc; 
520                                         if (GetFileTime(srcFileHandle, NULL, NULL, &modtimeSrc)==0)
521                                         {
522                                                 DWORD errorCode;
523                                                 errorCode = GetLastError();
524                                                 printf("\nGetFileTime errorCode = %d\n", errorCode);
525                                         }
526                                         if (  ( modtimeSrc.dwHighDateTime < modtimeBinary.dwHighDateTime)
527                                                 ||(( modtimeSrc.dwHighDateTime == modtimeBinary.dwHighDateTime)&&(modtimeSrc.dwLowDateTime <= modtimeBinary.dwLowDateTime)))
528                                         {
529                                                 fileUpToDate=true;
530                                         } else
531                                         {
532                                                 printf("\nCached binary file out-of-date (%s)\n",binaryFileName);
533                                         }
534                                         CloseHandle(srcFileHandle);
535                                 } 
536                                 else
537                                 {
538 #ifdef _DEBUG
539                                         DWORD errorCode;
540                                         errorCode = GetLastError();
541                                         switch (errorCode)
542                                         {
543                                         case ERROR_FILE_NOT_FOUND:
544                                                 {
545                                                         printf("\nSrc file not found %s\n", clFileNameForCaching);
546                                                         break;
547                                                 }
548                                         case ERROR_PATH_NOT_FOUND:
549                                                 {
550                                                         printf("\nSrc path not found %s\n", clFileNameForCaching);
551                                                         break;
552                                                 }
553                                         default:
554                                                 {
555                                                         printf("\nnSrc file reading errorCode = %d\n", errorCode);
556                                                 }
557                                         }
558
559                                         //we should make sure the src file exists so we can verify the timestamp with binary
560                                         assert(0);
561 #else
562                                         //if we cannot find the source, assume it is OK in release builds
563                                         fileUpToDate = true;
564 #endif
565                                 }
566                         }
567                         
568
569                 }
570
571                 if( fileUpToDate)
572                 {
573                         FILE* file = fopen(binaryFileName, "rb");
574                         if (file)
575                         {
576                                 fseek( file, 0L, SEEK_END );
577                                 size_t binarySize = ftell( file );
578                                 rewind( file );
579                                 char* binary = new char[binarySize];
580                                 fread( binary, sizeof(char), binarySize, file );
581                                 fclose( file );
582
583                                 m_cpProgram = clCreateProgramWithBinary( clContext, 1,&device, &binarySize, (const unsigned char**)&binary, 0, &status );
584                                 btAssert( status == CL_SUCCESS );
585                                 status = clBuildProgram( m_cpProgram, 1, &device, additionalMacros, 0, 0 );
586                                 btAssert( status == CL_SUCCESS );
587
588                                 if( status != CL_SUCCESS )
589                                 {
590                                         char *build_log;
591                                         size_t ret_val_size;
592                                         clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
593                                         build_log = new char[ret_val_size+1];
594                                         clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
595                                         build_log[ret_val_size] = '\0';
596                                         printf("%s\n", build_log);
597                                         delete build_log;
598                                         btAssert(0);
599                                         m_cpProgram = 0;
600                                 }
601                                 delete[] binary;
602                         }
603                 }
604 #endif //_WIN32
605                 
606         }
607         
608         if (!m_cpProgram)
609         {
610                 cl_kernel kernel;
611                 cl_int localErrNum;
612                 size_t program_length = strlen(kernelSource);
613
614                 m_cpProgram = clCreateProgramWithSource(clContext, 1, (const char**)&kernelSource, &program_length, &localErrNum);
615                 if (localErrNum!= CL_SUCCESS)
616                 {
617                         if (pErrNum)
618                                 *pErrNum = localErrNum;
619                         return 0;
620                 }
621
622                 // Build the program with 'mad' Optimization option
623
624
625         #ifdef MAC
626                 char* flags = "-cl-mad-enable -DMAC -DGUID_ARG";
627         #else
628                 //const char* flags = "-DGUID_ARG= -fno-alias";
629                 const char* flags = "-DGUID_ARG= ";
630         #endif
631
632                 char* compileFlags = new char[strlen(additionalMacros) + strlen(flags) + 5];
633                 sprintf(compileFlags, "%s %s", flags, additionalMacros);
634                 localErrNum = clBuildProgram(m_cpProgram, 1, &device, compileFlags, NULL, NULL);
635                 if (localErrNum!= CL_SUCCESS)
636                 {
637                         char *build_log;
638                         size_t ret_val_size;
639                         clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, 0, NULL, &ret_val_size);
640                         build_log = new char[ret_val_size+1];
641                         clGetProgramBuildInfo(m_cpProgram, device, CL_PROGRAM_BUILD_LOG, ret_val_size, build_log, NULL);
642
643                         // to be carefully, terminate with \0
644                         // there's no information in the reference whether the string is 0 terminated or not
645                         build_log[ret_val_size] = '\0';
646
647
648                         printf("Error in clBuildProgram, Line %u in file %s, Log: \n%s\n !!!\n\n", __LINE__, __FILE__, build_log);
649                         delete[] build_log;
650                         if (pErrNum)
651                                 *pErrNum = localErrNum;
652                         return 0;
653                 }
654
655                 if( clFileNameForCaching )
656                 {       //      write to binary
657
658                         cl_uint numAssociatedDevices;
659                         status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_NUM_DEVICES, sizeof(cl_uint), &numAssociatedDevices, 0 );
660                         btAssert( status == CL_SUCCESS );
661                         if (numAssociatedDevices==1)
662                         {
663
664                                 size_t binarySize;
665                                 status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_BINARY_SIZES, sizeof(size_t), &binarySize, 0 );
666                                 btAssert( status == CL_SUCCESS );
667
668                                 char* binary = new char[binarySize];
669
670                                 status = clGetProgramInfo( m_cpProgram, CL_PROGRAM_BINARIES, sizeof(char*), &binary, 0 );
671                                 btAssert( status == CL_SUCCESS );
672
673                                 {
674                                         FILE* file = fopen(binaryFileName, "wb");
675                                         if (file)
676                                         {
677                                                 fwrite( binary, sizeof(char), binarySize, file );
678                                                 fclose( file );
679                                         } else
680                                         {
681                                                 printf("cannot write file %s\n", binaryFileName);
682                                         }
683                                 }
684
685                                 delete [] binary;
686                         }
687                 }
688                 delete [] compileFlags;
689         }
690
691         return m_cpProgram;
692 }
693
694
695 cl_kernel btOpenCLUtils::compileCLKernelFromString(cl_context clContext, cl_device_id device, const char* kernelSource, const char* kernelName, cl_int* pErrNum, cl_program prog, const char* additionalMacros )
696 {
697         printf("compiling kernel %s ",kernelName);
698         cl_kernel kernel;
699         cl_int localErrNum;
700         size_t program_length = strlen(kernelSource);
701
702
703         cl_program m_cpProgram = prog;
704         if (!m_cpProgram)
705         {
706                 m_cpProgram = compileCLProgramFromString(clContext,device,kernelSource,pErrNum, additionalMacros);
707         }
708
709
710         // Create the kernel
711         kernel = clCreateKernel(m_cpProgram, kernelName, &localErrNum);
712         if (localErrNum != CL_SUCCESS)
713         {
714                 printf("Error in clCreateKernel, Line %u in file %s, cannot find kernel function %s !!!\n\n", __LINE__, __FILE__, kernelName);
715                 if (pErrNum)
716                         *pErrNum = localErrNum;
717                 return 0;
718         }
719
720         if (!prog && m_cpProgram)
721         {
722                 clReleaseProgram(m_cpProgram);
723         }
724         printf("ready. \n");
725
726
727         if (pErrNum)
728                         *pErrNum = CL_SUCCESS;
729         return kernel;
730
731 }