Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用结构作为缓冲支架_C++_C_Opencl - Fatal编程技术网

C++ 使用结构作为缓冲支架

C++ 使用结构作为缓冲支架,c++,c,opencl,C++,C,Opencl,在我当前的OpenCL实现中,我希望通过参数节省时间,避免每次我想在内核中使用缓冲区时都传递参数,并为内核提供一个较短的参数列表 因此,我创建了一个结构(工作区),其中保存了指向设备内存中缓冲区的指针,该结构的行为就像一个对象,其中包含您希望随时间访问的成员变量,并且希望在整个执行过程中保持活动状态。我从来没有在AMD GPU甚至CPU上遇到过问题。但是Nvidia在这方面造成了很多问题。这似乎总是一个对齐问题,从未到达正确的缓冲区,等等 下面是一些帮助代码,请参见下面的问题: 在主机上定义的结

在我当前的OpenCL实现中,我希望通过参数节省时间,避免每次我想在内核中使用缓冲区时都传递参数,并为内核提供一个较短的参数列表

因此,我创建了一个结构(工作区),其中保存了指向设备内存中缓冲区的指针,该结构的行为就像一个对象,其中包含您希望随时间访问的成员变量,并且希望在整个执行过程中保持活动状态。我从来没有在AMD GPU甚至CPU上遇到过问题。但是Nvidia在这方面造成了很多问题。这似乎总是一个对齐问题,从未到达正确的缓冲区,等等

下面是一些帮助代码,请参见下面的问题:

在主机上定义的结构:

 #define SRC_IMG 0       // (float4 buffer) Source image
 #define LAB_IMG 1       // (float4 buffer) LAB image

 // NOTE: The size of this array should be as much as the last define + 1.
 #define __WRKSPC_SIZE__ 2 

 // Structure defined on host.
 struct Workspace
 {
      cl_ulong getPtr[__WRKSPC_SIZE__];
 };

 struct HostWorkspace
 {
      cl::Buffer srcImg;
      cl::Buffer labImg;
 };
设备上定义的结构:

typedef struct __attribute__(( packed )) gpuWorkspace
{
    ulong getPtr[__WRKSPC_SIZE__]; 
} gpuWorkspace_t; 
请注意,在设备上,我使用ulong,在主机上,我使用cl_ulong,如下所示

所以,一旦为源映像或实验室映像创建了cl::Buffer,我就将它们保存到一个HostWorkspace对象中,因此,在释放该对象之前,对cl::Buffer的引用将保持不变,这样,主机上的整个项目和设备上的实际项目都存在缓冲区

现在,我需要向设备提供这些信息,因此我有一个简单的内核,它初始化我的设备工作区,如下所示:

__kernel void Workspace_Init(__global gpuWorkspace_t* wrkspc,
                             __global float4* src,
                             __global float4* LAB)
{
    // Get the ulong pointer on the first element of each buffer.
    wrkspc->getPtr[SRC_IMG] = &src[0];
    wrkspc->getPtr[LAB_IMG] = &LAB[0];
}
__kernel void ComputeLABFromSrc(__global gpuWorkspace_t* wrkSpc)
{
    // =============================================================
    // Get pointer from work space.
    // =============================================================

    // Cast back the pointer of first element as a normal buffer you
    // want to use along the execution of the kernel.
    __global float4* srcData = ( __global float4* )( wrkSpc->getPtr[SRC_IMG] );
    __global float4* labData = ( __global float4* )( wrkSpc->getPtr[LAB_IMG] );

    // Code kernel as usual.
}
其中wrkspc是一个用
结构工作区
分配的缓冲区,src+LAB只是作为1D数组映像分配的缓冲区

之后,在我的任何内核中,如果我想使用src或LAB,我会执行以下操作:

__kernel void Workspace_Init(__global gpuWorkspace_t* wrkspc,
                             __global float4* src,
                             __global float4* LAB)
{
    // Get the ulong pointer on the first element of each buffer.
    wrkspc->getPtr[SRC_IMG] = &src[0];
    wrkspc->getPtr[LAB_IMG] = &LAB[0];
}
__kernel void ComputeLABFromSrc(__global gpuWorkspace_t* wrkSpc)
{
    // =============================================================
    // Get pointer from work space.
    // =============================================================

    // Cast back the pointer of first element as a normal buffer you
    // want to use along the execution of the kernel.
    __global float4* srcData = ( __global float4* )( wrkSpc->getPtr[SRC_IMG] );
    __global float4* labData = ( __global float4* )( wrkSpc->getPtr[LAB_IMG] );

    // Code kernel as usual.
}
当我开始使用它的时候,我有4-5张图片,进展顺利,结构不同,如下所示:

