9.1 KiB
CLBufferRead
Reads an OpenCL buffer into an array and returns the number of read elements.
uint CLBufferRead(
int buffer, // A handle to the OpenCL buffer
const void& data[], // An array of values
uint buffer_offset=0, // An offset in the OpenCL buffer in bytes, 0 by default
uint data_offset=0, // An offset in the array in elements, 0 by default
uint data_count=WHOLE_ARRAY // The number of values from the buffer for reading, the whole buffer by default
);
There are also versions for handling matrices and vectors.
Reads the OpenCL buffer to the matrix and returns true if successful.
uint CLBufferRead(
int buffer, // a handle to the OpenCL buffer
uint buffer_offset, // an offset in the OpenCL buffer in bytes
const matrix& mat, // the matrix for receiving the values from the buffer
ulong rows=-1, // the number of rows in the matrix
ulong cols=-1 // the number of columns in the matrix
);
Reads the OpenCL buffer to the vector and returns true if successful.
uint CLBufferRead(
int buffer, // a handle to the OpenCL buffer
uint buffer_offset, // an offset in the OpenCL buffer in bytes
const vector& vec, // the vector for receiving the values from the buffer
ulong size-1, // vector length
);
Parameters
buffer
[in] A handle of the OpenCL buffer.
data[]
[in] An array for receiving values from the OpenCL buffer. Passed by reference.
buffer_offset
[in] An offset in the OpenCL buffer in bytes, from which reading begins. By default, reading start with the very beginning of the buffer.
data_offset
[in] The index of the first array element for writing the values of the OpenCL buffer. By default, writing of the read values into an array starts from the zero index.
data_count
[in] The number of values that should be read. The whole OpenCL buffer is read by default.
mat
[out] The matrix for reading data from the buffer can be any of the three types — matrix, matrixf or matrixc.
vec
[out] The vector for reading data from the buffer can be of any of the three types — vector, vectorf or vectorc.
rows=-1
[in] If the parameter is specified, the cols parameter should be specified as well. If the new matrix dimensions are not specified, the current ones are used. If the value is -1, then the number of rows does not change.
cols=-1
[in] If the parameter is not specified, the rows parameter should be skipped as well. The matrix adheres to the rule: either both parameters are specified, or none, otherwise an error will occur. If both parameters (rows and cols) are specified, the matrix size is changed. In case of -1, the number of columns does not change.
size=-1
[in] If the parameter is not specified or its value is -1, the vector length does not change.
Return Value
The number of read elements. 0 is returned in case of an error. For information about the error, use the GetLastError() function.
true if a matrix or a vector is handled successfully, otherwise false.
Note
For one-dimensional arrays, the number of the element, into which writing of data into an OpenCL buffer begins, is calculated taking into account the AS_SERIES flags.
An array of two or more dimensions is presented as one-dimensional. In this case, data_offset is the number of elements that should be skipped in the presentation, not the number of elements in the first dimension.
Example of calculating Pi using the equation:
#define _num_steps 1000000000
#define _divisor 40000
#define _step 1.0 / _num_steps
#define _intrnCnt _num_steps / _divisor
//+------------------------------------------------------------------+
//| |
//+------------------------------------------------------------------+
string D2S(double arg, int digits) { return DoubleToString(arg, digits); }
string I2S(int arg) { return IntegerToString(arg); }
//--- OpenCL programm code
const string clSource=
"#define _step "+D2S(_step, 12)+" \r\n"
"#define _intrnCnt "+I2S(_intrnCnt)+" \r\n"
" \r\n"
"__kernel void Pi( __global double *out ) \r\n"
"{ \r\n"
" int i = get_global_id( 0 ); \r\n"
" double partsum = 0.0; \r\n"
" double x = 0.0; \r\n"
" long from = i * _intrnCnt; \r\n"
" long to = from + _intrnCnt; \r\n"
" for( long j = from; j < to; j ++ ) \r\n"
" { \r\n"
" x = ( j + 0.5 ) * _step; \r\n"
" partsum += 4.0 / ( 1. + x * x ); \r\n"
" } \r\n"
" out[ i ] = partsum; \r\n"
"} \r\n";
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
int OnStart()
{
Print("Pi Calculation: step = "+D2S(_step, 12)+"; _intrnCnt = "+I2S(_intrnCnt));
//--- prepare OpenCL contexts
int clCtx;
if((clCtx=CLContextCreate(CL_USE_GPU_ONLY))==INVALID_HANDLE)
{
Print("OpenCL not found");
return(-1);
}
int clPrg = CLProgramCreate(clCtx, clSource);
int clKrn = CLKernelCreate(clPrg, "Pi");
int clMem=CLBufferCreate(clCtx, _divisor*sizeof(double), CL_MEM_READ_WRITE);
CLSetKernelArgMem(clKrn, 0, clMem);
const uint offs[1] = {0};
const uint works[1] = {_divisor};
//--- launch OpenCL program
ulong start=GetMicrosecondCount();
if(!CLExecute(clKrn, 1, offs, works))
{
Print("CLExecute(clKrn, 1, offs, works) failed! Error ", GetLastError());
CLFreeAll(clMem, clKrn, clPrg, clCtx);
return(-1);
}
//--- get results from OpenCL device
vector buffer(_divisor);
if(!CLBufferRead(clMem, 0, buffer))
{
Print("CLBufferRead(clMem, 0, buffer) failed! Error ", GetLastError());
CLFreeAll(clMem, clKrn, clPrg, clCtx);
return(-1);
}
//--- sum all values to calculate Pi
double Pi=buffer.Sum()*_step;
double time=(GetMicrosecondCount()-start)/1000.;
Print("OpenCL: Pi calculated for "+D2S(time, 2)+" ms");
Print("Pi = "+DoubleToString(Pi, 12));
//--- free memory
CLFreeAll(clMem, clKrn, clPrg, clCtx);
//--- success
return(0);
}
/*
Pi Calculation: step = 0.000000001000; _intrnCnt = 25000
OpenCL: GPU device 'Ellesmere' selected
OpenCL: Pi calculated for 99.98 ms
Pi = 3.141592653590
*/
//+------------------------------------------------------------------+
//| Auxiliary routine to free memory |
//+------------------------------------------------------------------+
void CLFreeAll(const int clMem, const int clKrn, const int clPrg, const int clCtx)
{
CLBufferFree(clMem);
CLKernelFree(clKrn);
CLProgramFree(clPrg);
CLContextFree(clCtx);
}
