用推力对打包的顶点进行排序

Sorting packed vertices with thrust

所以我有一个 PackedVertex 结构的设备数组:

struct PackedVertex {
  glm::vec3 Vertex;
  glm::vec2 UV;
  glm::vec3 Normal;
}

我正在尝试对它们进行排序,以便重复项在数组中聚集在一起;我根本不关心整体顺序。

我尝试通过比较 运行 向量的长度来对它们进行排序,但没有正确排序,所以现在我正在尝试使用 3 stable_sorts 和 binary_operators:

__thrust_hd_warning_disable__
struct sort_packed_verts_by_vertex : public thrust::binary_function < PackedVertex, PackedVertex, bool >
{
    __host__ __device__ bool operator()(const PackedVertex &lhs, const PackedVertex &rhs)
    {
        return lhs.Vertex.x < rhs.Vertex.x || lhs.Vertex.y < rhs.Vertex.y || lhs.Vertex.z < rhs.Vertex.z;
    }
};

__thrust_hd_warning_disable__
struct sort_packed_verts_by_uv : public thrust::binary_function < PackedVertex, PackedVertex, bool >
{
    __host__ __device__ bool operator()(const PackedVertex &lhs, const PackedVertex &rhs)
    {
        return lhs.UV.x < rhs.UV.x || lhs.UV.y < rhs.UV.y;
    }
};

__thrust_hd_warning_disable__
struct sort_packed_verts_by_normal : public thrust::binary_function < PackedVertex, PackedVertex, bool >
{
    __host__ __device__ bool operator()(const PackedVertex &lhs, const PackedVertex &rhs)
    {
        return lhs.Normal.x < rhs.Normal.x || lhs.Normal.y < rhs.Normal.y || lhs.Normal.z < rhs.Normal.z;
    }
};

问题是我现在遇到推力错误:"launch_closure_by_value" 这可能会导致猜测意味着我的排序由于我的运算符而没有收敛。

话虽这么说,但我也很确定这不是我进行此类排序的最佳方式,因此我们将不胜感激任何反馈。

我不相信你的排序函子是正确的。

排序仿函数必须给出一致的排序。让我们只考虑这个:

    return lhs.UV.x < rhs.UV.x || lhs.UV.y < rhs.UV.y;

假设我有两个这样的 UV 数量:

UV1.x: 1
UV1.y: 0
UV2.x: 0
UV2.y: 1

无论我呈现 UV1UV2 的顺序如何,这个函子都会 return true。您的其他函子同样有缺陷。

thrust speak, these are not valid StrictWeakOrdering 函子中。如果我们希望订购 UV1UV2,我们必须提供一个仿函数,它(一致地)returns true 用于一个呈现顺序,false 用于另一个演示顺序。 (唯一的例外是,如果两个呈现的数量确实相等,那么函子应该始终 return 只有一个答案,truefalse,始终如一,无论呈现顺序如何。但是,此处显示的 UV1UV2 并非 "equal" 用于您所需的排序目的,即相同结构的分组。)

以下简单测试似乎对我有用:

$ cat t717.cu
#include <thrust/sort.h>
#include <thrust/device_ptr.h>
#include <iostream>
#include <stdlib.h>

#define DSIZE 64
#define RNG 10

struct PackedVertex {
  float3 Vertex;
  float2 UV;
  float3 Normal;
};

struct my_PV_grouper {

  template <typename T>
  __host__ __device__
  bool operator()(const T &lhs, const T &rhs) const {

    if      (lhs.Vertex.x > rhs.Vertex.x) return true;
    else if (lhs.Vertex.x < rhs.Vertex.x) return false;
    else if (lhs.Vertex.y > rhs.Vertex.y) return true;
    else if (lhs.Vertex.y < rhs.Vertex.y) return false;
    else if (lhs.Vertex.z > rhs.Vertex.z) return true;
    else if (lhs.Vertex.z < rhs.Vertex.z) return false;
    else if (lhs.UV.x > rhs.UV.x) return true;
    else if (lhs.UV.x < rhs.UV.x) return false;
    else if (lhs.UV.y > rhs.UV.y) return true;
    else if (lhs.UV.y < rhs.UV.y) return false;
    else if (lhs.Normal.x > rhs.Normal.x) return true;
    else if (lhs.Normal.x < rhs.Normal.x) return false;
    else if (lhs.Normal.y > rhs.Normal.y) return true;
    else if (lhs.Normal.y < rhs.Normal.y) return false;
    else if (lhs.Normal.z > rhs.Normal.z) return true;
    else return false;
    }
};

int main(){

  PackedVertex h_data[DSIZE];
  PackedVertex *d_data;

  for (int i =0; i < DSIZE; i++)
    h_data[i].Vertex.x = h_data[i].Vertex.y = h_data[i].Vertex.z = h_data[i].UV.x = h_data[i].UV.y = h_data[i].Normal.x = h_data[i].Normal.y = h_data[i].Normal.z = rand()%RNG;
  cudaMalloc(&d_data, DSIZE*sizeof(PackedVertex));
  cudaMemcpy(d_data, h_data, DSIZE*sizeof(PackedVertex), cudaMemcpyHostToDevice);
  thrust::device_ptr<PackedVertex> d_ptr(d_data);
  thrust::sort(d_ptr, d_ptr+DSIZE, my_PV_grouper());
  cudaMemcpy(h_data, d_data, DSIZE*sizeof(PackedVertex), cudaMemcpyDeviceToHost);
  for (int i =0; i < DSIZE; i++)
    std::cout << h_data[i].Vertex.x << " ";
  std::cout << std::endl;
}
$ nvcc -o t717 t717.cu
$ ./t717
9 9 9 9 9 9 9 8 8 8 7 7 7 7 7 7 7 6 6 6 6 6 6 6 6 6 5 5 5 5 5 5 4 4 4 3 3 3 3 3 3 3 3 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 0 0 0 0 0 0
$

如果不清楚,这里没有特别说明推力和函子的用法;用于排序这些项目的基本逻辑需要正确才能进行有效排序。即使您编写了一个简单的串行冒泡排序,也必须使用类似的逻辑。您的函子中呈现的逻辑不能用于提供合理的排序。

如果您的方法还有其他问题,我不能说,因为您没有为此类问题提供适当的 MCVE, which is expected