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_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