使用包含浮点数组的OpenCL将struct传递给GPU

我目前有一些数据,我想传递给我的GPU,并乘以2。

我创建了一个可以在这里看到的结构:

struct GPUPatternData { cl_int nInput,nOutput,patternCount, offest; cl_float* patterns; }; 

此结构应包含浮点数组。 我不会知道浮动数组,直到用户指定的运行时间。

主机代码:

 typedef struct GPUPatternDataContatiner { int nodeInput,nodeOutput,patternCount, offest; float* patterns; } GPUPatternData; __kernel void patternDataAddition(__global GPUPatternData* gpd,__global GPUPatternData* output) { int index = get_global_id(0); if(index patternCount) { output.patterns[index] = gpd.patterns[index]*2; } } 

这是主机代码:

 GPUPattern::GPUPatternData gpd; gpd.nodeInput = ptSet->getInputCount(); gpd.nodeOutput = ptSet->getOutputCount(); gpd.offest = gpd.nodeInput+gpd.nodeOutput; gpd.patternCount = ptSet->getCount(); gpd.patterns = new cl_float [gpd.patternCount*gpd.offest]; GPUPattern::GPUPatternData gridC; gridC.nodeInput = ptSet->getInputCount(); gridC.nodeOutput = ptSet->getOutputCount(); gridC.offest = gpd.nodeInput+gpd.nodeOutput; gridC.patternCount = ptSet->getCount(); gridC.patterns = new cl_float [gpd.patternCount*gpd.offest]; 

初始化所有数据,然后使用值初始化,然后传递给GPU

 int elements = gpd.patternCount; size_t ofsdf = sizeof(gridC); size_t dataSize = sizeof(GPUPattern::GPUPatternData)+ (sizeof(cl_float)*elements); cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err); openCLErrorCheck(&err); //Copy the buffer to the device err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&gpd,0,NULL,NULL); //This buffer is being written to only cl_mem bufferC = clCreateBuffer(gpu.context,CL_MEM_WRITE_ONLY,dataSize,NULL,&err); openCLErrorCheck(&err); err = clEnqueueWriteBuffer(queue,bufferC,CL_TRUE,0,dataSize,(void*)&gridC,0,NULL,NULL); 

一切都是建立的,我检查只是看着保持在0的错误

 cl_program program = clCreateProgramWithSource(gpu.context,1, (const char**) &kernelSource,NULL,&err); ////Build program err = clBuildProgram(program, 0, NULL, NULL, NULL, NULL); char build[2048]; clGetProgramBuildInfo(program, gpu.device, CL_PROGRAM_BUILD_LOG, 2048, build, NULL); ////Create kernal cl_kernel kernal = clCreateKernel(program, "patternDataAddition",&err); ////Set kernal arguments err = clSetKernelArg(kernal, 0, sizeof(cl_mem), &bufferA); err |= clSetKernelArg(kernal, 1, sizeof(cl_mem), &bufferC); 

然后开始了

 size_t globalWorkSize = 1024; size_t localWorkSize = 512; err = clEnqueueNDRangeKernel(queue, kernal, 1, NULL, &globalWorkSize, &localWorkSize, 0, NULL, NULL); clFinish(queue); 

它在这一点上都出错了

 err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize, &gridC, 0, NULL, NULL); clFinish(queue); 

这种情况下的错误是-5(CL_OUT_OF_RESOURCES)。

如果我更改线路:

 err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize, &gridC, 0, NULL, 

至:

 err = clEnqueueReadBuffer(queue, bufferC, CL_TRUE, 0, dataSize*1000, &gridC, 0, NULL, NULL); 

我收到错误-30(CL_INVALID_VALUE)。

所以我的问题是为什么我在读回缓冲区时会遇到错误。 此外,我不确定我是否无法使用指向我的浮点数组的指针,因为这可能会给我错误的sizeof()用于datasize ,这给了我错误的缓冲区大小。

您不能将包含指针的结构传递给OpenCL

http://www.khronos.org/registry/cl/specs/opencl-1.2.pdf (第6.9节)

您可以按照Eric Bainville所指出的那样纠正,或者如果您对记忆的限制不是很严格,您可以做类似的事情

 struct GPUPatternData { cl_int nInput,nOutput,patternCount, offest; cl_float patterns[MAX_SIZE]; }; 

编辑:好的,如果内存是一个问题。 由于您只使用patternspatternCount ,因此可以从结构中复制模式并将它们分别传递给内核。

 struct GPUPatternData { cl_int nInput,nOutput,patternCount, offest; cl_float patterns*; }; 

patternsgpd复制到GPU,并为GPU上的gridC patterns分配空间。 然后

您可以单独传递缓冲区

 __kernel void patternDataAddition(int gpd_patternCount, __global const float * gpd_Patterns, __global float * gridC_Patterns) { int index = get_global_id(0); if(index < gpd_patternCount) { gridC_Patterns[index] = gpd_Patterns[index]*2; } } 

当你从内核回来时,将数据直接复制回gridC.patterns


多一个 :

您不必更改CPU结构。 它保持不变。 不过这部分

 size_t dataSize = sizeof(GPUPattern::GPUPatternData)+ (sizeof(cl_float)*elements); cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err); openCLErrorCheck(&err); //Copy the buffer to the device err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&gpd,0,NULL,NULL); 

应该改成类似的东西

 size_t dataSize = (sizeof(cl_float)*elements); // HERE float* gpd_dataPointer = gpd.patterns; // HERE cl_mem bufferA = clCreateBuffer(gpu.context,CL_MEM_READ_ONLY,dataSize,NULL,&err); openCLErrorCheck(&err); // Now use the gpd_dataPointer err = clEnqueueWriteBuffer(queue,bufferA,CL_TRUE,0,dataSize,(void*)&(gpd_dataPointer),0,NULL,NULL); 

gridC也是gridC

复制后,将其复制到gridC_dataPointer AKA gridC.dataPointer

然后继续使用结构,好像什么也没发生。

问题可能在于结构中的指针。

在这种情况下,我建议将nInput,nOutput,patternCount,offset作为内核args传递,并将模式作为float的缓冲区:

 __kernel void patternDataAddition(int nInput,int nOutput, int patternCount,int offset, __global const float * inPatterns, __global float * outPatterns) 

我知道它现在不是实际的,但我以其他方式传递了这个问题:你的数据结构的分配内存代码保持不变,但结构应该改为

 typedef struct GPUPatternDataContatiner { int nodeInput, nodeOutput, patternCount, offest; float patterns[0]; } GPUPatternData; 

使用这个“function”我已经为OpenCL创建了矢量