struct Workspace
{
    cl_ulong imgPtr;
    cl_ulong labPtr;
};
每个图像都有自己的指针

在某一点上,我看到了更多的图像,我遇到了一些问题。所以我在线搜索,发现了一些建议,结构的sizeof()在设备/主机之间可能不同,所以我将其更改为一个相同时间的单个数组,在16个元素之前都可以正常工作

因此,我搜索了更多信息,发现了一个关于属性的建议(打包),我把它放在了设备结构上(见上文)。但现在,我看到26个元素,当我在设备或主机上检查结构的大小时,大小是208(elements*sizeof(cl_ulong)==26*8)。但我仍然有一个类似的问题,我以前的模型,我的指针读取其他地方在前一个图像的中间,等等< /P> 所以我想知道,是否有人曾经尝试过类似的模型(可能采用不同的方法),或者有任何技巧可以用它来建立一个“可靠”的模型


请注意,所有内核都经过了很好的编码,在AMD或CPU上使用相同的代码执行时,我有一个很好的结果。唯一的问题是关于Nvidia

不要试图跨内核边界存储GPU端指针值。它们不能保证保持不变。始终使用索引。如果内核使用特定的缓冲区,则需要将其作为参数传递给该内核

参考资料:

  • OpenCL1.2规范(据我所知,nvidia没有实现更新的标准)没有定义指向整数强制转换的指针的行为,反之亦然
  • 第6.9p节指出:“声明为结构或联合的内核函数的参数不允许OpenCL对象作为结构或联合的元素传递。”这正是您试图做的:将缓冲区结构传递给内核
  • 第6.9a节指出:“程序中内核函数的参数不能声明为指向指针的指针。”-这本质上就是您试图通过将指针转换为整数并返回来颠覆的。(第1点)您不能通过绕过类型系统来“欺骗”OpenCL,使其具有良好的定义

  • 正如我在下面的注释线程中所建议的,您需要使用索引来保存缓冲区对象中的位置。如果要跨不同的内存区域存储位置,则需要将多个缓冲区统一为一个缓冲区,并将一个索引保存到这个巨大的缓冲区中,或者保存一个数字值来标识所引用的缓冲区。

    不要尝试跨内核边界存储GPU端指针值。它们不能保证保持不变。始终使用索引。如果内核使用特定的缓冲区,则需要将其作为参数传递给该内核

    参考资料:

  • OpenCL1.2规范(据我所知,nvidia没有实现更新的标准)没有定义指向整数强制转换的指针的行为,反之亦然
  • 第6.9p节指出:“声明为结构或联合的内核函数的参数不允许OpenCL对象作为结构或联合的元素传递。”这正是您试图做的:将缓冲区结构传递给内核
  • 第6.9a节指出:“程序中内核函数的参数不能声明为指向指针的指针。”-这本质上就是您试图通过将指针转换为整数并返回来颠覆的。(第1点)您不能通过绕过类型系统来“欺骗”OpenCL,使其具有良好的定义

  • 正如我在下面的注释线程中所建议的,您需要使用索引来保存缓冲区对象中的位置。如果您想跨不同的内存区域存储位置,您需要将多个缓冲区统一为一个,并将一个索引保存到这个巨大的缓冲区中,或者保存一个数字值来标识您所指的缓冲区。

    关于
    始终使用索引,您能否更具体一些?我不明白。@Vuwox如果需要在缓冲区中保存从一个内核调用到另一个内核调用的位置,则需要使用整数数组索引,而不是指针。OpenCL不允许在结构中包含指针。所以我已经在你的术语中存储了“索引”。你是说我应该这样做:
    wrkspc->getPtr[SRC_IMG]=SRC[0]而不是
    &src[0]
    ?因为这只会将包含的值存储在imo的位置0。我不明白。OpenCL允许在结构中使用指针