我正在尝试进行一些数据压缩实验。我正在尝试将3D纹理压缩到哈希表中,以避免存储空的卷信息。
为此,我编写了哈希函数和检索函数(它们在不同的着色器中):
struct Voxel
{
int filled;
ivec4 position;
vec4 normal;
vec4 color;
};
layout(std430, binding = 0) buffer voxel_buffer
{
uint index;
Voxel voxels[];
};
// Data storing shader
int a_size = 10000000;
void insert(vec3 pos, Voxel value) {
ivec3 discretized = ivec3(pos / v_size);
int index = int(pow(7, discretized.x) * pow(2, discretized.y) * pow(3, discretized.z)) % a_size;
for(int i=0; i<50; i++) {
if(atomicCompSwap(voxels[index].filled, 0, 1) == 0) {
Voxel c_voxel = voxels[index];
value.position = ivec4(discretized, 1);
voxels[index] = value;
break;
}
index = (index * index) % a_size;
}
}
//Data reading shader
int a_size = 10000000;
vec4 fetch(vec3 pos) {
ivec3 discretized = ivec3(pos / v_size);
int index = int(pow(7, discretized.x) * pow(2, discretized.y) * pow(3, discretized.z)) % a_size;
for(int i=0; i<50; i++) {
Voxel c_voxel = voxels[index];
if(ivec4(discretized,1) == voxels[index].position)
return voxels[index].color;
index = (index * index) % a_size;
}
}
但是我当前的问题是我缺少大约90%的体素值:
预期结果是:
我对可能出什么问题有一些想法,但似乎没有:
哈希数大于数组大小。我分配了1亿个字节,体素结构的总大小应为4 * 4 * 3 = 48,这使我可以使用的元素总数为2 083 333.33。我将数组的大小限制为一百万,是数组大小的一半,所以我不应该访问未分配的内存。
哈希函数碰撞50次以上,导致大多数元素被丢弃。我可能是错的,但是我使用二次更新来增加哈希索引,这应该比线性更好。而且我也依靠FTA来确保在消化之前唯一的密钥生成。因此,我怀疑如此多的哈希冲突超过50次。此外,保留的体素都在一个很好的区域(线性对角线切片) 似乎与这个假设不符。如果这是一个碰撞问题,我应该看到整体的半均匀分布,而不是这样定义的区域。
驱动程序无法为ssbo分配那么多的vram。我使用的是带有最新NVIDIA驱动程序的GTX 1070,该文档说该规范保证最小大小为128 MB,但大多数实现都允许您分配总内存大小。我分配了1亿个字节,这是上限,并且即使驱动程序将我的内存对齐为128 MB,也不会影响我的计算结果,因为我自己会跟踪逻辑数组的大小。
< / li>关于压缩时为什么丢失这么多信息的任何想法吗?
编辑: 根据评论添加了原子操作
仍然会发生一些内存丢失,但这是预期的。
答案 0 :(得分:2)
您的哈希函数
int(pow(7, discretized.x) * pow(2, discretized.y) * pow(3, discretized.z)) % a_size;
非常差。由于discretized
是ivec3
,因此整个操作都在整数上进行,并且无论何时pow(2, discretized.y)
是0
时,术语discretized.y
将是>= 31
。 ,得出完整的哈希值以评估为0
。另外,对于discretized.y < 0
,您应该得到0,因为结果分数也不能用int
类型表示。此外,index == 0
的二次探测也会失败,因为您将探测相同索引的50倍。