Changeset 248309 in webkit
- Timestamp:
- Aug 6, 2019, 1:18:43 PM (7 years ago)
- Location:
- trunk/Websites/webkit.org
- Files:
-
- 4 added
- 7 edited
- 1 copied
-
ChangeLog (modified) (1 diff)
-
demos/webgpu/compute-blur.html (added)
-
demos/webgpu/css/style.css (modified) (2 diffs)
-
demos/webgpu/hello-cube.html (modified) (7 diffs)
-
demos/webgpu/hello-triangle.html (modified) (1 diff)
-
demos/webgpu/index.html (modified) (3 diffs)
-
demos/webgpu/resources/compute-blur.png (added)
-
demos/webgpu/resources/hello-cube.png (modified) ( previous)
-
demos/webgpu/resources/textured-cube.png (added)
-
demos/webgpu/scripts/compute-blur.js (added)
-
demos/webgpu/scripts/hello-triangle.js (modified) (7 diffs)
-
demos/webgpu/textured-cube.html (copied) (copied from trunk/Websites/webkit.org/demos/webgpu/hello-cube.html ) (15 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/Websites/webkit.org/ChangeLog
r247122 r248309 1 2019-08-06 Justin Fan <justin_fan@apple.com> 2 3 [WebGPU] Fix up demos on and add compute demo to webkit.org/demos 4 https://bugs.webkit.org/show_bug.cgi?id=200454 5 6 Reviewed by Jon Lee. 7 8 Add the compute-blur demo. 9 Ensure that WebGPU demos will work on upcoming STP release. 10 11 * demos/webgpu/compute-blur.html: Added. 12 * demos/webgpu/css/style.css: Sync with internal demo repository stylesheet. 13 (body): 14 (canvas): 15 (body.error img): 16 (body.error input): 17 (#error p): 18 * demos/webgpu/hello-cube.html: 19 * demos/webgpu/hello-triangle.html: 20 * demos/webgpu/index.html: 21 * demos/webgpu/resources/compute-blur.png: Added. 22 * demos/webgpu/resources/hello-cube.png: 23 * demos/webgpu/resources/textured-cube.png: Added. 24 * demos/webgpu/scripts/compute-blur.js: Added. 25 (async.init): 26 (async.loadImage): 27 (setUpCompute): 28 (async.computeBlur): 29 (async.setUniforms): 30 (createShaderCode): 31 * demos/webgpu/scripts/hello-triangle.js: 32 (async.helloTriangle): 33 * demos/webgpu/textured-cube.html: Renmaed from Websites/webkit.org/demos/webgpu/hello-cube.html. 34 1 35 2019-07-03 Jon Davis <jond@apple.com> 2 36 -
trunk/Websites/webkit.org/demos/webgpu/css/style.css
r244992 r248309 1 /* This demo is based on webgl-compute-bitonicSort, found at https://github.com/9ballsyndrome/WebGL_Compute_shader. */2 3 1 body { 4 background-color: rgb(35%, 65%, 85%);5 2 margin: 0; 6 3 padding: 0; 7 height: 100vh;8 display: flex;9 align-items: center;10 justify-content: center;11 4 } 12 5 13 6 canvas { 14 7 display: block; 15 width: 100vw;16 height: 100vh;17 8 } 18 9 19 10 body.error canvas { 11 display: none; 12 } 13 14 body.error img { 15 display: none; 16 } 17 18 body.error input { 20 19 display: none; 21 20 } … … 76 75 font-size: 30px; 77 76 } 77 -
trunk/Websites/webkit.org/demos/webgpu/hello-cube.html
r244992 r248309 3 3 <head> 4 4 <meta name="viewport" content="width=1000"> 5 <title>WebGPU Cube demo</title>5 <title>WebGPU Cube</title> 6 6 <script src="scripts/gl-matrix-min.js"></script> 7 7 <link rel="stylesheet" href="css/style.css"/> 8 <style> 9 body { 10 font-family: system-ui; 11 color: #f7f7ff; 12 background-color: rgb(38, 38, 127); 13 text-align: center; 14 } 15 canvas { 16 margin: 0 auto; 17 } 18 </style> 8 19 </head> 9 20 <body> 10 <canvas></canvas> 21 <div id="contents"> 22 <h1>Simple Cube</h1> 23 <p> 24 This demo uses a rotating set of GPUBuffers to upload rotation matrix data every frame. 25 </p> 26 <canvas width="1200" height="1200"></canvas> 27 </div> 28 <div id="error"> 29 <h2>WebGPU not available</h2> 30 <p> 31 Make sure you are on a system with WebGPU enabled. In 32 Safari, first make sure the Developer Menu is visible (Preferences → 33 Advanced), then Develop → Experimental Features → WebGPU. 34 </p> 35 </div> 11 36 <script> 37 if (!navigator.gpu) 38 document.body.className = 'error'; 39 12 40 const positionAttributeNum = 0; 13 const texCoordsAttributeNum = 1;41 const colorAttributeNum = 1; 14 42 15 43 const transformBindingNum = 0; 16 const textureBindingNum = 1; 17 const samplerBindingNum = 2; 18 19 const vertexBufferIndex = 0; 44 20 45 const bindGroupIndex = 0; 21 46 22 47 const shader = ` 23 #include <metal_stdlib> 24 25 using namespace metal; 26 27 struct Vertex 48 struct FragmentData { 49 float4 position : SV_Position; 50 float4 color : attribute(${colorAttributeNum}); 51 } 52 53 vertex FragmentData vertex_main( 54 float4 position : attribute(${positionAttributeNum}), 55 float4 color : attribute(${colorAttributeNum}), 56 constant float4x4[] modelViewProjectionMatrix : register(b${transformBindingNum})) 28 57 { 29 float4 position [[attribute(${positionAttributeNum})]]; 30 float2 texCoords [[attribute(${texCoordsAttributeNum})]]; 31 }; 32 33 struct FragmentData 58 FragmentData out; 59 out.position = mul(modelViewProjectionMatrix[0], position); 60 out.color = color; 61 62 return out; 63 } 64 65 fragment float4 fragment_main(float4 color : attribute(${colorAttributeNum})) : SV_Target 0 34 66 { 35 float4 position [[position]];36 float2 texCoords;37 };38 39 struct Uniform40 {41 device float4x4* modelViewProjectionMatrix [[id(${transformBindingNum})]];42 };43 44 struct SampledTexture45 {46 texture2d<float> faceTexture [[id(${textureBindingNum})]];47 sampler faceSampler [[id(${samplerBindingNum})]];48 };49 50 vertex FragmentData vertex_main(Vertex vertexIn [[stage_in]],51 const device Uniform& uniforms [[buffer(${bindGroupIndex})]])52 {53 FragmentData output;54 output.position = uniforms.modelViewProjectionMatrix[0] * vertexIn.position;55 output.texCoords = vertexIn.texCoords;56 57 return output;58 }59 60 fragment float4 fragment_main(FragmentData data [[stage_in]],61 const device SampledTexture& args [[buffer(${bindGroupIndex})]])62 {63 float4 color = args.faceTexture.sample(args.faceSampler, data.texCoords);64 if (color.a < 1)65 discard_fragment();66 67 67 return color; 68 68 } 69 ` 70 71 let device, swapChain, verticesBuffer, bindGroupLayout, pipeline, renderPassDescriptor , queue, textureViewBinding, samplerBinding;69 `; 70 71 let device, swapChain, verticesBuffer, bindGroupLayout, pipeline, renderPassDescriptor; 72 72 let projectionMatrix = mat4.create(); 73 73 74 const texCoordsOffset = 4 * 4; 75 const vertexSize = 4 * 6; 76 function createVerticesArray() { 77 return new Float32Array([ 78 // float4 position, float2 texCoords 79 1, -1, 1, 1, 1, 0, 80 -1, -1, 1, 1, 0, 0, 81 -1, -1, -1, 1, 0, 1, 82 1, -1, -1, 1, 1, 1, 83 1, -1, 1, 1, 1, 0, 84 -1, -1, -1, 1, 0, 1, 85 86 1, 1, 1, 1, 0, 0, 87 1, -1, 1, 1, 0, 1, 88 1, -1, -1, 1, 1, 1, 89 1, 1, -1, 1, 1, 0, 90 1, 1, 1, 1, 0, 0, 91 1, -1, -1, 1, 1, 1, 92 93 -1, 1, 1, 1, 0, 1, 94 1, 1, 1, 1, 1, 1, 95 1, 1, -1, 1, 1, 0, 96 -1, 1, -1, 1, 0, 0, 97 -1, 1, 1, 1, 0, 1, 98 1, 1, -1, 1, 1, 0, 99 100 -1, -1, 1, 1, 1, 1, 101 -1, 1, 1, 1, 1, 0, 102 -1, 1, -1, 1, 0, 0, 103 -1, -1, -1, 1, 0, 1, 104 -1, -1, 1, 1, 1, 1, 105 -1, 1, -1, 1, 0, 0, 106 107 1, 1, 1, 1, 1, 0, 108 -1, 1, 1, 1, 0, 0, 109 -1, -1, 1, 1, 0, 1, 110 -1, -1, 1, 1, 0, 1, 111 1, -1, 1, 1, 1, 1, 112 1, 1, 1, 1, 1, 0, 113 114 1, -1, -1, 1, 0, 1, 115 -1, -1, -1, 1, 1, 1, 116 -1, 1, -1, 1, 1, 0, 117 1, 1, -1, 1, 0, 0, 118 1, -1, -1, 1, 0, 1, 119 -1, 1, -1, 1, 1, 0, 120 ]); 121 } 74 const colorOffset = 4 * 4; 75 const vertexSize = 4 * 8; 76 const verticesArray = new Float32Array([ 77 // float4 position, float4 color 78 1, -1, 1, 1, 1, 0, 1, 1, 79 -1, -1, 1, 1, 0, 0, 1, 1, 80 -1, -1, -1, 1, 0, 0, 0, 1, 81 1, -1, -1, 1, 1, 0, 0, 1, 82 1, -1, 1, 1, 1, 0, 1, 1, 83 -1, -1, -1, 1, 0, 0, 0, 1, 84 85 1, 1, 1, 1, 1, 1, 1, 1, 86 1, -1, 1, 1, 1, 0, 1, 1, 87 1, -1, -1, 1, 1, 0, 0, 1, 88 1, 1, -1, 1, 1, 1, 0, 1, 89 1, 1, 1, 1, 1, 1, 1, 1, 90 1, -1, -1, 1, 1, 0, 0, 1, 91 92 -1, 1, 1, 1, 0, 1, 1, 1, 93 1, 1, 1, 1, 1, 1, 1, 1, 94 1, 1, -1, 1, 1, 1, 0, 1, 95 -1, 1, -1, 1, 0, 1, 0, 1, 96 -1, 1, 1, 1, 0, 1, 1, 1, 97 1, 1, -1, 1, 1, 1, 0, 1, 98 99 -1, -1, 1, 1, 0, 0, 1, 1, 100 -1, 1, 1, 1, 0, 1, 1, 1, 101 -1, 1, -1, 1, 0, 1, 0, 1, 102 -1, -1, -1, 1, 0, 0, 0, 1, 103 -1, -1, 1, 1, 0, 0, 1, 1, 104 -1, 1, -1, 1, 0, 1, 0, 1, 105 106 1, 1, 1, 1, 1, 1, 1, 1, 107 -1, 1, 1, 1, 0, 1, 1, 1, 108 -1, -1, 1, 1, 0, 0, 1, 1, 109 -1, -1, 1, 1, 0, 0, 1, 1, 110 1, -1, 1, 1, 1, 0, 1, 1, 111 1, 1, 1, 1, 1, 1, 1, 1, 112 113 1, -1, -1, 1, 1, 0, 0, 1, 114 -1, -1, -1, 1, 0, 0, 0, 1, 115 -1, 1, -1, 1, 0, 1, 0, 1, 116 1, 1, -1, 1, 1, 1, 0, 1, 117 1, -1, -1, 1, 1, 0, 0, 1, 118 -1, 1, -1, 1, 0, 1, 0, 1, 119 ]); 122 120 123 121 async function init() { … … 136 134 137 135 const swapChainDescriptor = { 138 device: device, 136 device: device, 139 137 format: "bgra8unorm" 140 138 }; 141 139 swapChain = context.configureSwapChain(swapChainDescriptor); 142 140 143 // WebKit WebGPU accepts only MSL for now. 144 const shaderModuleDescriptor = { code: shader }; 141 const shaderModuleDescriptor = { code: shader, isWHLSL: true }; 145 142 const shaderModule = device.createShaderModule(shaderModuleDescriptor); 146 143 147 const verticesArray = createVerticesArray();148 144 const verticesBufferDescriptor = { 149 145 size: verticesArray.byteLength, 150 146 usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST 151 147 }; 152 verticesBuffer = device.createBuffer(verticesBufferDescriptor); 153 verticesBuffer.setSubData(0, verticesArray.buffer); 154 155 // Input state. Model will change soon to adopt one of https://github.com/kainino0x/gpuweb/pull/2/'s ideas. 148 let verticesArrayBuffer; 149 [verticesBuffer, verticesArrayBuffer] = device.createBufferMapped(verticesBufferDescriptor); 150 151 const verticesWriteArray = new Float32Array(verticesArrayBuffer); 152 verticesWriteArray.set(verticesArray); 153 verticesBuffer.unmap(); 154 155 // Vertex Input 156 156 const positionAttributeDescriptor = { 157 shaderLocation: positionAttributeNum, // [[attribute(0)]]. 158 inputSlot: vertexBufferIndex, // Used as vertex buffer index in Metal. 157 shaderLocation: positionAttributeNum, // [[attribute(0)]] 159 158 offset: 0, 160 159 format: "float4" 161 160 }; 162 const texCoordsAttributeDescriptor = { 163 shaderLocation: texCoordsAttributeNum, 164 inputSlot: vertexBufferIndex, 165 offset: texCoordsOffset, 166 format: "float2" 161 const colorAttributeDescriptor = { 162 shaderLocation: colorAttributeNum, 163 offset: colorOffset, 164 format: "float4" 167 165 } 168 166 const vertexBufferDescriptor = { 169 inputSlot: vertexBufferIndex,167 attributeSet: [positionAttributeDescriptor, colorAttributeDescriptor], 170 168 stride: vertexSize, 171 169 stepMode: "vertex" 172 170 }; 173 const inputStateDescriptor = { 174 indexFormat: "uint32", 175 attributes: [positionAttributeDescriptor, texCoordsAttributeDescriptor], 176 inputs: [vertexBufferDescriptor] 177 }; 178 179 // Texture 180 181 // Load texture image 182 const image = new Image(); 183 const imageLoadPromise = new Promise(resolve => { 184 image.onload = () => resolve(); 185 image.src = "resources/safari-alpha.png" 186 }); 187 await Promise.resolve(imageLoadPromise); 188 189 const textureSize = { 190 width: image.width, 191 height: image.height, 192 depth: 1 193 }; 194 195 const textureDescriptor = { 196 size: textureSize, 197 arrayLayerCount: 1, 198 mipLevelCount: 1, 199 sampleCount: 1, 200 dimension: "2d", 201 format: "rgba8unorm", 202 usage: GPUTextureUsage.TRANSFER_DST | GPUTextureUsage.SAMPLED 203 }; 204 const texture = device.createTexture(textureDescriptor); 205 206 // Texture data 207 const canvas2d = document.createElement('canvas'); 208 canvas2d.width = image.width; 209 canvas2d.height = image.height; 210 const context2d = canvas2d.getContext('2d'); 211 context2d.drawImage(image, 0, 0); 212 213 const imageData = context2d.getImageData(0, 0, image.width, image.height); 214 215 const textureDataBufferDescriptor = { 216 size: imageData.data.length, 217 usage: GPUBufferUsage.TRANSFER_SRC | GPUBufferUsage.TRANSFER_DST 218 }; 219 const textureDataBuffer = device.createBuffer(textureDataBufferDescriptor); 220 textureDataBuffer.setSubData(0, imageData.data.buffer); 221 222 const dataCopyView = { 223 buffer: textureDataBuffer, 224 offset: 0, 225 rowPitch: image.width * 4, 226 imageHeight: 0 227 }; 228 const textureCopyView = { 229 texture: texture, 230 mipLevel: 0, 231 arrayLayer: 0, 232 origin: { x: 0, y: 0, z: 0 } 233 }; 234 235 const blitCommandEncoder = device.createCommandEncoder(); 236 blitCommandEncoder.copyBufferToTexture(dataCopyView, textureCopyView, textureSize); 237 238 queue = device.getQueue(); 239 240 queue.submit([blitCommandEncoder.finish()]); 171 const vertexInputDescriptor = { vertexBuffers: [vertexBufferDescriptor] }; 241 172 242 173 // Bind group binding layout … … 247 178 }; 248 179 249 const textureBindGroupLayoutBinding = { 250 binding: textureBindingNum, 251 visibility: GPUShaderStageBit.FRAGMENT, 252 type: "sampled-texture" 253 }; 254 textureViewBinding = { 255 binding: textureBindingNum, 256 resource: texture.createDefaultView() 257 }; 258 259 const samplerBindGroupLayoutBinding = { 260 binding: samplerBindingNum, 261 visibility: GPUShaderStageBit.FRAGMENT, 262 type: "sampler" 263 }; 264 samplerBinding = { 265 binding: samplerBindingNum, 266 resource: device.createSampler({}) 267 }; 268 269 const bindGroupLayoutDescriptor = { 270 bindings: [transformBufferBindGroupLayoutBinding, textureBindGroupLayoutBinding, samplerBindGroupLayoutBinding] 271 }; 180 const bindGroupLayoutDescriptor = { bindings: [transformBufferBindGroupLayoutBinding] }; 272 181 bindGroupLayout = device.createBindGroupLayout(bindGroupLayoutDescriptor); 273 182 … … 311 220 colorStates: [colorState], 312 221 depthStencilState: depthStateDescriptor, 313 inputState: inputStateDescriptor222 vertexInput: vertexInputDescriptor 314 223 }; 315 224 pipeline = device.createRenderPipeline(pipelineDescriptor); … … 319 228 loadOp: "clear", 320 229 storeOp: "store", 321 clearColor: { r: 0. 5, g: 1.0, b: 1.0, a: 1.0 } // GPUColor230 clearColor: { r: 0.15, g: 0.15, b: 0.5, a: 1.0 } // GPUColor 322 231 }; 323 232 … … 361 270 /* Transform Buffers and Bindings */ 362 271 const transformSize = 4 * 16; 272 273 const transformBufferDescriptor = { 274 size: transformSize, 275 usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE 276 }; 277 278 let mappedGroups = []; 279 280 function render() { 281 if (mappedGroups.length === 0) { 282 const [buffer, arrayBuffer] = device.createBufferMapped(transformBufferDescriptor); 283 const group = device.createBindGroup(createBindGroupDescriptor(buffer)); 284 let mappedGroup = { buffer: buffer, arrayBuffer: arrayBuffer, bindGroup: group }; 285 drawCommands(mappedGroup); 286 } else 287 drawCommands(mappedGroups.shift()); 288 } 289 290 function createBindGroupDescriptor(transformBuffer) { 291 const transformBufferBinding = { 292 buffer: transformBuffer, 293 offset: 0, 294 size: transformSize 295 }; 296 const transformBufferBindGroupBinding = { 297 binding: transformBindingNum, 298 resource: transformBufferBinding 299 }; 300 return { 301 layout: bindGroupLayout, 302 bindings: [transformBufferBindGroupBinding] 303 }; 304 } 305 306 function drawCommands(mappedGroup) { 307 updateTransformArray(new Float32Array(mappedGroup.arrayBuffer)); 308 mappedGroup.buffer.unmap(); 309 310 const commandEncoder = device.createCommandEncoder(); 311 renderPassDescriptor.colorAttachments[0].attachment = swapChain.getCurrentTexture().createDefaultView(); 312 const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); 313 314 // Encode drawing commands 315 316 passEncoder.setPipeline(pipeline); 317 // Vertex attributes 318 passEncoder.setVertexBuffers(0, [verticesBuffer], [0]); 319 // Bind groups 320 passEncoder.setBindGroup(bindGroupIndex, mappedGroup.bindGroup); 321 // 36 vertices, 1 instance, 0th vertex, 0th instance. 322 passEncoder.draw(36, 1, 0, 0); 323 passEncoder.endPass(); 324 325 device.getQueue().submit([commandEncoder.finish()]); 326 327 // Ready the current buffer for update after GPU is done with it. 328 mappedGroup.buffer.mapWriteAsync().then((arrayBuffer) => { 329 mappedGroup.arrayBuffer = arrayBuffer; 330 mappedGroups.push(mappedGroup); 331 }); 332 333 requestAnimationFrame(render); 334 } 335 363 336 function updateTransformArray(array) { 364 337 let viewMatrix = mat4.create(); … … 368 341 let modelViewProjectionMatrix = mat4.create(); 369 342 mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix); 370 for (let i = 0; i < 16; i++) { 371 array[i] = modelViewProjectionMatrix[i]; 372 } 373 } 374 375 const transformBufferDescriptor = { 376 size: transformSize, 377 usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE 378 }; 379 380 function createBindGroupDescriptor(transformBuffer, textureViewBinding, samplerBinding) { 381 const transformBufferBinding = { 382 buffer: transformBuffer, 383 offset: 0, 384 size: transformSize 385 }; 386 const transformBufferBindGroupBinding = { 387 binding: transformBindingNum, 388 resource: transformBufferBinding 389 }; 390 return { 391 layout: bindGroupLayout, 392 bindings: [transformBufferBindGroupBinding, textureViewBinding, samplerBinding] 393 }; 394 } 395 396 let mappedGroups = []; 397 398 function render() { 399 if (mappedGroups.length == 0) { 400 const buffer = device.createBuffer(transformBufferDescriptor); 401 buffer.mapWriteAsync().then(arrayBuffer => { 402 const group = device.createBindGroup(createBindGroupDescriptor(buffer, textureViewBinding, samplerBinding)); 403 404 let mappedGroup = { buffer: buffer, arrayBuffer: arrayBuffer, bindGroup: group }; 405 drawCommands(mappedGroup); 406 }); 407 } else 408 drawCommands(mappedGroups.shift()); 409 } 410 411 function drawCommands(mappedGroup) { 412 updateTransformArray(new Float32Array(mappedGroup.arrayBuffer)); 413 mappedGroup.buffer.unmap(); 414 415 const commandEncoder = device.createCommandEncoder(); 416 renderPassDescriptor.colorAttachments[0].attachment = swapChain.getCurrentTexture().createDefaultView(); 417 const passEncoder = commandEncoder.beginRenderPass(renderPassDescriptor); 418 // Encode drawing commands. 419 passEncoder.setPipeline(pipeline); 420 // Vertex attributes 421 passEncoder.setVertexBuffers(vertexBufferIndex, [verticesBuffer], [0]); 422 // Bind groups 423 passEncoder.setBindGroup(bindGroupIndex, mappedGroup.bindGroup); 424 passEncoder.draw(36, 1, 0, 0); 425 passEncoder.endPass(); 426 427 queue.submit([commandEncoder.finish()]); 428 429 // Ready the current buffer for update after GPU is done with it. 430 mappedGroup.buffer.mapWriteAsync().then((arrayBuffer) => { 431 mappedGroup.arrayBuffer = arrayBuffer; 432 mappedGroups.push(mappedGroup); 433 }); 434 435 requestAnimationFrame(render); 436 } 437 438 init(); 343 mat4.copy(array, modelViewProjectionMatrix); 344 } 345 346 window.addEventListener("load", init); 439 347 </script> 440 348 </body> -
trunk/Websites/webkit.org/demos/webgpu/hello-triangle.html
r244992 r248309 4 4 <meta name="viewport" content="width=600"> 5 5 <meta http-equiv="Content-type" content="text/html; charset=utf-8"> 6 <title>Web GPU Hello Triangle demo</title>6 <title>WebGPU Hello Triangle</title> 7 7 <link rel="stylesheet" href="css/style.css"> 8 <link rel="stylesheet" href="https://webkit.org/wp-content/themes/webkit/style.css"> 8 <style> 9 body { 10 font-family: system-ui; 11 color: #f7f7ff; 12 background-color: rgb(38, 38, 127); 13 text-align: center; 14 } 15 canvas { 16 margin: 0 auto; 17 } 18 </style> 9 19 </head> 10 20 <body> 11 <canvas></canvas> 21 <div id="contents"> 22 <h1>Simple Triangle</h1> 23 <canvas></canvas> 24 </div> 12 25 <div id="error"> 13 <h2>Web GPU not available</h2>26 <h2>WebGPU not available</h2> 14 27 <p> 15 Make sure you are on a system with Web GPU enabled. In28 Make sure you are on a system with WebGPU enabled. In 16 29 Safari, first make sure the Developer Menu is visible (Preferences → 17 Advanced), then Develop → Experimental Features → Enable WebGPU.30 Advanced), then Develop → Experimental Features → WebGPU. 18 31 </p> 19 32 </div> -
trunk/Websites/webkit.org/demos/webgpu/index.html
r244992 r248309 4 4 <meta name="viewport" content="width=device-width"> 5 5 <meta http-equiv="Content-type" content="text/html; charset=utf-8"> 6 <title>Web Metaldemos</title>6 <title>WebGPU demos</title> 7 7 <link rel="stylesheet" href="https://webkit.org/wp-content/themes/webkit/style.css"> 8 8 <link rel="stylesheet" href="https://www.apple.com/wss/fonts?family=Myriad+Set+Pro&v=1"> … … 163 163 <header> 164 164 <img src="resources/circle.svg"> 165 <h1>Web GPU<br>demos</h1>165 <h1>WebGPU<br>demos</h1> 166 166 </header> 167 167 <section class="demos"> 168 168 <p class="intro"> 169 169 Here are a collection of simple <a 170 href="https://en.wikipedia.org/wiki/WebGPU">Web GPU</a>170 href="https://en.wikipedia.org/wiki/WebGPU">WebGPU</a> 171 171 examples. They should work in the latest <a 172 href="https://webkit.org/build-archives/">WebKit</a> builds, and 173 soon in a <a 174 href="https://developer.apple.com/safari/technology-preview/">Safari 175 Technology Preview</a> release. The full specification is a work-in-progress on <a 172 href="https://webkit.org/build-archives/">WebKit</a> builds and 173 <a href="https://developer.apple.com/safari/technology-preview/">Safari 174 Technology Preview</a> release. The full <a href="https://gpuweb.github.io/gpuweb/">specification</a> is a work-in-progress on <a 176 175 href="https://github.com/gpuweb/gpuweb 177 176 ">GitHub</a>, and the implementation may differ from the current API. 178 177 </p> 179 178 <p class="howto"> 180 Make sure you are on a system with Web GPU enabled. In Safari, first179 Make sure you are on a system with WebGPU enabled. In Safari, first 181 180 make sure the Developer Menu is visible (Preferences → Advanced), 182 then ensure Develop → Experimental Features → Web GPU is checked.181 then ensure Develop → Experimental Features → WebGPU is checked. 183 182 </p> 184 183 <p class="warning"> 185 Web GPU is an experimental technology, and you should not browse the entire184 WebGPU is an experimental technology, and you should not browse the entire 186 185 Web with it enabled for now. It doesn't do much validation of content, and 187 186 thus may cause some issues with your computer. … … 195 194 <div class="example"> 196 195 <a href="hello-cube.html"> 197 <img src="resources/hello-cube.png"><br> 196 <img src = "resources/hello-cube.png"><br> 197 Hello World Cube 198 </a> 199 </div> 200 <div class="example"> 201 <a href="textured-cube.html"> 202 <img src="resources/textured-cube.png"><br> 198 203 Textured Spinning Cube 204 </a> 205 </div> 206 <div class="example"> 207 <a href="compute-blur.html"> 208 <img src="resources/compute-blur.png"><br> 209 Compute Shader Blur 199 210 </a> 200 211 </div> -
trunk/Websites/webkit.org/demos/webgpu/scripts/hello-triangle.js
r244992 r248309 13 13 const positionLocation = 0; 14 14 const colorLocation = 1; 15 16 const shaderSource = ` 17 #include <metal_stdlib> 18 19 using namespace metal; 20 21 struct Vertex { 22 float4 position [[attribute(${positionLocation})]]; 23 float4 color [[attribute(${colorLocation})]]; 24 }; 25 15 16 const whlslSource = ` 26 17 struct FragmentData { 27 float4 position [[position]];28 float4 color ;29 } ;30 31 vertex FragmentData vertexMain( const Vertex in [[stage_in]])18 float4 position : SV_Position; 19 float4 color : attribute(${colorLocation}); 20 } 21 22 vertex FragmentData vertexMain(float4 position : attribute(${positionLocation}), float4 color : attribute(${colorLocation})) 32 23 { 33 return FragmentData { in.position, in.color }; 24 FragmentData out; 25 26 out.position = position; 27 out.color = color; 28 29 return out; 34 30 } 35 36 fragment float4 fragmentMain( const FragmentData in [[stage_in]])31 32 fragment float4 fragmentMain(float4 color : attribute(${colorLocation})) : SV_Target 0 37 33 { 38 return in.color;34 return color; 39 35 } 40 36 `; 41 const shaderModule = device.createShaderModule({ code: shaderSource });37 const shaderModule = device.createShaderModule({ code: whlslSource, isWHLSL: true }); 42 38 43 39 /* GPUPipelineStageDescriptors */ … … 53 49 54 50 /* GPUBufferDescriptor */ 55 const vertex BufferDescriptor = {51 const vertexDataBufferDescriptor = { 56 52 size: vertexDataSize, 57 53 usage: GPUBufferUsage.MAP_WRITE | GPUBufferUsage.VERTEX 58 54 }; 59 55 /* GPUBuffer */ 60 const vertexBuffer = device.createBuffer(vertex BufferDescriptor);56 const vertexBuffer = device.createBuffer(vertexDataBufferDescriptor); 61 57 62 58 /*** Write Data To GPU ***/ … … 79 75 const positionAttribute = { 80 76 shaderLocation: positionLocation, 81 inputSlot: vertexBufferSlot,82 77 offset: 0, 83 78 format: "float4" … … 85 80 const colorAttribute = { 86 81 shaderLocation: colorLocation, 87 inputSlot: vertexBufferSlot,88 82 offset: colorOffset, 89 83 format: "float4" 90 84 }; 91 85 86 /* GPUVertexBufferDescriptor */ 87 const vertexBufferDescriptor = { 88 stride: vertexStride, 89 attributeSet: [positionAttribute, colorAttribute] 90 }; 91 92 92 /* GPUVertexInputDescriptor */ 93 93 const vertexInputDescriptor = { 94 inputSlot: vertexBufferSlot, 95 stride: vertexStride, 96 stepMode: "vertex" 97 }; 98 99 /* GPUInputStateDescriptor */ 100 const inputStateDescriptor = { 101 attributes: [positionAttribute, colorAttribute], 102 inputs: [vertexInputDescriptor] 94 vertexBuffers: [vertexBufferDescriptor] 103 95 }; 104 96 … … 123 115 primitiveTopology: "triangle-list", 124 116 colorStates: [colorStateDescriptor], 125 inputState: inputStateDescriptor117 vertexInput: vertexInputDescriptor 126 118 }; 127 119 /* GPURenderPipeline */ … … 131 123 132 124 const canvas = document.querySelector("canvas"); 133 let canvasSize = canvas.getBoundingClientRect(); 134 canvas.width = canvasSize.width; 135 canvas.height = canvasSize.height; 125 canvas.width = 600; 126 canvas.height = 600; 136 127 137 128 const gpuContext = canvas.getContext("gpu"); … … 152 143 153 144 /* GPUColor */ 154 const darkBlue = { r: 0 , g: 0, b: 0.5, a: 1 };145 const darkBlue = { r: 0.15, g: 0.15, b: 0.5, a: 1 }; 155 146 156 147 /* GPURenderPassColorATtachmentDescriptor */ -
trunk/Websites/webkit.org/demos/webgpu/textured-cube.html
r248308 r248309 3 3 <head> 4 4 <meta name="viewport" content="width=1000"> 5 <title>WebGPU Cube demo</title>5 <title>WebGPU Cube</title> 6 6 <script src="scripts/gl-matrix-min.js"></script> 7 7 <link rel="stylesheet" href="css/style.css"/> 8 <style> 9 body { 10 font-family: system-ui; 11 color: #f7f7ff; 12 background-color: rgb(13, 77, 153); 13 text-align: center; 14 } 15 canvas { 16 margin: 0 auto; 17 } 18 p { 19 margin: 0 8px; 20 } 21 </style> 8 22 </head> 9 23 <body> 10 <canvas></canvas> 24 <div id="contents"> 25 <h1>Textured Cube</h1> 26 <p> 27 This demo uploads a PNG image as texture data and uses it on the faces of a cube. 28 </p> 29 <canvas width="1200" height="1200"></canvas> 30 </div> 31 <div id="error"> 32 <h2>WebGPU not available</h2> 33 <p> 34 Make sure you are on a system with WebGPU enabled. In 35 Safari, first make sure the Developer Menu is visible (Preferences → 36 Advanced), then Develop → Experimental Features → WebGPU. 37 </p> 38 </div> 11 39 <script> 40 if (!navigator.gpu) 41 document.body.className = 'error'; 42 12 43 const positionAttributeNum = 0; 13 44 const texCoordsAttributeNum = 1; … … 17 48 const samplerBindingNum = 2; 18 49 19 const vertexBufferIndex = 0;20 50 const bindGroupIndex = 0; 21 51 22 52 const shader = ` 23 #include <metal_stdlib> 24 25 using namespace metal; 26 27 struct Vertex 53 struct FragmentData { 54 float4 position : SV_Position; 55 float2 texCoords : attribute(${texCoordsAttributeNum}); 56 } 57 58 vertex FragmentData vertex_main( 59 float4 position : attribute(${positionAttributeNum}), 60 float2 texCoords : attribute(${texCoordsAttributeNum}), 61 constant float4x4[] modelViewProjectionMatrix : register(b${transformBindingNum})) 28 62 { 29 float4 position [[attribute(${positionAttributeNum})]]; 30 float2 texCoords [[attribute(${texCoordsAttributeNum})]]; 31 }; 32 33 struct FragmentData 63 FragmentData out; 64 out.position = mul(modelViewProjectionMatrix[0], position); 65 out.texCoords = texCoords; 66 67 return out; 68 } 69 70 fragment float4 fragment_main( 71 float2 texCoords : attribute(${texCoordsAttributeNum}), 72 Texture2D<float4> faceTexture : register(t${textureBindingNum}), 73 sampler faceSampler : register(s${samplerBindingNum})) : SV_Target 0 34 74 { 35 float4 position [[position]]; 36 float2 texCoords; 37 }; 38 39 struct Uniform 40 { 41 device float4x4* modelViewProjectionMatrix [[id(${transformBindingNum})]]; 42 }; 43 44 struct SampledTexture 45 { 46 texture2d<float> faceTexture [[id(${textureBindingNum})]]; 47 sampler faceSampler [[id(${samplerBindingNum})]]; 48 }; 49 50 vertex FragmentData vertex_main(Vertex vertexIn [[stage_in]], 51 const device Uniform& uniforms [[buffer(${bindGroupIndex})]]) 52 { 53 FragmentData output; 54 output.position = uniforms.modelViewProjectionMatrix[0] * vertexIn.position; 55 output.texCoords = vertexIn.texCoords; 56 57 return output; 58 } 59 60 fragment float4 fragment_main(FragmentData data [[stage_in]], 61 const device SampledTexture& args [[buffer(${bindGroupIndex})]]) 62 { 63 float4 color = args.faceTexture.sample(args.faceSampler, data.texCoords); 64 if (color.a < 1) 65 discard_fragment(); 66 67 return color; 68 } 69 ` 75 return Sample(faceTexture, faceSampler, texCoords); 76 } 77 `; 70 78 71 79 let device, swapChain, verticesBuffer, bindGroupLayout, pipeline, renderPassDescriptor, queue, textureViewBinding, samplerBinding; … … 74 82 const texCoordsOffset = 4 * 4; 75 83 const vertexSize = 4 * 6; 76 function createVerticesArray() { 77 return new Float32Array([ 78 // float4 position, float2 texCoords 79 1, -1, 1, 1, 1, 0, 80 -1, -1, 1, 1, 0, 0, 81 -1, -1, -1, 1, 0, 1, 82 1, -1, -1, 1, 1, 1, 83 1, -1, 1, 1, 1, 0, 84 -1, -1, -1, 1, 0, 1, 85 86 1, 1, 1, 1, 0, 0, 87 1, -1, 1, 1, 0, 1, 88 1, -1, -1, 1, 1, 1, 89 1, 1, -1, 1, 1, 0, 90 1, 1, 1, 1, 0, 0, 91 1, -1, -1, 1, 1, 1, 92 93 -1, 1, 1, 1, 0, 1, 94 1, 1, 1, 1, 1, 1, 95 1, 1, -1, 1, 1, 0, 96 -1, 1, -1, 1, 0, 0, 97 -1, 1, 1, 1, 0, 1, 98 1, 1, -1, 1, 1, 0, 99 100 -1, -1, 1, 1, 1, 1, 101 -1, 1, 1, 1, 1, 0, 102 -1, 1, -1, 1, 0, 0, 103 -1, -1, -1, 1, 0, 1, 104 -1, -1, 1, 1, 1, 1, 105 -1, 1, -1, 1, 0, 0, 106 107 1, 1, 1, 1, 1, 0, 108 -1, 1, 1, 1, 0, 0, 109 -1, -1, 1, 1, 0, 1, 110 -1, -1, 1, 1, 0, 1, 111 1, -1, 1, 1, 1, 1, 112 1, 1, 1, 1, 1, 0, 113 114 1, -1, -1, 1, 0, 1, 115 -1, -1, -1, 1, 1, 1, 116 -1, 1, -1, 1, 1, 0, 117 1, 1, -1, 1, 0, 0, 118 1, -1, -1, 1, 0, 1, 119 -1, 1, -1, 1, 1, 0, 120 ]); 121 } 84 const verticesArray = new Float32Array([ 85 // float4 position, float2 texCoords 86 1, -1, -1, 1, 0, 1, 87 -1, -1, -1, 1, 1, 1, 88 -1, 1, -1, 1, 1, 0, 89 1, 1, -1, 1, 0, 0, 90 1, -1, -1, 1, 0, 1, 91 -1, 1, -1, 1, 1, 0, 92 93 1, 1, 1, 1, 0, 0, 94 1, -1, 1, 1, 0, 1, 95 1, -1, -1, 1, 1, 1, 96 1, 1, -1, 1, 1, 0, 97 1, 1, 1, 1, 0, 0, 98 1, -1, -1, 1, 1, 1, 99 100 1, -1, 1, 1, 1, 0, 101 -1, -1, 1, 1, 0, 0, 102 -1, -1, -1, 1, 0, 1, 103 1, -1, -1, 1, 1, 1, 104 1, -1, 1, 1, 1, 0, 105 -1, -1, -1, 1, 0, 1, 106 107 -1, 1, 1, 1, 0, 1, 108 1, 1, 1, 1, 1, 1, 109 1, 1, -1, 1, 1, 0, 110 -1, 1, -1, 1, 0, 0, 111 -1, 1, 1, 1, 0, 1, 112 1, 1, -1, 1, 1, 0, 113 114 -1, -1, 1, 1, 1, 1, 115 -1, 1, 1, 1, 1, 0, 116 -1, 1, -1, 1, 0, 0, 117 -1, -1, -1, 1, 0, 1, 118 -1, -1, 1, 1, 1, 1, 119 -1, 1, -1, 1, 0, 0, 120 121 1, 1, 1, 1, 1, 0, 122 -1, 1, 1, 1, 0, 0, 123 -1, -1, 1, 1, 0, 1, 124 -1, -1, 1, 1, 0, 1, 125 1, -1, 1, 1, 1, 1, 126 1, 1, 1, 1, 1, 0, 127 ]); 122 128 123 129 async function init() { … … 126 132 127 133 const canvas = document.querySelector('canvas'); 128 let canvasSize = canvas.getBoundingClientRect();129 canvas.width = canvasSize.width;130 canvas.height = canvasSize.height;131 134 132 135 const aspect = Math.abs(canvas.width / canvas.height); … … 136 139 137 140 const swapChainDescriptor = { 138 device: device, 141 device: device, 139 142 format: "bgra8unorm" 140 143 }; … … 142 145 143 146 // WebKit WebGPU accepts only MSL for now. 144 const shaderModuleDescriptor = { code: shader };147 const shaderModuleDescriptor = { code: shader, isWHLSL: true }; 145 148 const shaderModule = device.createShaderModule(shaderModuleDescriptor); 146 149 147 const verticesArray = createVerticesArray();148 150 const verticesBufferDescriptor = { 149 151 size: verticesArray.byteLength, 150 152 usage: GPUBufferUsage.VERTEX | GPUBufferUsage.TRANSFER_DST 151 153 }; 152 verticesBuffer = device.createBuffer(verticesBufferDescriptor); 153 verticesBuffer.setSubData(0, verticesArray.buffer); 154 155 // Input state. Model will change soon to adopt one of https://github.com/kainino0x/gpuweb/pull/2/'s ideas. 154 let verticesArrayBuffer; 155 [verticesBuffer, verticesArrayBuffer] = device.createBufferMapped(verticesBufferDescriptor); 156 157 const verticesWriteArray = new Float32Array(verticesArrayBuffer); 158 verticesWriteArray.set(verticesArray); 159 verticesBuffer.unmap(); 160 161 // Vertex Input 162 156 163 const positionAttributeDescriptor = { 157 164 shaderLocation: positionAttributeNum, // [[attribute(0)]]. 158 inputSlot: vertexBufferIndex, // Used as vertex buffer index in Metal.159 165 offset: 0, 160 166 format: "float4" … … 162 168 const texCoordsAttributeDescriptor = { 163 169 shaderLocation: texCoordsAttributeNum, 164 inputSlot: vertexBufferIndex,165 170 offset: texCoordsOffset, 166 171 format: "float2" 167 172 } 168 173 const vertexBufferDescriptor = { 169 inputSlot: vertexBufferIndex,174 attributeSet: [positionAttributeDescriptor, texCoordsAttributeDescriptor], 170 175 stride: vertexSize, 171 176 stepMode: "vertex" 172 177 }; 173 const inputStateDescriptor = { 174 indexFormat: "uint32", 175 attributes: [positionAttributeDescriptor, texCoordsAttributeDescriptor], 176 inputs: [vertexBufferDescriptor] 177 }; 178 const vertexInputDescriptor = { vertexBuffers: [vertexBufferDescriptor] }; 178 179 179 180 // Texture … … 215 216 const textureDataBufferDescriptor = { 216 217 size: imageData.data.length, 217 usage: GPUBufferUsage.TRANSFER_SRC | GPUBufferUsage.TRANSFER_DST 218 }; 219 const textureDataBuffer = device.createBuffer(textureDataBufferDescriptor); 220 textureDataBuffer.setSubData(0, imageData.data.buffer); 218 usage: GPUBufferUsage.TRANSFER_SRC 219 }; 220 const [textureDataBuffer, textureArrayBuffer] = device.createBufferMapped(textureDataBufferDescriptor); 221 222 const textureWriteArray = new Uint8Array(textureArrayBuffer); 223 textureWriteArray.set(imageData.data); 224 textureDataBuffer.unmap(); 221 225 222 226 const dataCopyView = { … … 311 315 colorStates: [colorState], 312 316 depthStencilState: depthStateDescriptor, 313 inputState: inputStateDescriptor317 vertexInput: vertexInputDescriptor 314 318 }; 315 319 pipeline = device.createRenderPipeline(pipelineDescriptor); … … 319 323 loadOp: "clear", 320 324 storeOp: "store", 321 clearColor: { r: 0. 5, g: 1.0, b: 1.0, a: 1.0 } // GPUColor325 clearColor: { r: 0.05, g: .3, b: .6, a: 1.0 } // GPUColor 322 326 }; 323 327 … … 361 365 /* Transform Buffers and Bindings */ 362 366 const transformSize = 4 * 16; 363 function updateTransformArray(array) {364 let viewMatrix = mat4.create();365 mat4.translate(viewMatrix, viewMatrix, vec3.fromValues(0, 0, -5));366 let now = Date.now() / 1000;367 mat4.rotate(viewMatrix, viewMatrix, 1, vec3.fromValues(Math.sin(now), Math.cos(now), 0));368 let modelViewProjectionMatrix = mat4.create();369 mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix);370 for (let i = 0; i < 16; i++) {371 array[i] = modelViewProjectionMatrix[i];372 }373 }374 367 375 368 const transformBufferDescriptor = { … … 377 370 usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.MAP_WRITE 378 371 }; 372 373 let mappedGroups = []; 374 375 function render() { 376 if (mappedGroups.length === 0) { 377 const [buffer, arrayBuffer] = device.createBufferMapped(transformBufferDescriptor); 378 const group = device.createBindGroup(createBindGroupDescriptor(buffer, textureViewBinding, samplerBinding)); 379 let mappedGroup = { buffer: buffer, arrayBuffer: arrayBuffer, bindGroup: group }; 380 drawCommands(mappedGroup); 381 } else 382 drawCommands(mappedGroups.shift()); 383 } 379 384 380 385 function createBindGroupDescriptor(transformBuffer, textureViewBinding, samplerBinding) { … … 392 397 bindings: [transformBufferBindGroupBinding, textureViewBinding, samplerBinding] 393 398 }; 394 }395 396 let mappedGroups = [];397 398 function render() {399 if (mappedGroups.length == 0) {400 const buffer = device.createBuffer(transformBufferDescriptor);401 buffer.mapWriteAsync().then(arrayBuffer => {402 const group = device.createBindGroup(createBindGroupDescriptor(buffer, textureViewBinding, samplerBinding));403 404 let mappedGroup = { buffer: buffer, arrayBuffer: arrayBuffer, bindGroup: group };405 drawCommands(mappedGroup);406 });407 } else408 drawCommands(mappedGroups.shift());409 399 } 410 400 … … 419 409 passEncoder.setPipeline(pipeline); 420 410 // Vertex attributes 421 passEncoder.setVertexBuffers( vertexBufferIndex, [verticesBuffer], [0]);411 passEncoder.setVertexBuffers(0, [verticesBuffer], [0]); 422 412 // Bind groups 423 413 passEncoder.setBindGroup(bindGroupIndex, mappedGroup.bindGroup); … … 436 426 } 437 427 438 init(); 428 function updateTransformArray(array) { 429 let viewMatrix = mat4.create(); 430 mat4.translate(viewMatrix, viewMatrix, vec3.fromValues(0, 0, -5)); 431 let now = Date.now() / 1000; 432 mat4.rotate(viewMatrix, viewMatrix, 1, vec3.fromValues(Math.sin(now), 1, 1)); 433 let modelViewProjectionMatrix = mat4.create(); 434 mat4.multiply(modelViewProjectionMatrix, projectionMatrix, viewMatrix); 435 mat4.copy(array, modelViewProjectionMatrix); 436 } 437 438 window.addEventListener("load", init); 439 439 </script> 440 440 </body>
Note:
See TracChangeset
for help on using the changeset viewer.