Hello,
I'm wondering about the right setup for the clEnqueueReadBufferRect function. I tried to boil it down to a minimum test case: In the attached example, a buffer of 4x4 ints is created. Then the clEnqueueReadBufferRect should be used to copy a region with origin (0,0) and a size of 3x3 ints. However, it keeps saying "CL_INVALID_VALUE". (With a region of size 2x2 it works, but I assume that it copies only garbage then)
Can anyone give me a hint or an example how this function may be used, or tell me what's wrong with the function arguments in the example?
#include <cstdio> #include <cstdlib> #include <iostream> #include <CL/cl.hpp> int main() { // --->--- Initialization stuff cl_platform_id platform; clGetPlatformIDs(1, &platform, NULL); cl_context_properties contextProperties[3] = { CL_CONTEXT_PLATFORM, (cl_context_properties)platform, 0 }; cl_context context = clCreateContextFromType( contextProperties, CL_DEVICE_TYPE_CPU, NULL, NULL, NULL); cl_device_id device; clGetContextInfo(context, CL_CONTEXT_DEVICES, sizeof(cl_device_id), &device, NULL); cl_command_queue commandQueue = clCreateCommandQueue(context, device, 0, NULL); // ---<--- Initialization stuff // Create a buffer of 4*4 ints int sizeX = 4; int sizeY = 4; int n = sizeX * sizeY; cl_mem mem = clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(int)*n, NULL, NULL); size_t bufferOffset[] = { 0, 0, 0 }; size_t hostOffset[] = { 0, 0, 0 }; // Copy a region of 3x3 int values from the buffer int regionSizeX = 3; int regionSizeY = 3; // The region size must be given in bytes size_t region[] = { regionSizeX * sizeof(int), regionSizeY * sizeof(int), 1 }; // These values are computed automatically when they are 0 size_t bufferRowPitch = 0; size_t bufferSlicePitch = 0; size_t hostRowPitch = 0; size_t hostSlicePitch = 0; int *regionData = new int[regionSizeX*regionSizeY]; int result = clEnqueueReadBufferRect( commandQueue, mem, true, bufferOffset, hostOffset, region, bufferRowPitch, bufferSlicePitch, hostRowPitch, hostSlicePitch, regionData, 0, NULL, NULL); if (result == CL_SUCCESS) { printf("Passed\n"); } else { printf("Failed\n"); } return 0; }
Originally posted by: Marco13 Hello,
I'm wondering about the right setup for the clEnqueueReadBufferRect function. I tried to boil it down to a minimum test case: In the attached example, a buffer of 4x4 ints is created. Then the clEnqueueReadBufferRect should be used to copy a region with origin (0,0) and a size of 3x3 ints. However, it keeps saying "CL_INVALID_VALUE". (With a region of size 2x2 it works, but I assume that it copies only garbage then)
Can anyone give me a hint or an example how this function may be used, or tell me what's wrong with the function arguments in the example?
bufferRowPitch and hostRowPitch are wrong and should be as follows
size_t bufferRowPitch = sizeZ * sizeof(int);
size_t hostRowPitch = regionSizeX * sizeof(int);
Hello genaganna,
Thank you for your response. Initially I tried to set these values similar to what you described
size_t bufferRowPitch = sizeX * sizeof(int); // using sizeX here
size_t hostRowPitch = regionSizeX * sizeof(int);
which should be correct to my understanding of the specification. Initially, I used an offset of (1,1,0) and a size of (2,2,1), but then I noticed that I might be tricky to get the multiplication with sizeof(int) right - excerpt from the spec:
buffer_origin: [...]
The offset in bytes is computed as buffer_origin
[2] * buffer_slice_pitch
+ buffer_origin
[1] * buffer_row_pitch
Originally posted by: Marco13 Hello genaganna,
Thank you for your response. Initially I tried to set these values similar to what you described
size_t bufferRowPitch = sizeX * sizeof(int); // using sizeX here
size_t hostRowPitch = regionSizeX * sizeof(int);
which should be correct to my understanding of the specification. Initially, I used an offset of (1,1,0) and a size of (2,2,1), but then I noticed that I might be tricky to get the multiplication with sizeof(int) right - excerpt from the spec:
buffer_origin: [...]
The offset in bytes is computed asbuffer_origin
[2] *buffer_slice_pitch
+buffer_origin
[1] *buffer_row_pitch
- So as far as I understand, the factor sizeof(int) should /either/ be applied to the buffer_origin[1], /or/ to the buffer_row_pitch, but not to both, and care has to be taken not to multiply with sizeof(int) once too often.
- However, to avoid issues like this and to simplify things for the first test, I set the origin to (0,0,0), and referred to the behavior that is described in the specification, which says: When the bufferHostPitch or hostRowPitch are 0, they are computed as 'region[0]' - so I don't see what's wrong with the given code. Or did I overlook something in the release notes, stating that this behavior (computing the pitches automatically) is not supported yet?
- Otherwise, I'll try to do some "black box analysis" of the function, to see if I can guess the right parameters, but would appreciate any hints that might point me in the right direction...
- bye
buffer_row_pitch is zero means region must be 1D.
Just replace following code with size_t region[] statement. Your code works without any problem.
size_t region[] = { regionSizeX * sizeof(int), 1, 1 };
I hope it clarifies your all doughts.
Hello,
Setting the region size to
size_t region[] = { regionSizeX * sizeof(int), 1, 1 };
obviously copied only the first row, but this hint (together with some more trial and error and painting of little boxes) lead me into the right direction: 'int' entries are 4 bytes wide, but only 1 byte high... (Now this seems sooo embarassing to me - it's obviously time for the weekend )
Thanks for your support!