#_*_coding:骆驼翔子-8_*_ 2024-07-10 11:45 采纳率: 93.3%
浏览 2
已结题

pyopencl中传参问题

最近正在用pyopencl编写GPU内核程序,但是遇到问题。
以下是内核程序的代码

__kernel void overlay(__global float4 *bg, __global void* ptrs, __global int *img_info, int num_ptrs) {
    int x = get_global_id(0);
    int y = get_global_id(1);
    int bg_index = (y * 1232 + x);
    for (int i = 0; i < num_ptrs; i++) {
        int left = img_info[i * 4];
        int top = img_info[i * 4 + 1];
        int width = img_info[i * 4 + 2];
        int height = img_info[i * 4 + 3];
        if (x >= left && x < left + width && y >= top && y < top + height) {
            int img_index = ((y - top) * width + (x - left));
            printf("img_index: %d\\n", img_index);
            __global float4 *img = (__global float4 *)(((__global char*)ptrs)[i]);
            // 打印img
            float4 bg_pixel = bg[bg_index];
            float4 img_pixel = img[img_index];
            printf("img_pixel: %f, %f, %f, %f\\n", img_pixel.x, img_pixel.y, img_pixel.z, img_pixel.w);
            float alpha = img_pixel.w / 255.0f;
            float inv_alpha = 1.0f - alpha;
            bg[bg_index] = (float4)(
                bg_pixel.x * inv_alpha + img_pixel.x * alpha,
                bg_pixel.y * inv_alpha + img_pixel.y * alpha,
                bg_pixel.z * inv_alpha + img_pixel.z * alpha,
                bg_pixel.w
            );
        }
    }
}

在内核程序中,我传入了一参数 __global void* ptrs,这个ptrs是一个数组,数组内部包含了100个buffer类型的数据,在此之前,我写了一个程序如下


__kernel void overlay(__global float4 *bg, __global float4 *img, int img_width, int img_height, int bg_w, int bg_h, int blit_x, int blit_y) {
    int x = get_global_id(0);
    int y = get_global_id(1);

    if (x < img_width && y < img_height && x < bg_w && y < bg_h) {
        int bg_index = (bg_w * (y + blit_y) + x + blit_x) * 4;
        int img_index = (y * img_width + x) * 4;
        if (bg_index >= bg_w * bg_h * 4) {
            return;
        }
        if (blit_x + x > bg_w || blit_y + y > bg_h || blit_x + x < 0 || blit_y + y < 0) {
            return;
        }

        float4 bg_pixel = bg[bg_index / 4];
        float4 img_pixel = img[img_index / 4];

        float alpha = img_pixel.w / 255.0f;
        float inv_alpha = 1.0f - alpha;

        bg[bg_index / 4] = (float4)(
            bg_pixel.x * inv_alpha + img_pixel.x * alpha,
            bg_pixel.y * inv_alpha + img_pixel.y * alpha,
            bg_pixel.z * inv_alpha + img_pixel.z * alpha,
            bg_pixel.w
        );
    }
}

这两个内核程序都是进行贴图操作,但是第二个程序正常运行,第一个报错。这是因为我在传参的时候第二个程序传入的是单个buffer数据。但是第一段代码,我传入了一个数组的buffer数据,所以导致出错。那么应该怎么传参呢?
就是如何传大量的buffer图片

  • 写回答

2条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2024-07-10 11:45
    关注

    引自免费微信小程序:皆我百晓生

    在 OpenCL 和 PyOpenCL 中,当你需要传递一个数组类型的参数时,不能直接传递一个数组类型的缓冲区。你需要为每个缓冲区单独分配内存,并在调用内核时传递它们的指针。在你的例子中,你需要传递一个包含多个图像缓冲区的数组,你可以通过以下步骤来实现:

    1. 分配内存: 首先为每个图像分配 GPU 内存。这可以通过调用 clCreateBuffer 来完成。对于每个图像,你将得到一个缓冲区对象。将这些对象存储在一个列表中。
    2. 内核调用: 在调用内核时,你将需要一个方法来传递这个包含所有图像缓冲区的列表给内核函数。在 OpenCL 中,你可以使用指针来传递这种结构。在你的例子中,你可以创建一个包含所有这些缓冲区的指针的缓冲区,并将其传递给内核函数。在你的 PyOpenCL 代码中,你需要将这个列表转换为一个一维的缓冲数组,并传递给内核函数。在内核中,你将使用 __global void* ptrs 来接收这个指针数组。
    3. 内核中的处理: 在内核函数中,你可以使用指针算术来访问每个图像缓冲区。由于 ptrs 是一个指针数组,你可以使用索引来获取每个图像的指针。在你的循环中,对于每个图像,你将使用这个指针来访问图像的像素数据。

    以下是一个简化的代码示例,展示了如何在 PyOpenCL 中实现这个过程:

    # 假设 img_buffers 是一个包含所有图像缓冲区的列表
    # 创建一维缓冲区来存储这些指针
    ptr_buffer = cl.Buffer(context, cl.MEM_READ_WRITE, size=num_images * sizeof(cl.Buffer))
    
    # 将每个图像的缓冲区地址写入 ptr_buffer
    for i, img_buffer in enumerate(img_buffers):
        ptr_buffer_device = ptr_buffer.device_pointer + i * sizeof(cl.Buffer)
        queue.enqueue_write_buffer(ptr_buffer, ptr_buffer_device, img_buffer)
    
    # 在内核调用中传递 ptr_buffer
    kernel_overlay(bg_buffer, ptr_buffer, img_info_buffer, num_images)
    

    在内核代码中,你可以像这样访问这些图像:

    __kernel void overlay(__global float4 *bg, __global void* ptrs, __global int *img_info, int num_images) {
        // ...(与你的代码相同)
        for (int i = 0; i < num_images; i++) {
            __global float4 *img = (__global float4 *)((char*)ptrs)[i]; // 使用指针算术访问图像数据
            // ...(处理图像)
        }
    }
    

    这样,你就可以在 GPU 上并行处理多个图像了。请注意,你需要确保 img_info 缓冲区包含正确的信息来识别每个图像的边界和尺寸。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论 编辑记录
查看更多回答(1条)

报告相同问题?

问题事件

  • 系统已结题 7月18日
  • 已采纳回答 7月10日
  • 创建了问题 7月10日

悬赏问题

  • ¥15 CCF-CSP 2023 第三题 解压缩(50%)
  • ¥30 comfyui openpose报错
  • ¥20 Wpf Datarid单元格闪烁效果的实现
  • ¥15 图像分割、图像边缘提取
  • ¥15 sqlserver执行存储过程报错
  • ¥100 nuxt、uniapp、ruoyi-vue 相关发布问题
  • ¥15 浮窗和全屏应用同时存在,全屏应用输入法无法弹出
  • ¥100 matlab2009 32位一直初始化
  • ¥15 Expected type 'str | PathLike[str]…… bytes' instead
  • ¥15 三极管电路求解,已知电阻电压和三级关放大倍数