首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >为什么我的OpenCL 3d图像查找不能工作?

为什么我的OpenCL 3d图像查找不能工作?
EN

Stack Overflow用户
提问于 2016-01-05 21:39:03
回答 1查看 818关注 0票数 0

我在编写OpenCL内核时遇到了问题,它产生了不正确的结果(与一个引用的、蛮力的CPU实现相比)。

我跟踪这个问题直到我使用的3D查找表,它似乎是返回垃圾结果,而不是我传入的值。

我有以下(简化的) OpenCL内核,用于从3D图像类型读取预先计算的函数:

代码语言:javascript
运行
复制
__constant sampler_t legSampler = CLK_NORMALIZED_COORDS_TRUE | CLK_ADDRESS_CLAMP_TO_EDGE | CLK_FILTER_LINEAR;

inline float normalizedLegendre(int n, int m, float z, image3d_t legendreLUT)
{
  float nCoord = (((float) n) / get_image_width(legendreLUT));
  float mCoord = (((float) m) / get_image_height(legendreLUT));
  float zCoord = ((z + 1.0f) / 2.0f);
  float4 coord = (float4)(floor(nCoord) + 0.5f, floor(mCoord) + 0.5f, zCoord, 0.0f);

  return read_imagef(legendreLUT, legSampler, coord).x;

}

_kernel void noiseMain(__read_only image3d_t legendreLUT, __global float* outLegDump)
{

  //k is the linear index into the array.
  int k = get_global_id(0);

  if(k < get_image_depth(legendreLUT))
  {
    float z = ((float) k / (float) get_image_depth(legendreLUT)) * 2.0 - 1.0;
    float legLookup = normalizedLegendre(5, 4, z, legendreLUT);
    float texCoord = ((float) k / 1024.0) * 2 - 1;
    outLegDump = legLookup;
  }
}

在主机端,我使用以下代码生成3D图像legendreLUT:

代码语言:javascript
运行
复制
  static const size_t NLEGPOLYBINS = 1024;
  static const size_t NLEGPOLYORDERS = 16;
  boost::scoped_array<float> legendreHostBuffer(new float[NLEGPOLYORDERS * NLEGPOLYORDERS * NLEGPOLYBINS]);
  float stepSize = 1.0 / (((float) NLEGPOLYBINS/2.0) - 0.5);

  float z = -1.0;

  std::cout << "Generating legendre polynomials..." << std::endl;

  for(size_t n = 0; n < NLEGPOLYORDERS; n++)
    {
      for(size_t m = 0; m < NLEGPOLYORDERS; m++)
    {
      for(size_t zI = 0; zI < NLEGPOLYBINS; zI++)
        {
          using namespace boost::math;
          size_t index = (n * NLEGPOLYORDERS * NLEGPOLYBINS) + (m * NLEGPOLYBINS) + zI;
          //-1..1 in NLEGPOLYBINS steps...
          float val;
          if(m > n) 
        {
          legendreHostBuffer[index] = 0;
          continue;
        }
          else
        {
          //boost::math::legendre_p
          val = legendre_p<float>(n,m,z);
        }

          float nPm = n+m;
          float nMm = n-m;
          float factNum;
          float factDen;

          factNum = factorial<float>(n-m);
          factDen = factorial<float>(n+m);

          float nrmTerm;

          nrmTerm = pow(-1.0, m) * sqrt((n + 0.5) * (factNum/factDen));
          legendreHostBuffer[index] = val;
          z += stepSize;
          if(z > 1.0) z + 1.0;                   
        }
      z = -1.0;
    }
    }

  //DEBUGGING STEP: Dump everything we've just generated for m = 4, n = 5, z=-1..1
  std::ofstream legDump("legDump.txt");

  for(size_t i = 0; i < NLEGPOLYBINS; i++)
    {
      int n =5; int m = 4;
      size_t index = (n * NLEGPOLYORDERS * NLEGPOLYBINS) + (m * NLEGPOLYBINS) + i;

      float texCoord = ((float) i / (float) NLEGPOLYBINS) * 2 - 1;

      legDump << i << " " << texCoord << " " << legendreHostBuffer[index] << std::endl;
    }

  legDump.close();


  std::cout << "Creating legendre polynomial look up table image..." << std::endl;

  cl::ImageFormat legFormat(CL_R, CL_FLOAT);
  //Generate out legendre polynomials image...
  m_legendreTable = cl::Image3D(m_clContext,
                CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
                legFormat, 
                NLEGPOLYORDERS,
                NLEGPOLYORDERS,
                NLEGPOLYBINS,
                0,
                0,
                legendreHostBuffer.get());

