cancel
Showing results for 
Search instead for 
Did you mean: 

Archives Discussions

Error in clCopyImagetoBuffer

I want to copy all the contents of an input image to a buffer so that I can do further processing on it...the command looks lyk

clEnqueueCopyImageToBuffer (cl_command_queue command_queue,cl_mem src_image,cl_mem dst_buffer,const size_t src_origin[3],

                                                   const size_t region[3], size_t dst_offset,  cl_uint num_events_in_wait_list,const cl_event *event_wait_list,  cl_event *event)

     

      and in my code the command looks as follows...

errNum= clEnqueueCopyImageToBuffer ( commandQueue,  imageObjects[0] ,memObject,origin,

                                                                  region,0, NULL,NULL,NULL);

I get an error saying Image cant be copied...!

what is exactly to be written in place of size_t dst_offset...? please tell the exact syntax for it, if my buffer size is 4*width*height*sizeof(char), or just putting zero at that place will do o no...?

0 Likes
1 Solution

Yes, You got it right. You had not allocated your memObject.

Regarding your other question -- this is where command queue comes into place. CQ (command queue) is in-order usually unless you have explicitly enabled an out-of-order processing in the CQ. Currently, in AMD platforms, CQs are always in-order regardless of whether you enable out of order processing or not.

The sequence of buffer copies and kernel enqueue operation are all dictated by the application.

Creation of kernel object has no bearing on the copies.

You are free to do in any order that you like.

However, if you want to enqueue a kernel that will use a certain buffer -- then it is logical that you enqueue a copy and initialze the buffer before you enqueue the kernel. The order should be maintained in the command queue. Thats all.

Hope this is clear,

View solution in original post

0 Likes
12 Replies
himanshu_gautam
Grandmaster

Please post your code here.

Also, you can use "0" for numEventsInWaitList instead of NULL.

NULL is usually used to denote null pointers.

This is the code, I have marked the part in which I am getting error in bold....

#include <iostream>

#include <fstream>

#include <sstream>

#include <string.h>

#ifdef __APPLE__

#include <OpenCL/cl.h>

#else

#include <CL/cl.h>

#endif

#include "FreeImage.h"

///

//  Create an OpenCL context on the first available platform using

//  either a GPU or CPU depending on what is available.

//

cl_context CreateContext()

{

    cl_int errNum;

    cl_uint numPlatforms;

    cl_platform_id firstPlatformId;

    cl_context context = NULL;

    // First, select an OpenCL platform to run on.  For this example, we

    // simply choose the first available platform.  Normally, you would

    // query for all available platforms and select the most appropriate one.

    errNum = clGetPlatformIDs(1, &firstPlatformId, &numPlatforms);

    if (errNum != CL_SUCCESS || numPlatforms <= 0)

    {

        std::cerr << "Failed to find any OpenCL platforms." << std::endl;

        return NULL;

    }

    // Next, create an OpenCL context on the platform.  Attempt to

    // create a GPU-based context, and if that fails, try to create

    // a CPU-based context.

    cl_context_properties contextProperties[] =

    {

        CL_CONTEXT_PLATFORM,

        (cl_context_properties)firstPlatformId,

        0

    };

    context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_GPU,

                                      NULL, NULL, &errNum);

    if (errNum != CL_SUCCESS)

    {

        std::cout << "Could not create GPU context, trying CPU..." << std::endl;

        context = clCreateContextFromType(contextProperties, CL_DEVICE_TYPE_CPU,

                                          NULL, NULL, &errNum);

        if (errNum != CL_SUCCESS)

        {

            std::cerr << "Failed to create an OpenCL GPU or CPU context." << std::endl;

            return NULL;

        }

    }

    return context;

}

///

//  Create a command queue on the first device available on the

//  context

//

cl_command_queue CreateCommandQueue(cl_context context, cl_device_id *device)

{

    cl_int errNum;

    cl_device_id *devices;

    cl_command_queue commandQueue = NULL;

    size_t deviceBufferSize = -1;

    // First get the size of the devices buffer

    errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, 0, NULL, &deviceBufferSize);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Failed call to clGetContextInfo(...,GL_CONTEXT_DEVICES,...)";

        return NULL;

    }

    if (deviceBufferSize <= 0)

    {

        std::cerr << "No devices available.";

        return NULL;

    }

    // Allocate memory for the devices buffer

    devices = new cl_device_id[deviceBufferSize / sizeof(cl_device_id)];

    errNum = clGetContextInfo(context, CL_CONTEXT_DEVICES, deviceBufferSize, devices, NULL);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Failed to get device IDs";

        return NULL;

    }

    // In this example, we just choose the first available device.  In a

    // real program, you would likely use all available devices or choose

    // the highest performance device based on OpenCL device queries

    commandQueue = clCreateCommandQueue(context, devices[0], 0, NULL);

    if (commandQueue == NULL)

    {

        std::cerr << "Failed to create commandQueue for device 0";

        return NULL;

    }

    *device = devices[0];

    delete [] devices;

    return commandQueue;

}

