I am having difficulty in sending data of type CL_HALF_FLOAT to an AMD HD 7990 GPU.
Currently I am reading a .exr file using OpenEXR and storing the data in a buffer named 'pixels'.
// http://www.openexr.com/ReadingAndWritingImageFiles.pdf
Imf::Array2D<Imf::Rgba> pixels; // Input image buffer
try{
std::string fileName = resourcesDirectory + "Input/tunnel/00000.exr"; // Read in test file
std::cout << "Reading " << fileName << std::endl;
Imf::RgbaInputFile file(fileName.c_str()); // Constructor opens the file and reads the files header - dataWindow
Imath::Box2i dataWindow = file.dataWindow(); // File's data window
imageWidth = dataWindow.max.x - dataWindow.min.x + 1; // Width of image
imageHeight = dataWindow.max.y - dataWindow.min.y + 1; // Height of image
pixels.resizeErase(imageHeight, imageWidth); // Performs allocation
// Tell the RgbaInputFile object how to access individual pixels in the buffer
file.setFrameBuffer(&pixels[0][0] - dataWindow.min.x - dataWindow.min.y * imageWidth, 1, imageWidth);
// Copy the pixel data from the file into the buffer
file.readPixels(dataWindow.min.y, dataWindow.max.y);
// How many channels does the image have?
switch (file.channels()){
case Imf::WRITE_RGBA:
numChannels = 4;
break;
case Imf::WRITE_RGB:
numChannels = 3;
break;
default:
throw std::runtime_error("Unable to load EXR files that are not RGBA or RGB");
}
std::cout << "Image has " << numChannels << " channels\n";
}catch (Iex::BaseExc & e){
std::cout << e.what() << std::endl;
}
I am confident that the image is being correctly read in because if I use a built in OpenEXR function to write the file using 'pixels' it produces the same output image.
Creating the buffer object 'inputImageBuffer' does not produce any errors.
// Set Persistent memory only for AMD platform
cl_mem_flags inMemFlags = CL_MEM_READ_ONLY;
if (args->isAmdPlatform()){
inMemFlags |= CL_MEM_USE_PERSISTENT_MEM_AMD; // Faster transfer speed under windows 7
}
cl::Buffer inputImageBuffer;
// Create memory object for input image on the device
inputImageBuffer = cl::Buffer(
context, // Context
inMemFlags, // Flags
imageWidth * imageHeight * numChannels * sizeof(CL_HALF_FLOAT), // Size
NULL, // Host pointer
&status); // Status check
statusCheck(status, "Buffer::Buffer() failed. (inputImageBuffer)");
However when I try to send the data using the function enqueueWriteBuffer the program crashes and no helpful debug information is returned.
// Copy pixels to inputBufferImage
status = commandQueue.enqueueWriteBuffer(
inputImageBuffer,
CL_TRUE,
0,
imageWidth * imageHeight * numChannels * sizeof(CL_HALF_FLOAT),
&pixels);
statusCheck(status, "Copying failed");
I think the error might lay in how I am declaring the size of each buffer but I am unsure and any help would be much appreciated.
Thank you
Your problem stems mostly from C++ and over eager abstraction from the library maker. Array2D is not a raw flat memory which the OpenCL enqueueWriteBuffer will need, and it does not provide any clear way of actually accessing the memory.
You are basically giving it a pointer to a class instance and it tries to read from that on instead of from the _data that actually contains the pixels. See http://www.sidefx.com/docs/hdk12.1/_imf_array_8h_source.html on how it's implemented.
You need to get access to the actual memory where the pixels are held. You can either fiddle with the template and change it or you can perhaps try pixels[0]. It could work if the implementation is as on that page I linked.