1 // 2 // Copyright (c) 2017 The Khronos Group Inc. 3 // 4 // Licensed under the Apache License, Version 2.0 (the "License"); 5 // you may not use this file except in compliance with the License. 6 // You may obtain a copy of the License at 7 // 8 // http://www.apache.org/licenses/LICENSE-2.0 9 // 10 // Unless required by applicable law or agreed to in writing, software 11 // distributed under the License is distributed on an "AS IS" BASIS, 12 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 // See the License for the specific language governing permissions and 14 // limitations under the License. 15 // 16 #ifndef __KERNELARGS_H 17 #define __KERNELARGS_H 18 19 20 #ifdef __APPLE__ 21 #include <OpenCL/opencl.h> 22 #else 23 #include <CL/cl.h> 24 #endif 25 26 #include <assert.h> 27 28 #include <string> 29 #include <vector> 30 #include <iostream> 31 32 #include "harness/typeWrappers.h" 33 34 #include "exceptions.h" 35 36 class WorkSizeInfo; 37 38 /** 39 Represents the single kernel argument information 40 */ 41 class KernelArgInfo 42 { 43 public: getAddressQualifier()44 cl_kernel_arg_address_qualifier getAddressQualifier() const { return m_address_qualifier; } getAccessQualifier()45 cl_kernel_arg_access_qualifier getAccessQualifier() const { return m_access_qualifier; } getTypeQualifier()46 cl_kernel_arg_type_qualifier getTypeQualifier() const { return m_type_qualifier; } 47 getAddressQualifierRef()48 cl_kernel_arg_address_qualifier* getAddressQualifierRef() { return &m_address_qualifier; } getAccessQualifierRef()49 cl_kernel_arg_access_qualifier* getAccessQualifierRef() { return &m_access_qualifier; } getTypeQualifierRef()50 cl_kernel_arg_type_qualifier* getTypeQualifierRef() { return &m_type_qualifier; } 51 setTypeName(const char * name)52 void setTypeName( const char* name) { m_type.assign(name); } setName(const char * name)53 void setName( const char* name) { m_name.assign(name); } 54 getTypeName()55 std::string getTypeName() const { return m_type; } getName()56 std::string getName() const { return m_name; } 57 58 bool operator == ( const KernelArgInfo& rhs ) const 59 { 60 return !m_name.compare(rhs.m_name) && 61 !m_type.compare(rhs.m_type) && 62 m_address_qualifier == rhs.m_address_qualifier && 63 m_access_qualifier == rhs.m_access_qualifier && 64 m_type_qualifier == rhs.m_type_qualifier; 65 } 66 67 bool operator != ( const KernelArgInfo& rhs ) const 68 { 69 return !(*this == rhs); 70 } 71 72 private: 73 std::string m_name; 74 std::string m_type; 75 cl_kernel_arg_address_qualifier m_address_qualifier; 76 cl_kernel_arg_access_qualifier m_access_qualifier; 77 cl_kernel_arg_type_qualifier m_type_qualifier; 78 }; 79 80 /** 81 Represents the single kernel's argument value. 82 Responsible for livekeeping of OCL objects. 83 */ 84 class KernelArg 85 { 86 public: KernelArg(const KernelArgInfo & argInfo,void * buffer,size_t size)87 KernelArg(const KernelArgInfo& argInfo, void* buffer, size_t size): 88 m_argInfo(argInfo), 89 m_buffer(buffer), 90 m_size(size) 91 {} 92 ~KernelArg()93 virtual ~KernelArg() 94 { 95 align_free(m_buffer); 96 } 97 getArgSize()98 virtual size_t getArgSize() const 99 { 100 return m_size; 101 } 102 getBuffer()103 virtual const void* getBuffer() const 104 { 105 return m_buffer; 106 } 107 getArgValue()108 virtual const void* getArgValue() const 109 { 110 return m_buffer; 111 } 112 compare(const KernelArg & rhs,float ulps)113 virtual bool compare( const KernelArg& rhs, float ulps ) const 114 { 115 if( m_argInfo != rhs.m_argInfo ) 116 { 117 return false; 118 } 119 120 if( m_size != rhs.m_size) 121 { 122 return false; 123 } 124 125 if( (NULL == m_buffer || NULL == rhs.m_buffer) && m_buffer != rhs.m_buffer ) 126 { 127 return false; 128 } 129 130 //check two NULL buffers case 131 if( NULL == m_buffer && NULL == rhs.m_buffer ) 132 { 133 return true; 134 } 135 136 bool match = true; 137 if( memcmp( m_buffer, rhs.m_buffer, m_size) ) 138 { 139 std::string typeName = m_argInfo.getTypeName(); 140 size_t compared = 0; 141 if (typeName.compare("float*") == 0) 142 { 143 while (compared < m_size) 144 { 145 float l = *(float*)(((char*)m_buffer)+compared); 146 float r = *(float*)(((char*)rhs.m_buffer)+compared); 147 if (fabsf(Ulp_Error(l, r)) > ulps) 148 { 149 match = false; 150 break; 151 } 152 compared += sizeof(float); 153 } 154 } 155 else if (typeName.compare("double*") == 0) 156 { 157 while (compared < m_size) 158 { 159 double l = *(double*)(((char*)m_buffer)+compared); 160 double r = *(double*)(((char*)rhs.m_buffer)+compared); 161 if (fabsf(Ulp_Error_Double(l, r)) > ulps) 162 { 163 match = false; 164 break; 165 } 166 compared += sizeof(double); 167 } 168 } 169 else 170 { 171 while (compared < m_size) 172 { 173 if ( *(((char*)m_buffer)+compared) != *(((char*)rhs.m_buffer)+compared) ) 174 { 175 match = false; 176 break; 177 } 178 compared++; 179 } 180 } 181 if (!match) 182 { 183 std::cerr << std::endl << " difference is at offset " << compared << std::endl; 184 } 185 } 186 187 return match; 188 } 189 readToHost(cl_command_queue queue)190 virtual void readToHost(cl_command_queue queue) 191 { 192 return; 193 } 194 195 KernelArg* clone(cl_context context, const WorkSizeInfo& ws, const cl_kernel kernel, const cl_device_id device) const; 196 197 protected: 198 KernelArgInfo m_argInfo; 199 void* m_buffer; 200 size_t m_size; 201 }; 202 203 class KernelArgSampler:public KernelArg 204 { 205 public: KernelArgSampler(cl_context context,cl_bool isNormalized,cl_addressing_mode addressMode,cl_filter_mode filterMode)206 KernelArgSampler(cl_context context, cl_bool isNormalized, 207 cl_addressing_mode addressMode, cl_filter_mode filterMode): 208 KernelArg(KernelArgInfo(), NULL, sizeof(cl_sampler)) 209 { 210 m_argInfo.setTypeName("sampler_t"); 211 int error = CL_SUCCESS; 212 m_samplerObj = clCreateSampler(context, isNormalized, addressMode, 213 filterMode, &error); 214 if( error != CL_SUCCESS ) 215 { 216 throw Exceptions::TestError("clCreateSampler failed\n", error); 217 } 218 } 219 ~KernelArgSampler()220 ~KernelArgSampler() 221 { 222 //~clSamplerWrapper() releases the sampler object 223 } 224 getArgSize()225 size_t getArgSize() const 226 { 227 return sizeof(cl_sampler); 228 } 229 getArgValue()230 const void* getArgValue() const 231 { 232 return &m_samplerObj; 233 } 234 compare(const KernelArg & rhs)235 bool compare( const KernelArg& rhs ) const 236 { 237 if (const KernelArgSampler *Rhs = dynamic_cast<const KernelArgSampler*>(&rhs)) 238 { 239 return isNormalized() == Rhs->isNormalized() && 240 getAddressingMode() == Rhs->getAddressingMode() && 241 getFilterMode() == Rhs->getFilterMode(); 242 } 243 return false; 244 } 245 getSampler()246 cl_sampler getSampler() const 247 { 248 return (cl_sampler)m_samplerObj; 249 } 250 251 protected: 252 mutable clSamplerWrapper m_samplerObj; 253 isNormalized()254 cl_bool isNormalized() const 255 { 256 cl_bool norm; 257 cl_int err = clGetSamplerInfo(getSampler(), 258 CL_SAMPLER_NORMALIZED_COORDS, 259 sizeof(cl_bool), 260 &norm, 261 NULL); 262 if (CL_SUCCESS != err) 263 throw Exceptions::TestError("clGetSamplerInfo failed\n", err); 264 return norm; 265 } 266 getAddressingMode()267 cl_addressing_mode getAddressingMode() const 268 { 269 cl_addressing_mode addressingmode; 270 cl_int err = clGetSamplerInfo(getSampler(), 271 CL_SAMPLER_ADDRESSING_MODE, 272 sizeof(cl_addressing_mode), 273 &addressingmode, 274 NULL); 275 if (CL_SUCCESS != err) 276 throw Exceptions::TestError("clGetSamplerInfo failed\n", err); 277 return addressingmode; 278 } 279 getFilterMode()280 cl_filter_mode getFilterMode() const 281 { 282 cl_filter_mode filtermode; 283 cl_int err = clGetSamplerInfo(getSampler(), 284 CL_SAMPLER_FILTER_MODE, 285 sizeof(cl_filter_mode), 286 &filtermode, 287 NULL); 288 if (CL_SUCCESS != err) 289 throw Exceptions::TestError("clGetSamplerInfo failed\n", err); 290 return filtermode; 291 } 292 293 }; 294 295 296 class KernelArgMemObj:public KernelArg 297 { 298 public: KernelArgMemObj(const KernelArgInfo & argInfo,void * buffer,size_t size)299 KernelArgMemObj(const KernelArgInfo& argInfo, void* buffer, size_t size): 300 KernelArg(argInfo, buffer, size) 301 { 302 m_memObj = NULL; 303 } 304 ~KernelArgMemObj()305 ~KernelArgMemObj() 306 { 307 //~clMemWrapper() releases the memory object 308 } 309 310 virtual void readToHost(cl_command_queue queue) = 0; 311 312 getArgSize()313 size_t getArgSize() const 314 { 315 if( NULL == m_buffer ) 316 return m_size; // local buffer 317 else 318 return sizeof(cl_mem); 319 } 320 getArgValue()321 const void* getArgValue() const 322 { 323 if( NULL == m_buffer ) 324 { 325 return NULL; // local buffer 326 } 327 else { 328 clMemWrapper* p = const_cast<clMemWrapper*>(&m_memObj); 329 330 return (const void*)(&(*p)); 331 } 332 } 333 334 protected: 335 clMemWrapper m_memObj; 336 }; 337 338 /** 339 Represents the single kernel's argument value. 340 Responsible for livekeeping of OCL objects. 341 */ 342 class KernelArgBuffer:public KernelArgMemObj 343 { 344 public: KernelArgBuffer(cl_context context,const KernelArgInfo & argInfo,void * buffer,size_t size)345 KernelArgBuffer(cl_context context, const KernelArgInfo& argInfo, void* buffer, size_t size): 346 KernelArgMemObj(argInfo, buffer, size) 347 { 348 if( NULL != buffer ) 349 { 350 int error = CL_SUCCESS; 351 m_memObj = clCreateBuffer( context, 352 (cl_mem_flags)( CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR ), 353 size, buffer, &error ); 354 if( error != CL_SUCCESS ) 355 { 356 throw Exceptions::TestError("clCreateBuffer failed\n", error); 357 } 358 } 359 } 360 readToHost(cl_command_queue queue)361 void readToHost(cl_command_queue queue) 362 { 363 if( NULL == m_buffer ) 364 { 365 return; 366 } 367 368 int error = clEnqueueReadBuffer( queue, m_memObj, CL_TRUE, 0, m_size, m_buffer, 0, NULL, NULL); 369 if( error != CL_SUCCESS ) 370 { 371 throw Exceptions::TestError("clEnqueueReadBuffer failed\n", error); 372 } 373 } 374 }; 375 376 class KernelArgImage:public KernelArgMemObj 377 { 378 public: KernelArgImage(cl_context context,const KernelArgInfo & argInfo,void * buffer,size_t size,cl_mem_flags flags,cl_image_format format,cl_image_desc desc)379 KernelArgImage(cl_context context, const KernelArgInfo& argInfo, 380 void* buffer, size_t size, cl_mem_flags flags, 381 cl_image_format format, cl_image_desc desc): 382 KernelArgMemObj(argInfo, buffer, size), m_desc(desc) 383 { 384 if( NULL != buffer ) 385 { 386 int error = CL_SUCCESS; 387 flags |= CL_MEM_COPY_HOST_PTR ; 388 if (CL_MEM_OBJECT_IMAGE1D_BUFFER == m_desc.image_type) 389 { 390 m_desc.buffer = clCreateBuffer( context, flags, m_desc.image_row_pitch, buffer, &error ); 391 if( error != CL_SUCCESS ) 392 { 393 throw Exceptions::TestError("KernelArgImage clCreateBuffer failed\n", error); 394 } 395 buffer = NULL; 396 flags &= ~CL_MEM_COPY_HOST_PTR; 397 m_desc.image_row_pitch = 0; 398 m_desc.image_slice_pitch = 0; 399 } 400 m_memObj = clCreateImage( context, flags, &format, &m_desc, buffer, &error ); 401 if( error != CL_SUCCESS ) 402 { 403 throw Exceptions::TestError("KernelArgImage clCreateImage failed\n", error); 404 } 405 } 406 } 407 ~KernelArgImage()408 ~KernelArgImage() 409 { 410 if (CL_MEM_OBJECT_IMAGE1D_BUFFER == m_desc.image_type) 411 { 412 clReleaseMemObject(m_desc.buffer); 413 } 414 } 415 readToHost(cl_command_queue queue)416 void readToHost(cl_command_queue queue) 417 { 418 if( NULL == m_buffer ) 419 { 420 return; 421 } 422 423 size_t origin[3] = {0, 0, 0}; 424 size_t region[3] = {m_desc.image_width , m_desc.image_height , m_desc.image_depth}; 425 426 int error = clEnqueueReadImage (queue, m_memObj, CL_TRUE, origin, region, m_desc.image_row_pitch, m_desc.image_slice_pitch, m_buffer, 0, NULL, NULL); 427 428 if( error != CL_SUCCESS ) 429 { 430 throw Exceptions::TestError("clEnqueueReadImage failed\n", error); 431 } 432 } 433 434 private: 435 cl_image_desc m_desc; 436 }; 437 438 /** 439 Represents the container for the kernel parameters 440 */ 441 class KernelArgs 442 { 443 typedef std::vector<KernelArg*> KernelsArgsVector; 444 public: KernelArgs()445 KernelArgs(){} ~KernelArgs()446 ~KernelArgs() 447 { 448 KernelsArgsVector::iterator i = m_args.begin(); 449 KernelsArgsVector::iterator e = m_args.end(); 450 451 for( ; i != e; ++i ) 452 { 453 assert( NULL != *i ); 454 delete *i; 455 } 456 } 457 readToHost(cl_command_queue queue)458 void readToHost(cl_command_queue queue) 459 { 460 KernelsArgsVector::iterator i = m_args.begin(); 461 KernelsArgsVector::iterator e = m_args.end(); 462 463 for( ; i != e; ++i ) 464 { 465 (*i)->readToHost(queue); 466 } 467 } 468 getArgCount()469 size_t getArgCount() const { return m_args.size(); } 470 getArg(size_t index)471 KernelArg* getArg(size_t index ) { return m_args[index]; } 472 getArg(size_t index)473 const KernelArg* getArg(size_t index) const { return m_args[index]; } 474 addArg(KernelArg * arg)475 void addArg( KernelArg* arg ) { m_args.push_back(arg); } 476 477 private: 478 KernelsArgsVector m_args; 479 }; 480 481 #endif 482