enqueueNDRange上的InvalidKernelArgs,而类似的调用工作正常

问题描述 投票:0回答:1

我正在使用JavaCL来处理图像。我一直在

com.nativelibs4java.opencl.CLException $ InvalidKernelArgs:InvalidKernelArgs

在此(部分)函数中调用enqueueNDRange调用:

FloatBuffer outBuffer = ByteBuffer.allocateDirect(4*XYZ.length).order(context.getByteOrder()).asFloatBuffer();
CLFloatBuffer cl_outBuffer = context.createFloatBuffer(CLMem.Usage.Output, outBuffer, false);

CLFloatBuffer cl_inBuffer = context.createFloatBuffer(CLMem.Usage.Input,XYZ.length);
FloatBuffer inBuffer = cl_inBuffer.map(queue, CLMem.MapFlags.Write).put(XYZ);
inBuffer.rewind();
event = cl_inBuffer.unmap(queue, inBuffer);

XYZ2RGBKernel.setArgs(cl_inBuffer, XYZ.length/4,cl_outBuffer);
event = XYZ2RGBKernel.enqueueNDRange(queue, new int[]{XYZ.length/4}, event);

event = cl_outBuffer.read(queue, outBuffer, true, event);

XYZ是一个像素阵列,每个像素有4个浮点数(编码为RGBARGBARGBA ....)

关联的内核头是:

__kernel void XYZ2RGB(  __constant float3* inputXYZ,
                    int numberOfPixels,
                    __global float* output
                    )

我无法弄清楚为什么它对enqueueNDRange的调用不起作用:

        CLFloatBuffer cl_Rbuffer = context.createFloatBuffer(CLMem.Usage.Input, R.length);
        FloatBuffer R_buffer = cl_Rbuffer.map(queue, CLMem.MapFlags.Write).put(R);
        R_buffer.rewind();
        event = cl_Rbuffer.unmap(queue, R_buffer);

        CLFloatBuffer cl_Gbuffer = context.createFloatBuffer(CLMem.Usage.Input, G.length);
        FloatBuffer G_buffer = cl_Gbuffer.map(queue, CLMem.MapFlags.Write, event).put(G);
        G_buffer.rewind();
        event = cl_Gbuffer.unmap(queue, G_buffer);

        CLFloatBuffer cl_Bbuffer = context.createFloatBuffer(CLMem.Usage.Input, B.length);
        FloatBuffer B_buffer = cl_Bbuffer.map(queue, CLMem.MapFlags.Write, event).put(B);
        B_buffer.rewind();
        event = cl_Bbuffer.unmap(queue, B_buffer);

        FloatBuffer outBuffer = ByteBuffer.allocateDirect(4*4*R.length).order(context.getByteOrder()).asFloatBuffer();
        CLFloatBuffer cl_outBuffer = context.createFloatBuffer(CLMem.Usage.Output, outBuffer, false);

        RGB2XYZKernel.setArgs(cl_Rbuffer, cl_Gbuffer, cl_Bbuffer, cl_outBuffer);

        event = RGB2XYZKernel.enqueueNDRange(queue, new int[]{R.length}, event);
        event = cl_outBuffer.read(queue, outBuffer, true, event);

使用关联的内核头:

__kernel void RGB2XYZ(     __constant float* inputR,
                        __constant float* inputG,
                        __constant float* inputB,
                        __global float3* output)

工作没有任何问题。

在有人要求之前,float3或float4的工作方式相同,因为OpenCL规范对两者都使用4 * sizeof(float)对齐。我试过在两者之间切换。我也尝试将输入传递为float *,但它也不起作用。两个呼叫都是一个接一个地发生的。

Update

多个小时后我修好了它:

  • __constant似乎有一个大小限制(虽然在规范中找不到)。 XYZ的大小是R,G或B的4倍,它在运行时崩溃了。
  • 之后我用float3遇到了问题。似乎我被迫使用的库不是最新的,所以它得不到足够的支持,所以我切换到float4

但是,如果你们有任何关于__constant大小限制和内容的更多见解,请告诉我,我相信这对于遇到这个帖子的人来说会很方便。

java exception crash opencl
1个回答
0
投票

__constant似乎有一个大小限制(虽然在规范中找不到)。

限制取决于设备。常量缓冲区具有每缓冲区大小限制(CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE,最小64KB),并且还可以将有多少常量参数传递给内核(CL_DEVICE_MAX_CONSTANT_ARGS,min 8)。 AMD和Nvidia GPU通常都接近最小值,因此可以作为__constant传递的数据总量非常小。

“常量”内存的要点不是将只读输入用户数据传递给内核(因为你似乎正在使用它);关键是存储特定于算法的常量(查找表,矩阵/多项式/滤波器系数等)。如果要传递只读输入数据,通常的方法是将内核参数声明为__global const <type>*并使用CL_MEM_READ_ONLY创建相应的缓冲区。

Here更具洞察力。

© www.soinside.com 2019 - 2024. All rights reserved.