///

//  Create an OpenCL program from the kernel source file

//

cl_program CreateProgram(cl_context context, cl_device_id device, const char* fileName)

{

    cl_int errNum;

    cl_program program;

    std::ifstream kernelFile(fileName, std::ios::in);

    if (!kernelFile.is_open())

    {

        std::cerr << "Failed to open file for reading: " << fileName << std::endl;

        return NULL;

    }

    std::ostringstream oss;

    oss << kernelFile.rdbuf();

    std::string srcStdStr = oss.str();

    const char *srcStr = srcStdStr.c_str();

    program = clCreateProgramWithSource(context, 1,

                                        (const char**)&srcStr,

                                        NULL, NULL);

    if (program == NULL)

    {

        std::cerr << "Failed to create CL program from source." << std::endl;

        return NULL;

    }

    errNum = clBuildProgram(program, 0, NULL, NULL, NULL, NULL);

    if (errNum != CL_SUCCESS)

    {

        // Determine the reason for the error

        char buildLog[16384];

        clGetProgramBuildInfo(program, device, CL_PROGRAM_BUILD_LOG,

                              sizeof(buildLog), buildLog, NULL);

        std::cerr << "Error in kernel: " << std::endl;

        std::cerr << buildLog;

        clReleaseProgram(program);

        return NULL;

    }

    return program;

}

///

//  Cleanup any created OpenCL resources

//

void Cleanup(cl_context context, cl_command_queue commandQueue,

             cl_program program, cl_kernel kernel, cl_mem imageObjects[2],

             cl_sampler sampler, cl_mem *memObject)

{

    for (int i = 0; i < 2; i++)

    {

        if (imageObjects != 0)

            clReleaseMemObject(imageObjects);

    }

    if (commandQueue != 0)

        clReleaseCommandQueue(commandQueue);

    if (kernel != 0)

        clReleaseKernel(kernel);

    if (program != 0)

        clReleaseProgram(program);

    if (sampler != 0)

        clReleaseSampler(sampler);

    if (context != 0)

        clReleaseContext(context);

          if(*memObject!=0)

                    clReleaseMemObject(*memObject);

}

///

//  Load an image using the FreeImage library and create an OpenCL

//  image out of it

//

cl_mem LoadImage(cl_context context, char *fileName, int &width, int &height)

{

    FREE_IMAGE_FORMAT format = FreeImage_GetFileType(fileName, 0);

    FIBITMAP* image = FreeImage_Load(format, fileName);

    // Convert to 32-bit image

    FIBITMAP* temp = image;

    image = FreeImage_ConvertTo32Bits(image);

    FreeImage_Unload(temp);

    width = FreeImage_GetWidth(image);

    height = FreeImage_GetHeight(image);

    char *buffer = new char[width * height * 4];

    memcpy(buffer, FreeImage_GetBits(image), width * height * 4);

    FreeImage_Unload(image);

    // Create OpenCL image

    cl_image_format clImageFormat;

    clImageFormat.image_channel_order = CL_RGBA;

    clImageFormat.image_channel_data_type = CL_UNORM_INT8;

    cl_int errNum;

    cl_mem clImage;

    clImage = clCreateImage2D(context,

                            CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,

                            &clImageFormat,

                            width,

                            height,

                            0,

                            buffer,

                            &errNum);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error creating CL image object" << std::endl;

        return 0;

    }

    return clImage;

}

///

//  Save an image using the FreeImage library

//

bool SaveImage(char *fileName, char *buffer, int width, int height)

{

    FREE_IMAGE_FORMAT format = FreeImage_GetFIFFromFilename(fileName);

    FIBITMAP *image = FreeImage_ConvertFromRawBits((BYTE*)buffer, width,

                        height, width * 4, 32,

                        0xFF000000, 0x00FF0000, 0x0000FF00);

    return (FreeImage_Save(format, image, fileName) == TRUE) ? true : false;

}

bool CreateMemObjects(cl_command_queue commandQueue,cl_context context, cl_mem *memObject,int width, int height)

{

 

   *memObject = clCreateBuffer(context, CL_MEM_READ_WRITE,

                                   sizeof(char) * width*height*4, NULL, NULL);

  

    if (*memObject == NULL )

    {

        std::cerr << "Error creating memory objects." << std::endl;

        return false;

    }

    return true;

}

