blob: 7c5673e88118921f19b5a3e3ac4d9b9f3ff933e1 [file] [log] [blame]
//
// Copyright (c) 2017 The Khronos Group Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#ifndef __KERNELARGS_H
#define __KERNELARGS_H
#ifdef __APPLE__
#include <OpenCL/opencl.h>
#else
#include <CL/cl.h>
#endif
#include <assert.h>
#include <string>
#include <vector>
#include <iostream>
#include "harness/typeWrappers.h"
#include "exceptions.h"
class WorkSizeInfo;
/**
Represents the single kernel argument information
*/
class KernelArgInfo
{
public:
cl_kernel_arg_address_qualifier getAddressQualifier() const { return m_address_qualifier; }
cl_kernel_arg_access_qualifier getAccessQualifier() const { return m_access_qualifier; }
cl_kernel_arg_type_qualifier getTypeQualifier() const { return m_type_qualifier; }
cl_kernel_arg_address_qualifier* getAddressQualifierRef() { return &m_address_qualifier; }
cl_kernel_arg_access_qualifier* getAccessQualifierRef() { return &m_access_qualifier; }
cl_kernel_arg_type_qualifier* getTypeQualifierRef() { return &m_type_qualifier; }
void setTypeName( const char* name) { m_type.assign(name); }
void setName( const char* name) { m_name.assign(name); }
std::string getTypeName() const { return m_type; }
std::string getName() const { return m_name; }
bool operator == ( const KernelArgInfo& rhs ) const
{
return !m_name.compare(rhs.m_name) &&
!m_type.compare(rhs.m_type) &&
m_address_qualifier == rhs.m_address_qualifier &&
m_access_qualifier == rhs.m_access_qualifier &&
m_type_qualifier == rhs.m_type_qualifier;
}
bool operator != ( const KernelArgInfo& rhs ) const
{
return !(*this == rhs);
}
private:
std::string m_name;
std::string m_type;
cl_kernel_arg_address_qualifier m_address_qualifier;
cl_kernel_arg_access_qualifier m_access_qualifier;
cl_kernel_arg_type_qualifier m_type_qualifier;
};
/**
Represents the single kernel's argument value.
Responsible for livekeeping of OCL objects.
*/
class KernelArg
{
public:
KernelArg(const KernelArgInfo& argInfo, void* buffer, size_t size):
m_argInfo(argInfo),
m_buffer(buffer),
m_size(size)
{}
virtual ~KernelArg()
{
align_free(m_buffer);
}
virtual size_t getArgSize() const
{
return m_size;
}
virtual const void* getBuffer() const
{
return m_buffer;
}
virtual const void* getArgValue() const
{
return m_buffer;
}
virtual bool compare( const KernelArg& rhs, float ulps ) const
{
if( m_argInfo != rhs.m_argInfo )
{
return false;
}
if( m_size != rhs.m_size)
{
return false;
}
if( (NULL == m_buffer || NULL == rhs.m_buffer) && m_buffer != rhs.m_buffer )
{
return false;
}
//check two NULL buffers case
if( NULL == m_buffer && NULL == rhs.m_buffer )
{
return true;
}
bool match = true;
if( memcmp( m_buffer, rhs.m_buffer, m_size) )
{
std::string typeName = m_argInfo.getTypeName();
size_t compared = 0;
if (typeName.compare("float*") == 0)
{
while (compared < m_size)
{
float l = *(float*)(((char*)m_buffer)+compared);
float r = *(float*)(((char*)rhs.m_buffer)+compared);
if (fabsf(Ulp_Error(l, r)) > ulps)
{
match = false;
break;
}
compared += sizeof(float);
}
}
else if (typeName.compare("double*") == 0)
{
while (compared < m_size)
{
double l = *(double*)(((char*)m_buffer)+compared);
double r = *(double*)(((char*)rhs.m_buffer)+compared);
if (fabsf(Ulp_Error_Double(l, r)) > ulps)
{
match = false;
break;
}
compared += sizeof(double);
}
}
else
{
while (compared < m_size)
{
if ( *(((char*)m_buffer)+compared) != *(((char*)rhs.m_buffer)+compared) )
{
match = false;
break;
}
compared++;
}
}
if (!match)
{
std::cerr << std::endl << " difference is at offset " << compared << std::endl;
}
}
return match;
}
virtual void readToHost(cl_command_queue queue)
{
return;
}
KernelArg* clone(cl_context context, const WorkSizeInfo& ws, const cl_kernel kernel, const cl_device_id device) const;
protected:
KernelArgInfo m_argInfo;
void* m_buffer;
size_t m_size;
};
class KernelArgSampler:public KernelArg
{
public:
KernelArgSampler(cl_context context, cl_bool isNormalized,
cl_addressing_mode addressMode, cl_filter_mode filterMode):
KernelArg(KernelArgInfo(), NULL, sizeof(cl_sampler))
{
m_argInfo.setTypeName("sampler_t");
int error = CL_SUCCESS;
m_samplerObj = clCreateSampler(context, isNormalized, addressMode,
filterMode, &error);
if( error != CL_SUCCESS )
{
throw Exceptions::TestError("clCreateSampler failed\n", error);
}
}
~KernelArgSampler()
{
//~clSamplerWrapper() releases the sampler object
}
size_t getArgSize() const
{
return sizeof(cl_sampler);
}
const void* getArgValue() const
{
return &m_samplerObj;
}
bool compare( const KernelArg& rhs ) const
{
if (const KernelArgSampler *Rhs = dynamic_cast<const KernelArgSampler*>(&rhs))
{
return isNormalized() == Rhs->isNormalized() &&
getAddressingMode() == Rhs->getAddressingMode() &&
getFilterMode() == Rhs->getFilterMode();
}
return false;
}
cl_sampler getSampler() const
{
return (cl_sampler)m_samplerObj;
}
protected:
mutable clSamplerWrapper m_samplerObj;
cl_bool isNormalized() const
{
cl_bool norm;
cl_int err = clGetSamplerInfo(getSampler(),
CL_SAMPLER_NORMALIZED_COORDS,
sizeof(cl_bool),
&norm,
NULL);
if (CL_SUCCESS != err)
throw Exceptions::TestError("clGetSamplerInfo failed\n", err);
return norm;
}
cl_addressing_mode getAddressingMode() const
{
cl_addressing_mode addressingmode;
cl_int err = clGetSamplerInfo(getSampler(),
CL_SAMPLER_ADDRESSING_MODE,
sizeof(cl_addressing_mode),
&addressingmode,
NULL);
if (CL_SUCCESS != err)
throw Exceptions::TestError("clGetSamplerInfo failed\n", err);
return addressingmode;
}
cl_filter_mode getFilterMode() const
{
cl_filter_mode filtermode;
cl_int err = clGetSamplerInfo(getSampler(),
CL_SAMPLER_FILTER_MODE,
sizeof(cl_filter_mode),
&filtermode,
NULL);
if (CL_SUCCESS != err)
throw Exceptions::TestError("clGetSamplerInfo failed\n", err);
return filtermode;
}
};
class KernelArgMemObj:public KernelArg
{
public:
KernelArgMemObj(const KernelArgInfo& argInfo, void* buffer, size_t size):
KernelArg(argInfo, buffer, size)
{
m_memObj = NULL;
}
~KernelArgMemObj()
{
//~clMemWrapper() releases the memory object
}
virtual void readToHost(cl_command_queue queue) = 0;
size_t getArgSize() const
{
if( NULL == m_buffer )
return m_size; // local buffer
else
return sizeof(cl_mem);
}
const void* getArgValue() const
{
if( NULL == m_buffer )
{
return NULL; // local buffer
}
else {
clMemWrapper* p = const_cast<clMemWrapper*>(&m_memObj);
return (const void*)(&(*p));
}
}
protected:
clMemWrapper m_memObj;
};
/**
Represents the single kernel's argument value.
Responsible for livekeeping of OCL objects.
*/
class KernelArgBuffer:public KernelArgMemObj
{
public:
KernelArgBuffer(cl_context context, const KernelArgInfo& argInfo, void* buffer, size_t size):
KernelArgMemObj(argInfo, buffer, size)
{
if( NULL != buffer )
{
int error = CL_SUCCESS;
m_memObj = clCreateBuffer(context,
CL_MEM_READ_WRITE | CL_MEM_COPY_HOST_PTR,
size, buffer, &error);
if( error != CL_SUCCESS )
{
throw Exceptions::TestError("clCreateBuffer failed\n", error);
}
}
}
void readToHost(cl_command_queue queue)
{
if( NULL == m_buffer )
{
return;
}
int error = clEnqueueReadBuffer( queue, m_memObj, CL_TRUE, 0, m_size, m_buffer, 0, NULL, NULL);
if( error != CL_SUCCESS )
{
throw Exceptions::TestError("clEnqueueReadBuffer failed\n", error);
}
}
};
class KernelArgImage:public KernelArgMemObj
{
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):
KernelArgMemObj(argInfo, buffer, size), m_desc(desc)
{
if( NULL != buffer )
{
int error = CL_SUCCESS;
flags |= CL_MEM_COPY_HOST_PTR ;
if (CL_MEM_OBJECT_IMAGE1D_BUFFER == m_desc.image_type)
{
m_desc.buffer = clCreateBuffer( context, flags, m_desc.image_row_pitch, buffer, &error );
if( error != CL_SUCCESS )
{
throw Exceptions::TestError("KernelArgImage clCreateBuffer failed\n", error);
}
buffer = NULL;
flags &= ~CL_MEM_COPY_HOST_PTR;
m_desc.image_row_pitch = 0;
m_desc.image_slice_pitch = 0;
}
m_memObj = clCreateImage( context, flags, &format, &m_desc, buffer, &error );
if( error != CL_SUCCESS )
{
throw Exceptions::TestError("KernelArgImage clCreateImage failed\n", error);
}
}
}
~KernelArgImage()
{
if (CL_MEM_OBJECT_IMAGE1D_BUFFER == m_desc.image_type)
{
clReleaseMemObject(m_desc.buffer);
}
}
void readToHost(cl_command_queue queue)
{
if( NULL == m_buffer )
{
return;
}
size_t origin[3] = {0, 0, 0};
size_t region[3] = {m_desc.image_width , m_desc.image_height , m_desc.image_depth};
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);
if( error != CL_SUCCESS )
{
throw Exceptions::TestError("clEnqueueReadImage failed\n", error);
}
}
private:
cl_image_desc m_desc;
};
/**
Represents the container for the kernel parameters
*/
class KernelArgs
{
typedef std::vector<KernelArg*> KernelsArgsVector;
public:
KernelArgs(){}
~KernelArgs()
{
KernelsArgsVector::iterator i = m_args.begin();
KernelsArgsVector::iterator e = m_args.end();
for( ; i != e; ++i )
{
assert( NULL != *i );
delete *i;
}
}
void readToHost(cl_command_queue queue)
{
KernelsArgsVector::iterator i = m_args.begin();
KernelsArgsVector::iterator e = m_args.end();
for( ; i != e; ++i )
{
(*i)->readToHost(queue);
}
}
size_t getArgCount() const { return m_args.size(); }
KernelArg* getArg(size_t index ) { return m_args[index]; }
const KernelArg* getArg(size_t index) const { return m_args[index]; }
void addArg( KernelArg* arg ) { m_args.push_back(arg); }
private:
KernelsArgsVector m_args;
};
#endif