除了索引之外,值的实际生成或多或少是不相关的,但是为了完整性,我已经在这里包含了它。

下面是我如何执行内核并读取结果:

代码语言:javascript
运行
复制
  cl::Buffer outLegDump = cl::Buffer(m_clContext, CL_MEM_WRITE_ONLY, NLEGPOLYBINS * sizeof(float));

  //Create out kernel...
  cl::Kernel kernel(m_program, "noiseMain");


  kernel.setArg(0, m_legendreTable);
  kernel.setArg(1, outLegDump);

  size_t kernelSize = 1024;

  cl::NDRange globalRange(kernelSize);

  cl::NDRange localRange(1);

  m_commandQueue.enqueueNDRangeKernel(kernel, cl::NullRange, globalRange, cl::NullRange);
  m_commandQueue.finish();

  boost::scoped_array<float> legDumpHost(new float[NLEGPOLYBINS]);
  m_commandQueue.enqueueReadBuffer(outLegDump, CL_TRUE, 0, NLEGPOLYBINS * sizeof(float), legDumpHost.get());

  std::ofstream legreadback("legreadback.txt");

  for(size_t i = 0; i < NLEGPOLYBINS; i++)
    {
      legreadback << i << " "  << legDumpHost[i] << std::endl;
    }

  legreadback.close();

当我查看转储数据(即从主机端缓冲区输出的legdump.txt数据)时,我得到了预期的数据。但是,当我将它与从设备端收到的数据(即内核查找并在legreadback.txt中输出的数据)进行比较时,我得到了不正确的值。

由于在这两种情况下我都在计算1024个值,所以我会让每个人省去整个转储,但是,下面是每个值的前几个/最后几个值:

legdump.txt (主机侧健康检查):

代码语言:javascript
运行
复制
0 -0
1 -0.0143913
2 -0.0573401
3 -0.12851
4 -0.227566
5 -0.354175
..
..
1020 0.12859
1021 0.0144185
1022 0.0144185
1023 1.2905e-8

legreadback.txt (设备端查找和读取)

代码语言:javascript
运行
复制
0 1
1 1 
2 1
3 1
4 0.5
5 0
..
..
1020 7.74249e+11
1021 -1.91171e+15
1022 -3.81029e+15
1023 -1.91173e+15

请注意,这些值在多个代码运行中是相同的,因此我不认为这是初始化问题。

我只能假设我在某个地方计算指数错误,但我不知道在哪里。我检查了Z坐标的计算(自然是在-1.1上定义的),将其转换为纹理坐标(0..1范围),以及将M和N转换为纹理坐标(应该不进行插值),没有发现任何错误。

因此,我的问题是:

在OpenCL中创建和索引3D查找表的正确方法是什么?

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2016-01-07 15:52:42

正如预期的那样,问题最终出现在用于生成查找表的主机端的索引中。

先前的指数计算:

代码语言:javascript
运行
复制
 size_t index = (n * NLEGPOLYORDERS * NLEGPOLYBINS) + (m * NLEGPOLYBINS) + zI;

是基于C++三维数组索引,这不是在OpenCL中对3D图像进行寻址的方式。3D图像可以被认为是在彼此之上的2D图像的“叠加”,其中深度坐标(在这种情况下是Z)选择图像,而水平和垂直坐标(在这种情况下是m和n)选择所选图像中的像素。

正确的索引计算是:

代码语言:javascript
运行
复制
size_t index = m * NLEGPOLYORDERS + n + (zI * NLEGPOLYORDERS * NLEGPOLYORDERS);

可以看到,这种新方法符合前面描述的“叠加图像”布局,而以前的计算则不适合。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/34621693

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档