EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 索引访问器时

EXC_BAD_ACCESS (code=EXC_I386_GPFLT) when indexing accessor

我想 运行 一个并行的 for 循环来初始化一个具有随机值的二维缓冲区。但是我在内核的第一行得到了一个 EXC_BAD_ACCESS (code=EXC_I386_GPFLT) 异常。

这是代码(像素结构来自 PixelGameEngine 库):

namespace olc
{
    struct Pixel
    {
        union
        {
            uint32_t n = nDefaultPixel;
            struct
            {
                uint8_t r;
                uint8_t g;
                uint8_t b;
                uint8_t a;
            };
        };

        enum Mode
        {
            NORMAL, MASK, ALPHA, CUSTOM
        };

        Pixel()
        {
            r = 0;
            g = 0;
            b = 0;
            a = nDefaultAlpha;
        }

        Pixel(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha = nDefaultAlpha)
        {
            n = red | (green << 8) | (blue << 16) | (alpha << 24);
        }

        Pixel(uint32_t p) { n = p; }
    };
}

 int main()
{
    auto* screenBuffer = new olc::Pixel[256 * 240];

    cl::sycl::queue queue;
    {
        cl::sycl::buffer<olc::Pixel, 2> b_screenBuffer(screenBuffer,
                                                       cl::sycl::range<2>(256, 240));

        queue.submit([&](cl::sycl::handler& cgh) {
            auto screenBuffer_acc = b_screenBuffer.get_access<cl::sycl::access::mode::write>(cgh);

            cgh.parallel_for(cl::sycl::range<2>(256, 240), [&](cl::sycl::id<2> index) {
                screenBuffer_acc[index] = olc::Pixel(rand() % 256, //Here I get the exception 
                                                     rand() % 256,
                                                     rand() % 256);
            });
        });
    }

    return 0;
}

我在 Mac OS Catalina 上使用 triSYCL 0.1.0,boost 1.74 和 C++20。我试图将缓冲区的数据类型从 old::Pixel 更改为 float 并使缓冲区成为 1 维,但我总是遇到相同的异常。 有人知道我可以尝试什么吗?

除了一个小问题外,您的代码还不错:

cgh.parallel_for(cl::sycl::range<2>(256, 240), [&](cl::sycl::id<2> index) {...}

此处您在内核中通过引用捕获变量。永远不要这样做。 如果您的目标是加速器(例如 GPU),则捕获的变量将引用主机内存并在设备上访问时崩溃。如果你只针对 CPU,它仍然是未定义的行为,因为内核是异步执行的,当内核是 运行.

时,捕获的变量可能不再存在

因此,在内核lambdas中总是按值捕获:

cgh.parallel_for(cl::sycl::range<2>(256, 240), [=](cl::sycl::id<2> index) {...}

在命令组范围 queue.submit([&](sycl::handler& cgh){...}) 的 lambda 中,通过引用捕获总是没问题,因为命令组范围总是在主机上同步计算。

我手头没有安装 triSYCL,但是在这个小修改之后你的代码 运行 可以使用 hipSYCL(顺便说一下,运行s 在 Mac 上,如果你想 double-check 你的代码有两个实现,这有时会有帮助)。 如果更改 lambda 捕获不能解决您的问题,您可能想在 triSYCL 的 github 存储库上提出问题。

我同意@illuhad。

我试过 triSYCL 并在顶部添加了一些想象力

#include "CL/sycl.hpp"
constexpr auto nDefaultPixel = 2;
constexpr auto nDefaultAlpha = 42;

让它编译(请 post 一些完整的代码示例)并且它有效。

您必须使用 [=] 而不是 [&] 的原因是因为 SYCL 还针对您无法从加速器直接访问主机内存的架构。