Title: [249446] trunk/Websites/webkit.org
Revision
249446
Author
justin_...@apple.com
Date
2019-09-03 17:20:57 -0700 (Tue, 03 Sep 2019)

Log Message

[WebGPU] Add compute-boids to WebGPU demo page
https://bugs.webkit.org/show_bug.cgi?id=201416

Reviewed by Dean Jackson.

Add the compute-boids demo for use with STP 91.

* demos/webgpu/compute-boids.html: Added.
* demos/webgpu/index.html:
* demos/webgpu/resources/compute-boids.png: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/Websites/webkit.org/ChangeLog (249445 => 249446)


--- trunk/Websites/webkit.org/ChangeLog	2019-09-03 23:37:12 UTC (rev 249445)
+++ trunk/Websites/webkit.org/ChangeLog	2019-09-04 00:20:57 UTC (rev 249446)
@@ -1,3 +1,16 @@
+2019-09-03  Justin Fan  <justin_...@apple.com>
+
+        [WebGPU] Add compute-boids to WebGPU demo page
+        https://bugs.webkit.org/show_bug.cgi?id=201416
+
+        Reviewed by Dean Jackson.
+
+        Add the compute-boids demo for use with STP 91.
+
+        * demos/webgpu/compute-boids.html: Added.
+        * demos/webgpu/index.html:
+        * demos/webgpu/resources/compute-boids.png: Added.
+
 2019-08-06  Justin Fan  <justin_...@apple.com>
 
         [WebGPU] Fix up demos on and add compute demo to webkit.org/demos

Added: trunk/Websites/webkit.org/demos/webgpu/compute-boids.html (0 => 249446)