///

//  Round up to the nearest multiple of the group size

//

size_t RoundUp(int groupSize, int globalSize)

{

    int r = globalSize % groupSize;

    if(r == 0)

    {

        return globalSize;

    }

    else

    {

        return globalSize + groupSize - r;

    }

}

///

//      main() for HelloBinaryWorld example

//

int main(int argc, char** argv)

{

    cl_context context = 0;

    cl_command_queue commandQueue = 0;

    cl_program program = 0;

    cl_device_id device = 0;

    cl_kernel kernel = 0;

    cl_mem imageObjects[2] = { 0, 0 };

          cl_mem memObject= 0;

    cl_sampler sampler = 0;

    cl_int errNum;

  //  if (argc != 3)

    //{

   //     std::cerr << "USAGE: " << argv[0] << " <inputImageFile> <outputImageFiles>" << std::endl;

//                    system("pause");

//       return 1;

  //  }

//     Create an OpenCL context on first available platform

    context = CreateContext();

    if (context == NULL)

    {

        std::cerr << "Failed to create OpenCL context." << std::endl;

        return 1;

    }

    // Create a command-queue on the first device available

    // on the created context

    commandQueue = CreateCommandQueue(context, &device);

    if (commandQueue == NULL)

    {

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    // Make sure the device supports images, otherwise exit

    cl_bool imageSupport = CL_FALSE;

    clGetDeviceInfo(device, CL_DEVICE_IMAGE_SUPPORT, sizeof(cl_bool),

                    &imageSupport, NULL);

    if (imageSupport != CL_TRUE)

    {

        std::cerr << "OpenCL device does not support images." << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    // Load input image from file and load it into

    // an OpenCL image object

    int width, height;

          // size_t origin[3] = { 0, 0, 0 };

//size_t region[3] = { width, height, 1};

    imageObjects[0] = LoadImage(context,"C:\\Users\\Shreedhar\\Documents\\Visual Studio 2010\\Projects\\ImageFilter3\\lena.bmp", width, height);

    if (imageObjects[0] == 0)

    {

        std::cerr << "Error loading: " << std::string("lena") << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        system("Pause");

                    return 1;

    }

 

    // Create ouput image object

    cl_image_format clImageFormat;

    clImageFormat.image_channel_order = CL_RGBA;

    clImageFormat.image_channel_data_type = CL_UNORM_INT8;

    imageObjects[1] = clCreateImage2D(context,

                                       CL_MEM_WRITE_ONLY,

                                       &clImageFormat,

                                       width,

                                       height,

                                       0,

                                       NULL,

                                       &errNum);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error creating CL output image object." << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    // Create sampler for sampling image object

    sampler = clCreateSampler(context,

                              CL_FALSE, // Non-normalized coordinates

                              CL_ADDRESS_CLAMP_TO_EDGE,

                              CL_FILTER_NEAREST,

                              &errNum);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error creating CL sampler object." << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    // Create OpenCL program

    program = CreateProgram(context, device, "ImageFilter2D.cl");

    if (program == NULL)

    {

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    // Create OpenCL kernel

    kernel = clCreateKernel(program, "gaussian_filter", NULL);

    if (kernel == NULL)

    {

        std::cerr << "Failed to create kernel" << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    // Set the kernel arguments

    errNum = clSetKernelArg(kernel, 0, sizeof(cl_mem), &imageObjects[0]);

    errNum |= clSetKernelArg(kernel, 1, sizeof(cl_mem), &imageObjects[1]);

    errNum |= clSetKernelArg(kernel, 2, sizeof(cl_sampler), &sampler);

    errNum |= clSetKernelArg(kernel, 3, sizeof(cl_int), &width);

    errNum |= clSetKernelArg(kernel, 4, sizeof(cl_int), &height);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error setting kernel arguments." << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    size_t localWorkSize[2] = { 16, 16 };

    size_t globalWorkSize[2] =  { RoundUp(localWorkSize[0], width),

                                  RoundUp(localWorkSize[1], height) };

    // Queue the kernel up for execution

    errNum = clEnqueueNDRangeKernel(commandQueue, kernel, 2, NULL,

                                    globalWorkSize, localWorkSize,

                                    0, NULL, NULL);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error queuing kernel for execution." << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

    // Read the output buffer back to the Host

    char *buffer = new char [width * height * 4];

char *result;

           result= (char*)malloc(sizeof(char)*4*width*height);

               size_t origin[3] = { 0, 0, 0 };

    size_t region[3] = { width, height, 1};

 

          errNum= clEnqueueCopyImageToBuffer ( commandQueue,  imageObjects[0] ,memObject,origin,

                    region,0, NULL,NULL,NULL);

if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error in copying Image to buffer." << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

errNum = clEnqueueReadBuffer(commandQueue, memObject, CL_TRUE,

                                 0,4*width*height * sizeof(char), result,

                                 0, NULL, NULL);

if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error reading result buffer." << std::endl;

  Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

//  for (unsigned int i = 0; i < 4*width*height; i++)

  //  {

  //      std::cout << result << std::endl;

   // } 

    errNum = clEnqueueReadImage(commandQueue, imageObjects[1], CL_TRUE,

                                origin, region, 0, 0, buffer,

                                0, NULL, NULL);

    if (errNum != CL_SUCCESS)

    {

        std::cerr << "Error reading result buffer." << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        return 1;

    }

           for ( int i = 0; i < 4*width*height; i++)

      {

        std::cout << i<<"="<<buffer << std::endl;

      }

    std::cout << std::endl;

    std::cout << "Executed program succesfully." << std::endl;

    //memset(buffer, 0xff, width * height * 4);

    // Save the image out to disk

    if (!SaveImage("C:\\Users\\Shreedhar\\Documents\\Visual Studio 2010\\Projects\\ImageFilter3\\lenaout.bmp", buffer, width, height))

    {

        std::cerr << "Error writing output image: " <<"lenaout.bmp" << std::endl;

        Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

        delete [] buffer;

        return 1;

    }

    delete [] buffer;

    Cleanup(context, commandQueue, program, kernel, imageObjects, sampler,&memObject);

    return 0;

}

0 Likes

Oh, I got the error, I had not created the memory object buffer in which I was to store the Image contents... ie "memObject"

... but still I have a doubt that exists... can't we give the commands like clCopyImagetoBuffer or clEnqueueReadBuffer before even the kernel is created or just before enqueueing the kernel..??? Please answer this doubt.... Its not clear to me...! Cause I had done this before making changes in the above code and it gave error...!  if you want  I will post that code too...!

0 Likes

Please answer my doubt...

0 Likes

Yes, You got it right. You had not allocated your memObject.

Regarding your other question -- this is where command queue comes into place. CQ (command queue) is in-order usually unless you have explicitly enabled an out-of-order processing in the CQ. Currently, in AMD platforms, CQs are always in-order regardless of whether you enable out of order processing or not.

The sequence of buffer copies and kernel enqueue operation are all dictated by the application.

Creation of kernel object has no bearing on the copies.

You are free to do in any order that you like.

However, if you want to enqueue a kernel that will use a certain buffer -- then it is logical that you enqueue a copy and initialze the buffer before you enqueue the kernel. The order should be maintained in the command queue. Thats all.

Hope this is clear,

0 Likes

Hey Himanshu,

  I understood what uve said and implemented the code by specifying clCopyImagetoBuffer before the kernel creation and it worked... but I dint understand what you meant by last line... "order should be maintained in the command queue"... does this order mean the order in which we right the code or does it mean something else...?  Because nowhere in the code we give the order to the command queue specifically....! please explain what do you mean exactly by your last line...!

0 Likes

I have one more doubt... after getting the image contents into the buffer, I made the buffer to be read on the host memory and printed the buffer, it prints some character values... It should have given the intensity values instead, cause I need the pixel intensity values for further processing( eg : sorting the pixel values, doing arithmetic on it to generate a graph etc)... how to get the pixel values then.... or is it that I should use this buffer as it is and give the buffer memObject as the argument to the kernel... will the work get done automatically...?

0 Likes

please answer the doubts as soon as possible...!

0 Likes

Order --> Order of enqeue operations to the command queue. This can be maintained only if you code it in the right order 🙂

Printing --> Use printf "%d" or "%x" to print in decimal or hexa-decimal. What is output on the screen, depends on how you interpret the format (as character or as number etc..)

Kernel -> Pass the buffer as argument to the kernel. There in - you can either read or write into it -- depending on what you want.... Map the buffer back in Host memory and then read the output.

k...  I printed it in decimal form... but i am getting some values negative... how is it possible..? cause pixel intensity range is just 0 to 255...!

0 Likes

"%d" will print a signed integer. Take a byte. It has 8 bits. It can represent 256 values - 0 to 255.

However, if it is signed, it will interpret the values from 0 to 127 as +ve numbers, 128 to 255 as -ve numbers.

You can try "%u"

0 Likes

I tried "%u", but for many values i am getting a 10 digit number, Is it a garbage value...?

and how are these intensities arranged in the buffer, I mean is it  R,,G, B of the first position in a sequence  , then the R G  B of the next or is it R values of all position first then the G and then B...?

0 Likes