Vala プログラミング

WebGPU プログラミング

おなが@京都先端科学大

WebGPU with Firefox Nightly ( Linux ) 2

HTMLとJavaScriptで書かれたWebGPUのサンプルがありましたので、
Firefox Nightlyでトライしてみました。
プログラムは、以下のサイトにあります。
tsherif/webgpu-examples
https://github.com/tsherif/webgpu-examples

triangle
f:id:onagat12:20200617121326p:plain

particles
f:id:onagat12:20200617121444g:plain

cube
f:id:onagat12:20200617121514g:plain

cube-texture-lighting
f:id:onagat12:20200617121553g:plain
・glslang.js を使用している。ただし、最新版を使っています。

import("https://unpkg.com/@webgpu/glslang@0.0.15/dist/web-devel/glslang.js").then(m => m.default())

・example.css, gl-matrix.js, utils/utils.js はそのまま使用している。

言語仕様のバージョンアップがありますので、いくつかプログラム文の変更が必要です。
変更箇所は以下の通り。
1 swapChainFormat

const swapChainFormat = await context.getSwapChainPreferredFormat(device);
=> getSwapChainPreferredFormat()が使えません。
変更
const swapChainFormat = "bgra8unorm";

2 createBuffer関連

const positionBuffer = device.createBuffer({
    size: cubeData.positions.byteLength,
    usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
});
positionBuffer.setSubData(0, cubeData.positions);
=> setSubData()が使えません。
変更
const [positionBuffer, positionMapping] = device.createBufferMapped({
    size: cubeData.positions.byteLength,
    usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST
});
new Float32Array(positionMapping).set(cubeData.positions);
positionBuffer.unmap();

3 createRenderPipeline

const pipeline = device.createRenderPipeline({
    vertexStage: { },
    ・・・
});
 => layout メンバーが必要です。
変更
const pipeline = device.createRenderPipeline({
    layout: device.createPipelineLayout({bindGroupLayouts: []}),
    vertexStage: { },
    ・・・
});

4 createBindGroup関連

const sceneUniformBindGroupLayout = device.createBindGroupLayout({
    bindings: [{ }]
});
=> bindingsが使えません。 entriesを使います。
変更
const sceneUniformBindGroupLayout = device.createBindGroupLayout({
    entries: [{    }]
});

5 copyBufferToTexture

textureLoadEncoder.copyBufferToTexture({
    buffer: textureDataBuffer,
    rowPitch: img.width * 4,
    imageHeight: img.height
 }, 
 ・・・
 =>  GPUBufferCopyViewには、 bytesPerRowメンバーが必要です。
変更
 textureLoadEncoder.copyBufferToTexture({
     buffer: textureDataBuffer,
     bytesPerRow: 4 * 256, // a multiple of 256
     rowPitch: img.width * 4,
     imageHeight: img.height
 }, 
・・・

6 uniform buffer dataのupdate
 requestAnimationFrameループ内で、uniform buffer dataのupdateをします。

sceneUniformBuffer.setSubData(0, mvpMatrix);
=>  setSubDataが使えません。
変更
update用関数を準備し、ループ内で実行する。
function updateBufferData(device, commandEncoder, uniformBuffer, mvpMatricesData) {
    const [srcBuffer, arrayBuffer] = device.createBufferMapped({
        size: 64,
        usage: GPUBufferUsage.COPY_SRC
    });
    new Float32Array(arrayBuffer).set(mvpMatricesData);
    srcBuffer.unmap();

    commandEncoder.copyBufferToBuffer(srcBuffer, 0, uniformBuffer, 0, mvpMatricesData.byteLength);
    srcBuffer.destroy();
}

関数の実行
updateBufferData(device, commandEncoder, sceneUniformBuffer, mvpMatrix);

7 blank, triangle, point について
 これはissueにもなっているのですが、これら3つのプログラムは、直ぐに描画されません。
 何回かリロードを繰り返すと描画できるときがあります。
 解決策として、以下の様にしています。
 cubeやparticlesなどの様に、描画部分に

requestAnimationFrame(function draw() {
    ・・・
    requestAnimationFrame(draw);
});

を入れ、ループ状態にします。