【发布时间】:2020-01-23 04:02:43
【问题描述】:
我正在使用 c++ 在 mac 上编写一个 OpenCL 应用程序,它在某些情况下会崩溃,具体取决于工作量。 程序因 SIGABRT 而崩溃。
有什么方法可以获取有关错误的更多信息? 为什么要提出 SIGABRT?我能抓住它吗?
编辑: 我知道这个程序很牛逼,但是我会试着解释一下,以防有人想尝试一下。
通过调试我发现SIGABRT的原因是内核超时之一。
该程序是基于图块的 3D 渲染器。这是该算法的 OpenCL 实现:https://github.com/ssloy/tinyrenderer
屏幕分为 8x8 块。其中一个内核(切片器)计算哪些多边形与每个切片重叠,并将结果存储在名为tilePolys 的数据结构中。随后的内核(光栅化器)在每个图块上运行一个工作项,遍历占据图块的多边形列表并将它们光栅化。
平铺程序写入一个整数缓冲区,该缓冲区是多边形索引列表的列表。每个列表的大小都是固定的(polysPerTile + 1 表示计数),其中第一个元素是计数,随后的 polysPerTile 元素是图块中多边形的索引。每个图块都有一个这样的列表。
由于某些原因,在某些情况下,拼贴器会将非常大的多边形计数 (13172746) 写入tilePolys 中的拼贴列表之一。这会导致光栅化器循环很长时间并超时。
奇怪的是,写入大计数的索引永远不会被 tiler 访问。
tiler内核的代码如下:
// this kernel is executed once per polygon
// it computes which tiles are occupied by the polygon and adds the index of the polygon to the list for that tile
kernel void tiler(
// number of polygons
ulong nTris,
// width of screen
int width,
// height of screen
int height,
// number of tiles in x direction
int tilesX,
// number of tiles in y direction
int tilesY,
// number of pixels per tile (tiles are square)
int tileSize,
// size of the polygon list for each tile
int polysPerTile,
// 4x4 matrix representing the viewport
global const float4* viewport,
// vertex positions
global const float* vertices,
// indices of vertices
global const int* indices,
// array of array-lists of polygons per tile
// structure of list is an int representing the number of polygons covering that tile,
// followed by [polysPerTile] integers representing the indices of the polygons in that tile
// there are [tilesX*tilesY] such arraylists
volatile global int* tilePolys)
{
size_t faceInd = get_global_id(0);
// compute vertex position in viewport space
float3 vs[3];
for(int i = 0; i < 3; i++) {
// indices are vertex/uv/normal
int vertInd = indices[faceInd*9+i*3];
float4 vertHomo = (float4)(vertices[vertInd*4], vertices[vertInd*4+1], vertices[vertInd*4+2], vertices[vertInd*4+3]);
vertHomo = vec4_mul_mat4(vertHomo, viewport);
vs[i] = vertHomo.xyz / vertHomo.w;
}
float2 bboxmin = (float2)(INFINITY,INFINITY);
float2 bboxmax = (float2)(-INFINITY,-INFINITY);
// size of screen
float2 clampCoords = (float2)(width-1, height-1);
// compute bounding box of triangle in screen space
for (int i=0; i<3; i++) {
for (int j=0; j<2; j++) {
bboxmin[j] = max(0.f, min(bboxmin[j], vs[i][j]));
bboxmax[j] = min(clampCoords[j], max(bboxmax[j], vs[i][j]));
}
}
// transform bounding box to tile space
int2 tilebboxmin = (int2)(bboxmin[0] / tileSize, bboxmin[1] / tileSize);
int2 tilebboxmax = (int2)(bboxmax[0] / tileSize, bboxmax[1] / tileSize);
// loop over all tiles in bounding box
for(int x = tilebboxmin[0]; x <= tilebboxmax[0]; x++) {
for(int y = tilebboxmin[1]; y <= tilebboxmax[1]; y++) {
// get index of tile
int tileInd = y * tilesX + x;
// get start index of polygon list for this tile
int counterInd = tileInd * (polysPerTile + 1);
// get current number of polygons in list
int numPolys = atomic_inc(&tilePolys[counterInd]);
// if list is full, skip tile
if(numPolys >= polysPerTile) {
// decrement the count because we will not add to the list
atomic_dec(&tilePolys[counterInd]);
} else {
// otherwise add the poly to the list
// the index is the offset + numPolys + 1 as tilePolys[counterInd] holds the poly count
int ind = counterInd + numPolys + 1;
tilePolys[ind] = (int)(faceInd);
}
}
}
}
我的理论是:
- 我错误地实现了用于读取和递增计数的原子函数
- 我使用了不正确的数字格式,导致垃圾被写入
tilePolys - 我的其他内核之一无意中写入了
tilePolys缓冲区
我不认为这是最后一个,因为如果我不将faceInd 写入tilePolys,而是写入一个常量值,那么大多边形数就会消失。
tilePolys[counterInd+numPolys+1] = (int)(faceInd); // this is the problem line
tilePolys[counterInd+numPolys+1] = (int)(5); // this fixes the issue
【问题讨论】:
-
我对 OpenCL C++ 接口并不太熟悉,但在 C 语言中,大多数函数都会返回错误代码或设置错误参数。你在检查这些吗?