Tool/software: Linux
I am beginning to investigate OpenCL on the AM5728. I have OpenCL working and can do basic things like vector addition. I am now interested in image processing with OpenCL. I tried to implement the same "blur" function found in this blog post: "https://anteru.net/blog/2012/11/05/2022/index.html".
I am using TI Processor SDK with Kernel 4.4.41.
When OpenCL tries to compile the kernel, it fails with CL_BUILD_PROGRAM_FAILURE ( -11 ) because of the functions "read_imagef" and "write_imagef".
Does TI OpenCL on the AM5728 not support image functions?
Error message:
Defined and initialized filter undefined first referenced symbol in file --------- ---------------- read_imagef /tmp/opencltJqDR7.obj write_imagef /tmp/opencltJqDR7.obj error #10234-D: unresolved symbols remain error #10010: errors encountered during linking; "/tmp/opencltJqDR7.out" not built >> Compilation failure OpenCL call failed with error -11
Here is the code:
/** * OCLControl::blurImage() * Purpose: Blue Image with OpenCL * * @param input is a char* representing the image to process * @param width is stride of input image * @param height is height of input image * @param depth is bit depth of input image * */ void OCLControl::blurImage(char *input, uint width, uint height, uint depth) { // Error tracking int error = -1; // Simple Gaussian blur filter float filter [] = { 1, 2, 1, 2, 4, 2, 1, 2, 1 }; // Normalize the filter for (int i = 0; i < 9; ++i) { filter [i] /= 16.0f; } #ifdef OCL_DEBUG qDebug() << "Defined and initialized filter"; #endif cl_program program = CreateProgram(QString("ocl.cl")); CheckError(clBuildProgram(program, 1, &m_DeviceId, "-D FILTER_SIZE=1", nullptr, nullptr)); #ifdef OCL_DEBUG qDebug() << "Created program"; #endif // www.khronos.org/.../clCreateKernel.html cl_kernel kernel = clCreateKernel(program, "Filter", &error); CheckError(error); #ifdef OCL_DEBUG qDebug() << "Created kernel"; #endif // Create image from DMABUF const auto image = LoadImageFromCharArray(input, width, height, depth); // www.khronos.org/.../clCreateImage2D.html static const cl_image_format format = { CL_RGBA, CL_UNORM_INT8 }; cl_mem inputImage = clCreateImage2D(m_Context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, &format, image.width, image.height, 0, // This is a bug in the spec const_cast<char*> (image.pixel.data ()), &error); CheckError(error); #ifdef OCL_DEBUG qDebug() << "Created 2D input Image"; #endif // Create output image cl_mem outputImage = clCreateImage2D(m_Context, CL_MEM_WRITE_ONLY, &format, image.width, image.height, 0, nullptr, &error); CheckError (error); #ifdef OCL_DEBUG qDebug() << "Created 2D output Image"; #endif // Create a buffer for the filter weights // www.khronos.org/.../clCreateBuffer.html cl_mem filterWeightsBuffer = clCreateBuffer(m_Context, CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR, sizeof (float) * 9, filter, &error); CheckError (error); // Setup the kernel arguments clSetKernelArg (kernel, 0, sizeof (cl_mem), &inputImage); clSetKernelArg (kernel, 1, sizeof (cl_mem), &filterWeightsBuffer); clSetKernelArg (kernel, 2, sizeof (cl_mem), &outputImage); #ifdef OCL_DEBUG qDebug() << "Set Kernel Arguments"; #endif // Run the processing // www.khronos.org/.../clEnqueueNDRangeKernel.html std::size_t offset [3] = { 0 }; std::size_t size [3] = { image.width, image.height, 1 }; CheckError(clEnqueueNDRangeKernel(m_CommandQueue, kernel, 2, offset, size, nullptr, 0, nullptr, nullptr)); // Prepare the result image, set to black Image result = image; std::fill(result.pixel.begin (), result.pixel.end (), 0); #ifdef OCL_DEBUG qDebug() << "Submitted image for processing"; #endif // Get the result back to the host std::size_t origin [3] = { 0 }; std::size_t region [3] = { result.width, result.height, 1 }; clEnqueueReadImage (m_CommandQueue, outputImage, CL_TRUE, origin, region, 0, 0, result.pixel.data(), 0, nullptr, nullptr); #ifdef OCL_DEBUG qDebug() << "Read back image"; #endif // Save for debugging SaveImage(RGBAtoRGB(result), "output.ppm"); #ifdef OCL_DEBUG qDebug() << "Saved Image as file to output"; #endif // Cleanup clReleaseMemObject(outputImage); clReleaseMemObject(filterWeightsBuffer); clReleaseMemObject(inputImage); clReleaseKernel (kernel); clReleaseProgram (program); }