【问题标题】:Calculations in GPU.js giving different results in CPU and GPU modesGPU.js 中的计算在 CPU 和 GPU 模式下给出不同的结果
【发布时间】:2022-12-29 05:47:41
【问题描述】:

我正在尝试使用 GPU.js 绘制 Mandelbrot 集。

我遇到的一个问题是内核函数中的数学在 CPU 模式和 GPU 模式下运行时给出不同的结果。这是内核函数和支持代码:

function inlineTestPoint(initialReal, initialImag, maxIterations) {
  let currentReal = initialReal;
  let currentImag = initialImag;

  let i = 0;
  for (;i < maxIterations; i++) {
    const curRealSq = (currentReal * currentReal);
    const curImagSq = (currentImag * currentImag);
    if (curRealSq + curImagSq <= 4) {
      currentImag = (2 * currentReal * currentImag) + initialImag;
      currentReal = (curRealSq - curImagSq) + initialReal;
    } else {
      break;
    }
  }

  return i;
}

function mapRange(n, sourceMin, sourceMax, targetMin, targetMax) {
  const sourceRatio = (n - sourceMin) / (sourceMax - sourceMin);

  return (sourceRatio * (targetMax - targetMin)) + targetMin;
}

const canvasWidth = 1000;
const canvasHeight = 1000;

const gpu = new GPU({mode: "gpu"});
gpu.addFunction(mapRange, {argumentTypes: ['Float', 'Float', 'Float', 'Float', 'Float'], returnType: 'Float'});
gpu.addFunction(inlineTestPoint, {source: inlineTestPoint, argumentTypes: ['Float', 'Float', 'Float'], returnType: 'Integer'});
const kernel = gpu.createKernel(function(canvasWidth,canvasHeight) {
  const canvasX = this.thread.x;
  const canvasY = this.thread.y;
  const real = mapRange(canvasX, 0, canvasWidth, -2, 2);
  const imag = mapRange(canvasY, 0, canvasHeight, -2, 2);

  const iters = inlineTestPoint(real, imag, 200);
  this.color(iters / 50, iters / 100, iters / 200);
  //return [real, imag, iters];
})
  .setGraphical(true)
  .setLoopMaxIterations(200)
  .setOutput([canvasWidth, canvasHeight]);

kernel(canvasWidth, canvasHeight);

在 CPU 模式下运行时,每个像素的 iters 都符合我的预期(使用 CPU 模式下可用的断点进行验证)。

但是在 GPU 模式下,iters 始终为 0。我可以通过关闭图形模式并从内核函数返回 iters 来看到这一点。虽然这是相同的数学,所以我不明白为什么它在 CPU 和 GPU 上运行会有什么不同。这也证明很难调试,因为调试的唯一方法是从内核返回值。

什么可能导致结果发生变化?

【问题讨论】:

    标签: javascript gpu.js


    【解决方案1】:

    原因似乎是参数被视为整数并被截断。 CPUKernelsGPUKernels 似乎以不同方式推断类型,这导致在我的例子中,mapRange 的参数被视为整数。或者至少,这就是我的猜测。我可以通过为函数和 seei 指定不同的类型来推断

    最小的修复是将 argumentTypes 添加到对 mapRangeaddFunction 的调用中,但为了安全起见,我最终为这两个函数添加了类型:

    gpu.addFunction(mapRange, {argumentTypes: ['Float', 'Float', 'Float', 'Float', 'Float'], returnType: 'Float'});
    gpu.addFunction(inlineTestPoint, {source: inlineTestPoint, argumentTypes: ['Float', 'Float', 'Float'], returnType: 'Integer'});
    

    这解决了它。

    如果您遇到这样的问题,我建议明确设置类型。我现在将开始为所有功能添加它们,只是为了完全避免这个问题。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-07-24
      • 2016-07-16
      • 2014-01-28
      • 1970-01-01
      • 2015-12-24
      • 1970-01-01
      • 1970-01-01
      • 2020-05-07
      相关资源
      最近更新 更多