OpenCL 内核导致应用程序无限期地 运行 并且仅在我关闭我的 IDE 后才停止
OpenCL kernel causes application to run indefinitely and only stops after I shut down my IDE
我正在尝试使用 OpenCL 在 GPU 上 运行 部分 this 代码。我现在正在尝试 运行 处理 YCbCr 到 RGB 转换的函数。
请注意,到目前为止我还没有尝试优化 GPU 代码。我只是想要一个与 CPU.
相同的输出
函数原来是这样写的:
void YCbCr_to_ARGB(uint8_t *YCbCr_MCU[3], uint32_t *RGB_MCU, uint32_t nb_MCU_H, uint32_t nb_MCU_V)
{
uint8_t *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint32_t ARGB;
uint8_t index, i, j;
MCU_Y = YCbCr_MCU[0];
MCU_Cb = YCbCr_MCU[1];
MCU_Cr = YCbCr_MCU[2];
for (i = 0; i < 8 * nb_MCU_V; i++) {
for (j = 0; j < 8 * nb_MCU_H; j++) {
index = i * (8 * nb_MCU_H) + j;
R = (MCU_Cr[index] - 128) * 1.402f + MCU_Y[index];
B = (MCU_Cb[index] - 128) * 1.7772f + MCU_Y[index];
G = MCU_Y[index] - (MCU_Cb[index] - 128) * 0.34414f -
(MCU_Cr[index] - 128) * 0.71414f;
/* Saturate */
if (R > 255)
R = 255;
if (R < 0)
R = 0;
if (G > 255)
G = 255;
if (G < 0)
G = 0;
if (B > 255)
B = 255;
if (B < 0)
B = 0;
ARGB = ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF);
// ARGB = 0xFF << 8;
RGB_MCU[(i * (8 * nb_MCU_H) + j)] = ARGB;
}
}
}
这个函数的变量在main.c
中声明如下:
cl_uchar* YCbCr_MCU[3] = { NULL, NULL, NULL};
cl_uint* RGB_MCU = NULL;
这些变量的内存是这样分配的:
if (screen_init_needed == 1)
{
screen_init_needed = 0;
.....
.....
//Some code
for (index = 0 ; index < SOF_section.n ; index++) {
YCbCr_MCU[index] = malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
YCbCr_MCU_ds[index] = malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
}
RGB_MCU = malloc (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int));
}
break;
}
我直接将其复制并粘贴到我的 .cl
文件中,并进行了一些小改动以使其符合 OpenCL 标准。我修改后的 OpenCL 代码如下所示:
__kernel void YCbCr_to_ARGB(__global uchar* YCbCr_MCU[3], __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
MCU_Y = YCbCr_MCU[0];
MCU_Cb = YCbCr_MCU[1];
MCU_Cr = YCbCr_MCU[2];
//Same code as the first code snippet
......
......
......
}
当我使用 .cl
文件中的上述内核代码构建和 运行 我的应用程序时,出现错误。其中一个错误表明 OpenCL 不允许指向指针参数的指针。
为了解决这些错误,我再次修改了我的代码,如下所示:
__kernel void YCbCr_to_ARGB(__global uchar YCbCr_MCU[3], __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
MCU_Y = &YCbCr_MCU[0];
MCU_Cb = &YCbCr_MCU[1];
MCU_Cr = &YCbCr_MCU[2];
//Same code as the first code snippet
......
......
......
}
当我再次构建并 运行 应用程序时,我没有收到任何错误。这促使我为这个内核编写主机代码。
看起来像这样:
color_kernel= clCreateKernel(program, "YCbCr_to_ARGB", &ret);
//YCbCr_MCU for YCbCrtoARGB
cl_mem colorMCU_GPU= clCreateBuffer(context, CL_MEM_READ_WRITE, 3 * sizeof(cl_uchar), NULL, &ret);
//rgb_MCU for YCbCrtoARGB
cl_mem RGB_GPU= clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(cl_uint), NULL, &ret);
我在 main.c
中调用原始函数的地方调用了内核参数。我按以下方式为这个内核执行了剩余的步骤:
if(color&&(SOF_section.n>1)
{
ret = clEnqueueWriteBuffer(command_queue, colorMCU_GPU, CL_TRUE, 0, 3 * sizeof(cl_uchar), YCbCr_MCU, 0, NULL, NULL);
ret = clEnqueueWriteBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), (void *)&colorMCU_GPU);
ret |= clSetKernelArg(color_kernel, 1, sizeof(cl_mem), (void *)&RGB_GPU);
ret = clSetKernelArg(color_kernel, 2, sizeof(cl_uint), (void *)&max_ss_h);
ret |= clSetKernelArg(color_kernel, 3, sizeof(cl_uint), (void *)&max_ss_v);
ret = clEnqueueTask(command_queue, color_kernel, 0, NULL, NULL);
ret = clEnqueueReadBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
//YCbCr_to_ARGB(YCbCr_MCU, RGB_MCU, max_ss_h, max_ss_v);
在我 运行 并使用这些参数构建代码之后,代码会无限期地保持 运行ning(其输出应该是 运行ning 上的影片剪辑 运行ning屏幕。使用此代码,我只会得到一个黑屏)。我必须关闭 Eclipse 并重新打开它才能在此之后对代码进行其他更改。
是什么导致程序出现这样的行为?有没有办法在 GPU 上安全地 运行 这个函数?
更新:
我听从了 Anders Cedronius 的建议并按以下方式更改了我的内核代码:
__kernel void YCbCr_to_ARGB(__global uchar YCbCr_MCU[3], __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
printf("Doing color conversion\n");
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
i= get_global_id(0);
j= get_global_id(1);
MCU_Y = &YCbCr_MCU[0];
MCU_Cb = &YCbCr_MCU[1];
MCU_Cr = &YCbCr_MCU[2];
if (i < 8 * nb_MCU_V && j < 8 * nb_MCU_H)
{
index = i * (8 * nb_MCU_H) + j;
R = (MCU_Cr[index] - 128) * 1.402f + MCU_Y[index];
B = (MCU_Cb[index] - 128) * 1.7772f + MCU_Y[index];
G = MCU_Y[index] - (MCU_Cb[index] - 128) * 0.34414f -
(MCU_Cr[index] - 128) * 0.71414f;
/* Saturate */
if (R > 255)
R = 255;
if (R < 0)
R = 0;
if (G > 255)
G = 255;
if (G < 0)
G = 0;
if (B > 255)
B = 255;
if (B < 0)
B = 0;
ARGB = ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF);
// ARGB = 0xFF << 8;
RGB_MCU[(i * (8 * nb_MCU_H) + j)] = ARGB;
}
printf("Finished color conversion\n");
}
我调用内核的主机代码现在如下所示:
color_kernel= clCreateKernel(program, "YCbCr_to_ARGB", &ret);
我按以下方式设置工作大小和内核参数:
ret = clEnqueueWriteBuffer(command_queue, colorMCU_GPU, CL_TRUE, 0, 3*sizeof(cl_uchar), YCbCr_MCU, 0, NULL, NULL);
chk(ret, "clEnqueueWriteBuffer");
ret = clEnqueueWriteBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
chk(ret, "clEnqueueWriteBuffer");
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), (void *)&colorMCU_GPU);
ret |= clSetKernelArg(color_kernel, 1, sizeof(cl_mem), (void *)&RGB_GPU);
ret = clSetKernelArg(color_kernel, 2, sizeof(cl_uint), (void *)&max_ss_h);
ret |= clSetKernelArg(color_kernel, 3, sizeof(cl_uint), (void *)&max_ss_v);
size_t itemColor[2] = {1, 1};
ret = clEnqueueNDRangeKernel(command_queue, kernel, 2, NULL, itemColor, NULL, 0, NULL, NULL);
chk(ret, "clEnqueueNDRange");
ret = clEnqueueReadBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
clFinish(command_queue);
我 运行 这段代码,我再也不会黑屏了。但是,现在无法识别 "YCbCr to RGB" 的内核。 甚至我的 printf 注释也没有显示在输出控制台上。好像我的代码没有颜色转换功能
更新:
我没有在命令 EnqueueNDRangeKernel
中更改内核的名称。我更改了名称,现在 printf 语句出现在控制台上。但是,我仍然没有得到正确的输出。
size_t itemColor[2] = {1, 1};
ret = clEnqueueNDRangeKernel(command_queue, color_kernel, 2, NULL, itemColor, NULL, 0, NULL, NULL);
chk(ret, "clEnqueueNDRange");
clFinish(command_queue);
更新:
我听从了 pmdj 的建议并更改了我的内核代码。现在看起来像这样:
__kernel void YCbCr_to_ARGB(__global uchar* Y_GPU, __global uchar* Cb_GPU, __global uchar* Cr_GPU, __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
unsigned char iid= get_global_id(0);
unsigned char jid= get_global_id(1);
// MCU_Y = &YCbCr_MCU[0];
// MCU_Cb = &YCbCr_MCU[1];
// MCU_Cr = &YCbCr_MCU[2];
MCU_Y= Y_GPU;
MCU_Cb= Cb_GPU;
MCU_Cr= Cr_GPU;
if (iid <= (8 * nb_MCU_V) && jid <= (8 * nb_MCU_H))
{
index = iid * (8 * nb_MCU_H) + jid;
R = (MCU_Cr[index] - 128) * 1.402f + MCU_Y[index];
B = (MCU_Cb[index] - 128) * 1.7772f + MCU_Y[index];
G = MCU_Y[index] - (MCU_Cb[index] - 128) * 0.34414f -
(MCU_Cr[index] - 128) * 0.71414f;
/* Saturate */
if (R > 255)
R = 255;
if (R < 0)
R = 0;
if (G > 255)
G = 255;
if (G < 0)
G = 0;
if (B > 255)
B = 255;
if (B < 0)
B = 0;
ARGB = ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF);
RGB_MCU[(iid * (8 * nb_MCU_H) + jid)] = ARGB;
}
}
在主机代码中,我为 4 个新变量创建并分配了内存:
Y_ForGPU= (cl_uchar *)malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
Cb_ForGPU= (cl_uchar *)malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
Cr_ForGPU= (cl_uchar *)malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
//Now will do it for RGB
RGB_testing= (cl_uint *)malloc (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int));
我按以下方式创建了缓冲区:
cl_mem for_Y= clCreateBuffer(context, CL_MEM_READ_WRITE| CL_MEM_COPY_HOST_PTR, (MCU_sx * MCU_sy * max_ss_h * max_ss_v), Y_ForGPU, &ret);
cl_mem for_Cb= clCreateBuffer(context, CL_MEM_READ_WRITE| CL_MEM_COPY_HOST_PTR, (MCU_sx * MCU_sy * max_ss_h * max_ss_v), Cb_ForGPU , &ret);
cl_mem for_Cr= clCreateBuffer(context, CL_MEM_READ_WRITE| CL_MEM_COPY_HOST_PTR, (MCU_sx * MCU_sy * max_ss_h * max_ss_v), Cr_ForGPU, &ret);
//rgb_MCU for YCbCrtoARGB
cl_mem RGB_GPU= clCreateBuffer(context, CL_MEM_READ_WRITE, (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int)), NULL, &ret);
然后我设置内核参数,执行内核并将计算的数据发送回主机:
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), &for_Y);
ret |= clSetKernelArg(color_kernel, 1, sizeof(cl_mem), &for_Cb);
ret |= clSetKernelArg(color_kernel, 2, sizeof(cl_mem), &for_Cr);
ret |= clSetKernelArg(color_kernel, 3, sizeof(cl_mem), &RGB_GPU);
ret |= clSetKernelArg(color_kernel, 4, sizeof(cl_uint), &max_ss_h);
ret |= clSetKernelArg(color_kernel, 5, sizeof(cl_uint), &max_ss_v);
const size_t itemColor[2] = {100, 100};
ret = clEnqueueNDRangeKernel(command_queue, color_kernel, 2, NULL, itemColor, NULL, 0, NULL, NULL);
clFinish(command_queue);
//Copy result to the host
ret = clEnqueueReadBuffer(command_queue, RGB_GPU, CL_TRUE, 0, (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int)), RGB_testing, 0, NULL, NULL);
但是,现在我的代码突然终止了。为什么会发生这种情况?
更新:
我的代码现在可以工作了。这些问题可能是由于指针的差异而发生的。我将 Y、Cb、Cr 和 RGB 变量(我创建的)设置为等于主机代码中的原始变量。
//---Setting color variables equal to array elements----//
Y_ForGPU= YCbCr_MCU[0];
Cb_ForGPU= YCbCr_MCU[1];
Cr_ForGPU= YCbCr_MCU[2];
//----RGB is being assigned value-----//
RGB_testing= RGB_MCU;
我不知道这是否是导致您出现问题的唯一原因(可能还有更多我尚未发现),但您的 YCbCr_MCU
内核参数中存在类型不匹配问题。你不能有指针到指针的参数,这是真的。不过,简单地删除 *
并不能解决问题。
特别是行
MCU_Cb = &YCbCr_MCU[1];
在内核中,从 YCbCr_MCU 指向的任何内容的开始处获取 1 个字节,从主机代码来看,这实际上是指针数组的开始,而不是像素数组。
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), (void *)&colorMCU_GPU);
看起来 YCbCr_MCU
应该是一个包含 3 个指向包含源像素的 Y、Cb、Cr 平面的指针的数组。您需要将它们作为指向 3 个数组的 3 个直接指针而不是指向 3 个指针的指针传递给您的内核。换句话说,把它变成Y,Cb,Cr参数,在主机上设置为colorMCU_GPU[0]
到colorMCU_GPU[2]
。
我正在尝试使用 OpenCL 在 GPU 上 运行 部分 this 代码。我现在正在尝试 运行 处理 YCbCr 到 RGB 转换的函数。
请注意,到目前为止我还没有尝试优化 GPU 代码。我只是想要一个与 CPU.
相同的输出函数原来是这样写的:
void YCbCr_to_ARGB(uint8_t *YCbCr_MCU[3], uint32_t *RGB_MCU, uint32_t nb_MCU_H, uint32_t nb_MCU_V)
{
uint8_t *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint32_t ARGB;
uint8_t index, i, j;
MCU_Y = YCbCr_MCU[0];
MCU_Cb = YCbCr_MCU[1];
MCU_Cr = YCbCr_MCU[2];
for (i = 0; i < 8 * nb_MCU_V; i++) {
for (j = 0; j < 8 * nb_MCU_H; j++) {
index = i * (8 * nb_MCU_H) + j;
R = (MCU_Cr[index] - 128) * 1.402f + MCU_Y[index];
B = (MCU_Cb[index] - 128) * 1.7772f + MCU_Y[index];
G = MCU_Y[index] - (MCU_Cb[index] - 128) * 0.34414f -
(MCU_Cr[index] - 128) * 0.71414f;
/* Saturate */
if (R > 255)
R = 255;
if (R < 0)
R = 0;
if (G > 255)
G = 255;
if (G < 0)
G = 0;
if (B > 255)
B = 255;
if (B < 0)
B = 0;
ARGB = ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF);
// ARGB = 0xFF << 8;
RGB_MCU[(i * (8 * nb_MCU_H) + j)] = ARGB;
}
}
}
这个函数的变量在main.c
中声明如下:
cl_uchar* YCbCr_MCU[3] = { NULL, NULL, NULL};
cl_uint* RGB_MCU = NULL;
这些变量的内存是这样分配的:
if (screen_init_needed == 1)
{
screen_init_needed = 0;
.....
.....
//Some code
for (index = 0 ; index < SOF_section.n ; index++) {
YCbCr_MCU[index] = malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
YCbCr_MCU_ds[index] = malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
}
RGB_MCU = malloc (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int));
}
break;
}
我直接将其复制并粘贴到我的 .cl
文件中,并进行了一些小改动以使其符合 OpenCL 标准。我修改后的 OpenCL 代码如下所示:
__kernel void YCbCr_to_ARGB(__global uchar* YCbCr_MCU[3], __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
MCU_Y = YCbCr_MCU[0];
MCU_Cb = YCbCr_MCU[1];
MCU_Cr = YCbCr_MCU[2];
//Same code as the first code snippet
......
......
......
}
当我使用 .cl
文件中的上述内核代码构建和 运行 我的应用程序时,出现错误。其中一个错误表明 OpenCL 不允许指向指针参数的指针。
为了解决这些错误,我再次修改了我的代码,如下所示:
__kernel void YCbCr_to_ARGB(__global uchar YCbCr_MCU[3], __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
MCU_Y = &YCbCr_MCU[0];
MCU_Cb = &YCbCr_MCU[1];
MCU_Cr = &YCbCr_MCU[2];
//Same code as the first code snippet
......
......
......
}
当我再次构建并 运行 应用程序时,我没有收到任何错误。这促使我为这个内核编写主机代码。
看起来像这样:
color_kernel= clCreateKernel(program, "YCbCr_to_ARGB", &ret);
//YCbCr_MCU for YCbCrtoARGB
cl_mem colorMCU_GPU= clCreateBuffer(context, CL_MEM_READ_WRITE, 3 * sizeof(cl_uchar), NULL, &ret);
//rgb_MCU for YCbCrtoARGB
cl_mem RGB_GPU= clCreateBuffer(context, CL_MEM_READ_WRITE, sizeof(cl_uint), NULL, &ret);
我在 main.c
中调用原始函数的地方调用了内核参数。我按以下方式为这个内核执行了剩余的步骤:
if(color&&(SOF_section.n>1)
{
ret = clEnqueueWriteBuffer(command_queue, colorMCU_GPU, CL_TRUE, 0, 3 * sizeof(cl_uchar), YCbCr_MCU, 0, NULL, NULL);
ret = clEnqueueWriteBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), (void *)&colorMCU_GPU);
ret |= clSetKernelArg(color_kernel, 1, sizeof(cl_mem), (void *)&RGB_GPU);
ret = clSetKernelArg(color_kernel, 2, sizeof(cl_uint), (void *)&max_ss_h);
ret |= clSetKernelArg(color_kernel, 3, sizeof(cl_uint), (void *)&max_ss_v);
ret = clEnqueueTask(command_queue, color_kernel, 0, NULL, NULL);
ret = clEnqueueReadBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
//YCbCr_to_ARGB(YCbCr_MCU, RGB_MCU, max_ss_h, max_ss_v);
在我 运行 并使用这些参数构建代码之后,代码会无限期地保持 运行ning(其输出应该是 运行ning 上的影片剪辑 运行ning屏幕。使用此代码,我只会得到一个黑屏)。我必须关闭 Eclipse 并重新打开它才能在此之后对代码进行其他更改。
是什么导致程序出现这样的行为?有没有办法在 GPU 上安全地 运行 这个函数?
更新:
我听从了 Anders Cedronius 的建议并按以下方式更改了我的内核代码:
__kernel void YCbCr_to_ARGB(__global uchar YCbCr_MCU[3], __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
printf("Doing color conversion\n");
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
i= get_global_id(0);
j= get_global_id(1);
MCU_Y = &YCbCr_MCU[0];
MCU_Cb = &YCbCr_MCU[1];
MCU_Cr = &YCbCr_MCU[2];
if (i < 8 * nb_MCU_V && j < 8 * nb_MCU_H)
{
index = i * (8 * nb_MCU_H) + j;
R = (MCU_Cr[index] - 128) * 1.402f + MCU_Y[index];
B = (MCU_Cb[index] - 128) * 1.7772f + MCU_Y[index];
G = MCU_Y[index] - (MCU_Cb[index] - 128) * 0.34414f -
(MCU_Cr[index] - 128) * 0.71414f;
/* Saturate */
if (R > 255)
R = 255;
if (R < 0)
R = 0;
if (G > 255)
G = 255;
if (G < 0)
G = 0;
if (B > 255)
B = 255;
if (B < 0)
B = 0;
ARGB = ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF);
// ARGB = 0xFF << 8;
RGB_MCU[(i * (8 * nb_MCU_H) + j)] = ARGB;
}
printf("Finished color conversion\n");
}
我调用内核的主机代码现在如下所示:
color_kernel= clCreateKernel(program, "YCbCr_to_ARGB", &ret);
我按以下方式设置工作大小和内核参数:
ret = clEnqueueWriteBuffer(command_queue, colorMCU_GPU, CL_TRUE, 0, 3*sizeof(cl_uchar), YCbCr_MCU, 0, NULL, NULL);
chk(ret, "clEnqueueWriteBuffer");
ret = clEnqueueWriteBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
chk(ret, "clEnqueueWriteBuffer");
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), (void *)&colorMCU_GPU);
ret |= clSetKernelArg(color_kernel, 1, sizeof(cl_mem), (void *)&RGB_GPU);
ret = clSetKernelArg(color_kernel, 2, sizeof(cl_uint), (void *)&max_ss_h);
ret |= clSetKernelArg(color_kernel, 3, sizeof(cl_uint), (void *)&max_ss_v);
size_t itemColor[2] = {1, 1};
ret = clEnqueueNDRangeKernel(command_queue, kernel, 2, NULL, itemColor, NULL, 0, NULL, NULL);
chk(ret, "clEnqueueNDRange");
ret = clEnqueueReadBuffer(command_queue, RGB_GPU, CL_TRUE, 0, sizeof(cl_uint), RGB_MCU, 0, NULL, NULL);
clFinish(command_queue);
我 运行 这段代码,我再也不会黑屏了。但是,现在无法识别 "YCbCr to RGB" 的内核。 甚至我的 printf 注释也没有显示在输出控制台上。好像我的代码没有颜色转换功能
更新:
我没有在命令 EnqueueNDRangeKernel
中更改内核的名称。我更改了名称,现在 printf 语句出现在控制台上。但是,我仍然没有得到正确的输出。
size_t itemColor[2] = {1, 1};
ret = clEnqueueNDRangeKernel(command_queue, color_kernel, 2, NULL, itemColor, NULL, 0, NULL, NULL);
chk(ret, "clEnqueueNDRange");
clFinish(command_queue);
更新:
我听从了 pmdj 的建议并更改了我的内核代码。现在看起来像这样:
__kernel void YCbCr_to_ARGB(__global uchar* Y_GPU, __global uchar* Cb_GPU, __global uchar* Cr_GPU, __global uint* RGB_MCU, uint nb_MCU_H, uint nb_MCU_V)
{
__global uchar *MCU_Y, *MCU_Cb, *MCU_Cr;
int R, G, B;
uint ARGB;
uchar index, i, j;
unsigned char iid= get_global_id(0);
unsigned char jid= get_global_id(1);
// MCU_Y = &YCbCr_MCU[0];
// MCU_Cb = &YCbCr_MCU[1];
// MCU_Cr = &YCbCr_MCU[2];
MCU_Y= Y_GPU;
MCU_Cb= Cb_GPU;
MCU_Cr= Cr_GPU;
if (iid <= (8 * nb_MCU_V) && jid <= (8 * nb_MCU_H))
{
index = iid * (8 * nb_MCU_H) + jid;
R = (MCU_Cr[index] - 128) * 1.402f + MCU_Y[index];
B = (MCU_Cb[index] - 128) * 1.7772f + MCU_Y[index];
G = MCU_Y[index] - (MCU_Cb[index] - 128) * 0.34414f -
(MCU_Cr[index] - 128) * 0.71414f;
/* Saturate */
if (R > 255)
R = 255;
if (R < 0)
R = 0;
if (G > 255)
G = 255;
if (G < 0)
G = 0;
if (B > 255)
B = 255;
if (B < 0)
B = 0;
ARGB = ((R & 0xFF) << 16) | ((G & 0xFF) << 8) | (B & 0xFF);
RGB_MCU[(iid * (8 * nb_MCU_H) + jid)] = ARGB;
}
}
在主机代码中,我为 4 个新变量创建并分配了内存:
Y_ForGPU= (cl_uchar *)malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
Cb_ForGPU= (cl_uchar *)malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
Cr_ForGPU= (cl_uchar *)malloc(MCU_sx * MCU_sy * max_ss_h * max_ss_v);
//Now will do it for RGB
RGB_testing= (cl_uint *)malloc (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int));
我按以下方式创建了缓冲区:
cl_mem for_Y= clCreateBuffer(context, CL_MEM_READ_WRITE| CL_MEM_COPY_HOST_PTR, (MCU_sx * MCU_sy * max_ss_h * max_ss_v), Y_ForGPU, &ret);
cl_mem for_Cb= clCreateBuffer(context, CL_MEM_READ_WRITE| CL_MEM_COPY_HOST_PTR, (MCU_sx * MCU_sy * max_ss_h * max_ss_v), Cb_ForGPU , &ret);
cl_mem for_Cr= clCreateBuffer(context, CL_MEM_READ_WRITE| CL_MEM_COPY_HOST_PTR, (MCU_sx * MCU_sy * max_ss_h * max_ss_v), Cr_ForGPU, &ret);
//rgb_MCU for YCbCrtoARGB
cl_mem RGB_GPU= clCreateBuffer(context, CL_MEM_READ_WRITE, (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int)), NULL, &ret);
然后我设置内核参数,执行内核并将计算的数据发送回主机:
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), &for_Y);
ret |= clSetKernelArg(color_kernel, 1, sizeof(cl_mem), &for_Cb);
ret |= clSetKernelArg(color_kernel, 2, sizeof(cl_mem), &for_Cr);
ret |= clSetKernelArg(color_kernel, 3, sizeof(cl_mem), &RGB_GPU);
ret |= clSetKernelArg(color_kernel, 4, sizeof(cl_uint), &max_ss_h);
ret |= clSetKernelArg(color_kernel, 5, sizeof(cl_uint), &max_ss_v);
const size_t itemColor[2] = {100, 100};
ret = clEnqueueNDRangeKernel(command_queue, color_kernel, 2, NULL, itemColor, NULL, 0, NULL, NULL);
clFinish(command_queue);
//Copy result to the host
ret = clEnqueueReadBuffer(command_queue, RGB_GPU, CL_TRUE, 0, (MCU_sx * MCU_sy * max_ss_h * max_ss_v * sizeof(cl_int)), RGB_testing, 0, NULL, NULL);
但是,现在我的代码突然终止了。为什么会发生这种情况?
更新:
我的代码现在可以工作了。这些问题可能是由于指针的差异而发生的。我将 Y、Cb、Cr 和 RGB 变量(我创建的)设置为等于主机代码中的原始变量。
//---Setting color variables equal to array elements----//
Y_ForGPU= YCbCr_MCU[0];
Cb_ForGPU= YCbCr_MCU[1];
Cr_ForGPU= YCbCr_MCU[2];
//----RGB is being assigned value-----//
RGB_testing= RGB_MCU;
我不知道这是否是导致您出现问题的唯一原因(可能还有更多我尚未发现),但您的 YCbCr_MCU
内核参数中存在类型不匹配问题。你不能有指针到指针的参数,这是真的。不过,简单地删除 *
并不能解决问题。
特别是行
MCU_Cb = &YCbCr_MCU[1];
在内核中,从 YCbCr_MCU 指向的任何内容的开始处获取 1 个字节,从主机代码来看,这实际上是指针数组的开始,而不是像素数组。
ret = clSetKernelArg(color_kernel, 0, sizeof(cl_mem), (void *)&colorMCU_GPU);
看起来 YCbCr_MCU
应该是一个包含 3 个指向包含源像素的 Y、Cb、Cr 平面的指针的数组。您需要将它们作为指向 3 个数组的 3 个直接指针而不是指向 3 个指针的指针传递给您的内核。换句话说,把它变成Y,Cb,Cr参数,在主机上设置为colorMCU_GPU[0]
到colorMCU_GPU[2]
。