--- trunk/Websites/webkit.org/demos/webgpu/compute-boids.html	                        (rev 0)
+++ trunk/Websites/webkit.org/demos/webgpu/compute-boids.html	2019-09-04 00:20:57 UTC (rev 249446)
@@ -0,0 +1,373 @@
+<!DOCTYPE html>
+<html>
+
+<head>
+  <meta name="viewport" content="width=1200">
+  <title>WebGPU Compute Flocking</title>
+  <script src=""
+  <link rel="stylesheet" href=""
+  <style>
+  body {
+      font-family: system-ui;
+      color: #f7f7ff;
+      background-color: rgb(38, 38, 127);
+      text-align: center;
+  }
+  canvas {
+      margin: 0 auto;
+  }
+  </style>
+</head>
+<body>
+  <div id="contents">
+    <h1>Compute Flocking</h1>
+    <p>
+        This demo uses a compute shader to update the positions of objects in parallel.
+    </p>
+    <canvas width="1200" height="1200"></canvas>
+  </div>
+  <div id="error">
+      <h2>WebGPU not available</h2>
+      <p>
+          Make sure you are on a system with WebGPU enabled. In
+          Safari, first make sure the Developer Menu is visible (Preferences →
+          Advanced), then Develop → Experimental Features → WebGPU.
+      </p>
+  </div>
+  <script>
+    if (!navigator.gpu)
+      document.body.className = 'error';
+
+    const numParticles = 1500;
+
+    const renderShadersWHLSL = `
+vertex float4 vertex_main(float2 particlePos : attribute(0), float2 particleVel : attribute(1), float2 position : attribute(2)) : SV_Position
+{
+    float angle = -atan(particleVel.x / particleVel.y);
+    float2 result = float2(position.x * cos(angle) - position.y * sin(angle),
+        position.x * sin(angle) + position.y * cos(angle));
+    return float4(result + particlePos, 0, 1);
+}
+
+fragment float4 fragment_main() : SV_Target 0
+{
+    return float4(1.0, 1.0, 1.0, 1.0);
+}
+`;
+
+    const computeShaderWHLSL = `
+struct Particle {
+    float2 pos;
+    float2 vel;
+}
+
+struct SimParams {
+    float deltaT;
+    float rule1Distance;
+    float rule2Distance;
+    float rule3Distance;
+    float rule1Scale;
+    float rule2Scale;
+    float rule3Scale;
+}
+
+[numthreads(1, 1, 1)]
+compute void compute_main(constant SimParams[] paramsBuffer : register(b0), device Particle[] particlesA : register(u1), device Particle[] particlesB : register(u2), float3 threadID : SV_DispatchThreadID) {
+    uint index = uint(threadID.x);
+
+    SimParams params = paramsBuffer[0];
+
+    if (index >= ${numParticles}) { 
+        return;
+    }
+
+    float2 vPos = particlesA[index].pos;
+    float2 vVel = particlesA[index].vel;
+
+    float2 cMass = float2(0.0, 0.0);
+    float2 cVel = float2(0.0, 0.0);
+    float2 colVel = float2(0.0, 0.0);
+    float cMassCount = 0.0;
+    float cVelCount = 0.0;
+
+    float2 pos;
+    float2 vel;
+    for (uint i = 0; i < ${numParticles}; ++i) {
+        if (i == index) { continue; }
+        pos = particlesA[i].pos.xy;
+        vel = particlesA[i].vel.xy;
+
+        if (distance(pos, vPos) < params.rule1Distance) {
+            cMass += pos;
+            cMassCount++;
+        }
+        if (distance(pos, vPos) < params.rule2Distance) {
+            colVel -= (pos - vPos);
+        }
+        if (distance(pos, vPos) < params.rule3Distance) {
+            cVel += vel;
+            cVelCount++;
+        }
+    }
+    if (cMassCount > 0.0) {
+        cMass = cMass / cMassCount - vPos;
+    }
+    if (cVelCount > 0.0) {
+        cVel = cVel / cVelCount;
+    }
+
+    vVel += cMass * params.rule1Scale + colVel * params.rule2Scale + cVel * params.rule3Scale;
+
+    // clamp velocity for a more pleasing simulation.
+    vVel = normalize(vVel) * clamp(length(vVel), 0.0, 0.1);
+
+    // kinematic update
+    vPos += vVel * params.deltaT;
+
+    // Wrap around boundary
+    if (vPos.x < -1.0) vPos.x = 1.0;
+    if (vPos.x > 1.0) vPos.x = -1.0;
+    if (vPos.y < -1.0) vPos.y = 1.0;
+    if (vPos.y > 1.0) vPos.y = -1.0;
+
+    particlesB[index].pos = vPos;
+    particlesB[index].vel = vVel;
+}
+`;
+
+    async function init() {
+      const adapter = await navigator.gpu.requestAdapter();
+      const device = await adapter.requestDevice();
+
+      const canvas = document.querySelector('canvas');
+      const context = canvas.getContext('gpu');
+
+      const swapChain = context.configureSwapChain({
+        device,
+        format: "bgra8unorm"
+      });
+
+      const computeBindGroupLayout = device.createBindGroupLayout({
+        bindings: [
+          { binding: 0, visibility: GPUShaderStageBit.COMPUTE, type: "uniform-buffer" },
+          { binding: 1, visibility: GPUShaderStageBit.COMPUTE, type: "storage-buffer" },
+          { binding: 2, visibility: GPUShaderStageBit.COMPUTE, type: "storage-buffer" },
+        ],
+      });
+
+      const computePipelineLayout = device.createPipelineLayout({
+        bindGroupLayouts: [computeBindGroupLayout],
+      });
+
+      device.pushErrorScope('validation');
+
+      const renderModule = device.createShaderModule({ code: renderShadersWHLSL, isWHLSL: true });
+
+      const renderPipeline = device.createRenderPipeline({
+        layout: device.createPipelineLayout({ bindGroupLayouts: [] }),
+
+        vertexStage: {
+          module: renderModule,
+          entryPoint: "vertex_main"
+        },
+        fragmentStage: {
+          module: renderModule,
+          entryPoint: "fragment_main"
+        },
+
+        primitiveTopology: "triangle-list",
+
+        depthStencilState: {
+          depthWriteEnabled: true,
+          depthCompare: "less",
+          format: "depth32float-stencil8",
+          stencilFront: {},
+          stencilBack: {},
+        },
+
+        vertexInput: {
+          indexFormat: "uint32",
+          vertexBuffers: [{
+            // instanced particles buffer
+            stride: 4 * 4,
+            stepMode: "instance",
+            attributeSet: [{
+              // instance position
+              shaderLocation: 0,
+              offset: 0,
+              format: "float2"
+            }, {
+              // instance velocity
+              shaderLocation: 1,
+              offset: 2 * 4,
+              format: "float2"
+            }],
+          }, {
+            // vertex buffer
+            stride: 2 * 4,
+            stepMode: "vertex",
+            attributeSet: [{
+              // vertex positions
+              shaderLocation: 2,
+              offset: 0,
+              format: "float2"
+            }],
+          }],
+        },
+
+        rasterizationState: {
+          frontFace: 'ccw',
+          cullMode: 'none',
+        },
+
+        colorStates: [{
+          format: "bgra8unorm",
+          alphaBlend: {},
+          colorBlend: {},
+        }],
+      });
+
+      device.popErrorScope().then(error => {
+        if (error)
+          console.error("Render shaders: " + error.message);
+      });
+
+      device.pushErrorScope('validation');
+
+      const computePipeline = device.createComputePipeline({
+        layout: computePipelineLayout,
+        computeStage: {
+          module: device.createShaderModule({
+            code: computeShaderWHLSL, isWHLSL: true
+          }),
+          entryPoint: "compute_main",
+        }
+      });
+
+      device.popErrorScope().then(error => {
+        if (error)
+          console.error("Compute shader: " + error.message);
+      });
+
+      const depthTexture = device.createTexture({
+        size: { width: canvas.width, height: canvas.height, depth: 1 },
+        arrayLayerCount: 1,
+        mipLevelCount: 1,
+        sampleCount: 1,
+        dimension: "2d",
+        format: "depth32float-stencil8",
+        usage: GPUTextureUsage.OUTPUT_ATTACHMENT
+      });
+
+      const renderPassDescriptor = {
+        colorAttachments: [{
+          loadOp: "clear",
+          clearColor: { r: 0.0, g: 0.0, b: 0.0, a: 1.0 },
+          storeOp: "store",
+        }],
+        depthStencilAttachment: {
+          attachment: depthTexture.createDefaultView(),
+          depthLoadOp: "clear",
+          depthStoreOp: "store",
+          clearDepth: 1.0,
+          stencilLoadValue: 0,
+          stencilStoreOp: "store",
+        }
+      };
+
+      const vertexBufferData = new Float32Array([-0.01, -0.02, 0.01, -0.02, 0.00, 0.02]);
+      const [verticesBuffer, verticesArrayBuffer] = device.createBufferMapped({
+        size: vertexBufferData.byteLength,
+        usage: GPUBufferUsage.VERTEX,
+      });
+      new Float32Array(verticesArrayBuffer).set(vertexBufferData);
+      verticesBuffer.unmap();
+
+      const simParamData = new Float32Array([0.04, 0.1, 0.025, 0.025, 0.02, 0.05, 0.005]);
+      const [simParamBuffer, simParamArrayBuffer] = device.createBufferMapped({
+        size: simParamData.byteLength,
+        usage: GPUBufferUsage.UNIFORM,
+      });
+      new Float32Array(simParamArrayBuffer).set(simParamData);
+      simParamBuffer.unmap();
+
+      const initialParticleData = new Float32Array(numParticles * 4);
+      for (let i = 0; i < numParticles; ++i) {
+        initialParticleData[4 * i + 0] = 2 * (Math.random() - 0.5);
+        initialParticleData[4 * i + 1] = 2 * (Math.random() - 0.5);
+        initialParticleData[4 * i + 2] = 2 * (Math.random() - 0.5) * 0.1;
+        initialParticleData[4 * i + 3] = 2 * (Math.random() - 0.5) * 0.1;
+      }
+
+      const particleBuffers = new Array(2);
+      const particleBindGroups = new Array(2);
+      for (let i = 0; i < 2; ++i) {
+        let particleArrayBuffer;
+        [particleBuffers[i], particleArrayBuffer] = device.createBufferMapped({
+          size: initialParticleData.byteLength,
+          usage: GPUBufferUsage.VERTEX | GPUBufferUsage.STORAGE
+        });
+        new Float32Array(particleArrayBuffer).set(initialParticleData);
+        particleBuffers[i].unmap();
+      }
+      for (let i = 0; i < 2; ++i) {
+        particleBindGroups[i] = device.createBindGroup({
+          layout: computeBindGroupLayout,
+          bindings: [{
+            binding: 0,
+            resource: {
+              buffer: simParamBuffer,
+              offset: 0,
+              size: simParamData.byteLength
+            },
+          }, {
+            binding: 1,
+            resource: {
+              buffer: particleBuffers[i],
+              offset: 0,
+              size: initialParticleData.byteLength,
+            },
+          }, {
+            binding: 2,
+            resource: {
+              buffer: particleBuffers[(i + 1) % 2],
+              offset: 0,
+              size: initialParticleData.byteLength,
+            },
+          }],
+        });
+      }
+
+      let t = 0;
+      function frame() {
+        renderPassDescriptor.colorAttachments[0].attachment = swapChain.getCurrentTexture().createDefaultView();
+
+        const commandEncoder = device.createCommandEncoder({});
+        {
+          const passEncoder = commandEncoder.beginComputePass();
+          passEncoder.setPipeline(computePipeline);
+          passEncoder.setBindGroup(0, particleBindGroups[t % 2]);
+          passEncoder.dispatch(numParticles, 1, 1);
+          passEncoder.endPass();
+        }
+        {
+          const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor);
+          passEncoder.setPipeline(renderPipeline);
+          passEncoder.setVertexBuffers(0, [particleBuffers[(t + 1) % 2], verticesBuffer], [0, 0]);
+          passEncoder.draw(3, numParticles, 0, 0);
+          passEncoder.endPass();
+        }
+        device.getQueue().submit([commandEncoder.finish()]);
+
+        ++t;
+        requestAnimationFrame(frame);
+      }
+      requestAnimationFrame(frame);
+    }
+
+    init();
+
+  </script>
+</body>
+
+</html>

