关于gpu:在-WebGPU-中使用时间戳查询

4次阅读

共计 2542 个字符,预计需要花费 7 分钟才能阅读完成。

原文 https://github.com/OmarShehat…


本文如何应用 WebGPU 的工夫戳查问(timestamp-query)性能来计算你的 GPU 指令执行耗时。

在 WebGPU 中,工夫戳查问是一项可选性能,不肯定全副实现版本都有。撰写本文时,出于平安思考,在浏览器上是禁用的(具体起因参考 gpuweb/gpuweb #2218)

概述

上面先简略介绍工夫戳查问的流程:

  • 申请设施对象时加上 timestamp-query 性能申请
  • 创立一个容量为 N 的查问集(以后帧要存多少个工夫戳)
  • 创立一个存储型缓冲对象(storage-buffer),大小为 8×N 字节,因为工夫戳查问的后果须要用 64 位存储;
  • 调用 commandEncoder.writeTimestamp 办法记录时间戳;它会在所有的指令完结后记录时间戳;
  • 调用 commandEncoder.resolveQuerySet 办法将工夫戳查问后果写入存储型缓冲
  • 将存储型缓冲复制到 CPU 可读的内存中,解码为 BigInt64Array(参考 BigInt – JavaScript | MDN)

按步教学

可在这个 PR 中找到残缺的示例:Example usage of timestamp queries by OmarShehata · Pull Request #5 · OmarShehata/webgpu-compute-rasterizer · GitHub

0. 让浏览器具备工夫戳查问性能

默认浏览器是敞开不平安的 API 的,应用下列参数启动 Chrome 浏览器即可:

--disable-dawn-features=disallow_unsafe_apis

译者注:从 --disable-dawn-features 能够看出,这个启动参数是 Chrome 系特有的,火狐和 Safari 不通用。具体操作能够右击 Chrome 或 Edge 的快捷方式,在“属性”–“指标”后追随这一串字符串。

1. 创立 Queryset 和缓冲对象

申请设施对象时,须要把 timestamp-query 增加进 requiredFeatures 数组中:

const device = await adapter.requestDevice({requiredFeatures: ["timestamp-query"],
})

如果浏览器未启用工夫戳查问或者不反对,就会报错:

Uncaught (in promise) TypeError: Failed to execute 'requestDevice' on 'GPUAdapter': Unsupported feature: timestamp-query

而后,创立一个查问集和查问缓冲对象:

const capacity = 3 // 要存多少个查问后果
const querySet = device.createQuerySet({
  type: "timestamp",
  count: capacity,
})
const queryBuffer = device.createBuffer({
  size: 8 * capacity,
  usage: GPUBufferUsage.QUERY_RESOLVE 
    | GPUBufferUsage.STORAGE
    | GPUBufferUsage.COPY_SRC
    | GPUBufferUsage.COPY_DST,
})

2. 写入工夫戳

在调配渲染管线的代码之间,调用 commandEncoder.writeTimestamp(querySet, index) 办法记录时间戳:

// 在各种指令编码过程中记录时间戳
commandEncoder.writeTimestamp(querySet, 0) // 初始工夫戳
// draw(...)
commandEncoder.writeTimestamp(querySet, 1)

index <= 定义的容量值 – 1.

3. 解析工夫戳到缓冲对象中

在每一帧代码的开端,调用 commandEncoder.resolveQuerySet 办法,以正确写入存储型缓冲对象:

commandEncoder.resolveQuerySet(
  querySet, 
  0, // 从哪个查问开始
  capacity, // 要写入多少个查问
  queryBuffer, 
  0 // 写入缓冲对象的偏移值
)

4. 读取查问后果

即从存储型缓冲对象读取数据。获取 ArrayBuffer 后,用 BigInt 类型数组读取即可。工夫戳值的单位是纳秒。

// === `commandEncoder.finish()` 调用之后 ===
// 应用上面的 readBuffer 函数读取 queryBuffer 对象中的数据
const arrayBuffer = await readBuffer(device, queryBuffer);
// 应用 BigInt 类型数组读取数据
const timingsNanoseconds = new BigInt64Array(arrayBuffer);

const readBuffer = async (device, buffer) => {
  const size = buffer.size
  const gpuReadBuffer = device.createBuffer({
    size,
    usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ 
  })

  const copyEncoder = device.createCommandEncoder()
  copyEncoder.copyBufferToBuffer(buffer, 0, gpuReadBuffer, 0, size)

  const copyCommands = copyEncoder.finish()
  device.queue.submit([copyCommands])

  await gpuReadBuffer.mapAsync(GPUMapMode.READ)
  return gpuReadBuffer.getMappedRange()}

5. (可选) 增加标签

为了让输入信息更加敌对,可将每个工夫戳加上标签,输入的时候有利于分别差别。将纳秒转为毫秒也有用。

致谢

非常感谢 Markus Schütz 在 Potree 对于 WebGPU 无关实现中 提供的工夫戳查问示例。

感激顾扬在 问题 3354 中解释了如何在 Chrome 中启用工夫戳查问。

正文完
 0