0

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

这是代码(Pixel 结构来自 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 并使缓冲区一维,但我总是遇到同样的异常。有人知道我可以尝试什么吗?

4

2 回答 2

3

除了一个小问题之外,您的代码很好:

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

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

因此,始终在内核 lambda 中按值捕获:

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

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

我手头没有安装 triSYCL,但是经过这个小修改后,您的代码在 hipSYCL 上运行良好(顺便说一下,它也可以在 Mac 上运行,以防您想用两个实现仔细检查您的代码,这可以是有时有帮助)。如果更改 lambda 捕获不能解决您的问题,您可能需要在 triSYCL 的 github 存储库上打开一个问题。

于 2020-09-29T00:31:09.323 回答
0

我同意@illuhad。

我尝试过使用 triSYCL 并在顶部添加了一些富有想象力的东西

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

让它编译(请发布一些完整的代码示例)并且它可以工作。

之所以必须使用[=]而不是,[&]是因为 SYCL 还针对无法从加速器直接访问主机内存的体系结构。

于 2020-09-29T14:44:29.837 回答