Modified: trunk/Websites/webkit.org/demos/webgpu/index.html (249445 => 249446)


--- trunk/Websites/webkit.org/demos/webgpu/index.html	2019-09-03 23:37:12 UTC (rev 249445)
+++ trunk/Websites/webkit.org/demos/webgpu/index.html	2019-09-04 00:20:57 UTC (rev 249446)
@@ -209,6 +209,12 @@
             Compute Shader Blur
             </a>
         </div>
+        <div class="example">
+            <a href=""
+            <img src=""
+            Compute Shader Boids
+            </a>
+        </div>
     </section>
 </div>
 </body>

Added: trunk/Websites/webkit.org/demos/webgpu/resources/compute-boids.png


(Binary files differ)
Index: trunk/Websites/webkit.org/demos/webgpu/resources/compute-boids.png =================================================================== --- trunk/Websites/webkit.org/demos/webgpu/resources/compute-boids.png 2019-09-03 23:37:12 UTC (rev 249445) +++ trunk/Websites/webkit.org/demos/webgpu/resources/compute-boids.png 2019-09-04 00:20:57 UTC (rev 249446) Property changes on: trunk/Websites/webkit.org/demos/webgpu/resources/compute-boids.png ___________________________________________________________________

Added: svn:mime-type

+image/png \ No newline at end of property
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to