| <script> |
| globalThis.testRunner?.waitUntilDone(); |
| const log = console.debug; |
| |
| const format = 'bgra8unorm'; |
| const veryBrightVideo = `data:video/mp4;base64,AAAAHGZ0eXBpc29tAAACAGlzb21pc28ybXA0MQAAAAhmcmVlAAAAvG1kYXQAAAAfTgEFGkdWStxcTEM/lO/FETzRQ6gD7gAA7gIAA3EYgAAAAEgoAa8iNjAkszOL+e58c//cEe//0TT//scp1n/381P/RWP/zOW4QtxorfVogeh8nQDbQAAAAwAQMCcWUTAAAAMAAAMAAAMA84AAAAAVAgHQAyu+KT35E7gAADFgAAADABLQAAAAEgIB4AiS76MTkNbgAAF3AAAPSAAAABICAeAEn8+hBOTXYAADUgAAHRAAAAPibW9vdgAAAGxtdmhkAAAAAAAAAAAAAAAAAAAD6AAAAKcAAQAAAQAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAw10cmFrAAAAXHRraGQAAAADAAAAAAAAAAAAAAABAAAAAAAAAKcAAAAAAAAAAAAAAAAAAAAAAAEAAAAAAAAAAAAAAAAAAAABAAAAAAAAAAAAAAAAAABAAAAAABAAAAAQAAAAAAAkZWR0cwAAABxlbHN0AAAAAAAAAAEAAACnAAAAAAABAAAAAAKFbWRpYQAAACBtZGhkAAAAAAAAAAAAAAAAAABdwAAAD6BVxAAAAAAAMWhkbHIAAAAAAAAAAHZpZGUAAAAAAAAAAAAAAABDb3JlIE1lZGlhIFZpZGVvAAAAAixtaW5mAAAAFHZtaGQAAAABAAAAAAAAAAAAAAAkZGluZgAAABxkcmVmAAAAAAAAAAEAAAAMdXJsIAAAAAEAAAHsc3RibAAAARxzdHNkAAAAAAAAAAEAAAEMaHZjMQAAAAAAAAABAAAAAAAAAAAAAAAAAAAAAAAQABAASAAAAEgAAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABj//wAAAHVodmNDAQIgAAAAsAAAAAAAPPAA/P36+gAACwOgAAEAGEABDAH//wIgAAADALAAAAMAAAMAPBXAkKEAAQAmQgEBAiAAAAMAsAAAAwAAAwA8oBQgQcCTDLYgV7kWVYC1CRAJAICiAAEACUQBwChkuNBTJAAAAApmaWVsAQAAAAATY29scm5jbHgACQAQAAkAAAAAEHBhc3AAAAABAAAAAQAAABRidHJ0AAAAAAAALPwAACz8AAAAKHN0dHMAAAAAAAAAAwAAAAIAAAPoAAAAAQAAAAEAAAABAAAD6AAAABRzdHNzAAAAAAAAAAEAAAABAAAAEHNkdHAAAAAAIBAQGAAAAChjdHRzAAAAAAAAAAMAAAABAAAAAAAAAAEAAAfQAAAAAgAAAAAAAAAcc3RzYwAAAAAAAAABAAAAAQAAAAQAAAABAAAAJHN0c3oAAAAAAAAAAAAAAAQAAABvAAAAGQAAABYAAAAWAAAAFHN0Y28AAAAAAAAAAQAAACwAAABhdWR0YQAAAFltZXRhAAAAAAAAACFoZGxyAAAAAAAAAABtZGlyYXBwbAAAAAAAAAAAAAAAACxpbHN0AAAAJKl0b28AAAAcZGF0YQAAAAEAAAAATGF2ZjYwLjMuMTAw`; |
| |
| function videoWithData() { |
| let video = document.createElement('video'); |
| video.src = veryBrightVideo; |
| video.muted = true; |
| return new Promise(resolve => { |
| video.onloadeddata = () => { |
| resolve(video); |
| }; |
| }); |
| } |
| |
| function createCanvasAndContext(device) { |
| let canvas = document.createElement('canvas'); |
| document.body.append(canvas); |
| let context = canvas.getContext('webgpu'); |
| context.configure({device, format, usage: GPUTextureUsage.RENDER_ATTACHMENT}); |
| return context; |
| } |
| |
| onload = async () => { |
| let adapter = await navigator.gpu.requestAdapter({}); |
| let device = await adapter.requestDevice({}); |
| let context = createCanvasAndContext(device); |
| let vertexesF32 = new Float32Array([1, -1, -1, 1, -1, -1]); |
| let vertexBuffer = device.createBuffer({size: vertexesF32.byteLength, usage: GPUBufferUsage.VERTEX, mappedAtCreation: true}); |
| new Float32Array(vertexBuffer.getMappedRange()).set(vertexesF32); |
| vertexBuffer.unmap(); |
| let v = await videoWithData(); |
| let code = ` |
| @vertex |
| fn v(@location(0) position : vec4f) -> @builtin(position) vec4f { |
| return position; |
| } |
| |
| @group(0) @binding(0) var et: texture_external; |
| |
| @fragment |
| fn f() -> @location(0) vec4f { |
| return textureLoad(et, vec2()); |
| } |
| `; |
| let bindGroupLayout = device.createBindGroupLayout({ |
| entries: [{binding: 0, externalTexture: {}, visibility: GPUShaderStage.FRAGMENT}], |
| }); |
| let module = device.createShaderModule({code}); |
| let pipeline = device.createRenderPipeline({ |
| layout: device.createPipelineLayout({bindGroupLayouts: [bindGroupLayout]}), |
| vertex: { |
| module, |
| buffers: [{arrayStride: 8, attributes: [{shaderLocation: 0, offset: 0, format: 'float32x2'}]}], |
| }, |
| fragment: {module, targets: [{format}]}, |
| }); |
| |
| let oneFrame = async _ => { |
| device.pushErrorScope('validation'); |
| let commandEncoder = device.createCommandEncoder(); |
| let renderPassEncoder = commandEncoder.beginRenderPass({ |
| colorAttachments: [ |
| { |
| view: context.getCurrentTexture().createView(), |
| clearValue: [0.5, 0.5, 0.5, 0.5], |
| loadOp: 'clear', storeOp: 'store', |
| }, |
| ], |
| }); |
| let externalTexture0 = device.importExternalTexture({source: v}); |
| let textureBindGroup = device.createBindGroup({ |
| layout: bindGroupLayout, |
| entries: [{binding: 0, resource: externalTexture0}], |
| }); |
| renderPassEncoder.setPipeline(pipeline); |
| renderPassEncoder.setVertexBuffer(0, vertexBuffer); |
| renderPassEncoder.setBindGroup(0, textureBindGroup); |
| renderPassEncoder.draw(3); |
| renderPassEncoder.end(); |
| device.queue.submit([commandEncoder.finish()]); |
| await device.queue.onSubmittedWorkDone(); |
| let error = await device.popErrorScope(); |
| if (error) { |
| log(error.message); |
| } else { |
| log('no validation error'); |
| } |
| globalThis.testRunner?.notifyDone(); |
| }; |
| v.src = 'data:'; |
| requestAnimationFrame(oneFrame); |
| }; |
| </script> |