| <style> |
| :root { background: #102030e0; color: #99ddbbcc; font-size: 15px; } |
| </style> |
| <script id="shared"> |
| const log = console.log; |
| |
| async function gc() { |
| await 0; |
| if (globalThis.GCController) { |
| globalThis.GCController.collect(); |
| } else if (globalThis.$vm) { |
| globalThis.$vm.gc(); |
| } else { |
| log('no GC available'); |
| } |
| } |
| |
| /** |
| * @param {GPUDevice} device |
| * @param {GPUComputePassEncoder} computePassEncoder |
| */ |
| function clearResourceUsages(device, computePassEncoder) { |
| let code = `@compute @workgroup_size(1) fn c() {}`; |
| let module = device.createShaderModule({code}); |
| computePassEncoder.setPipeline(device.createComputePipeline( |
| { |
| layout: 'auto', |
| compute: {module}, |
| })); |
| computePassEncoder.dispatchWorkgroups(1); |
| } |
| |
| /** |
| * @template {any} T |
| * @param {GPUDevice} device |
| * @param {string} label |
| * @param {()=>T} payload |
| * @returns {Promise<T>} |
| */ |
| async function validationWrapper(device, label, payload) { |
| device.pushErrorScope('internal'); |
| device.pushErrorScope('out-of-memory'); |
| device.pushErrorScope('validation'); |
| let result = payload(); |
| let validationError = await device.popErrorScope(); |
| let outOfMemoryError = await device.popErrorScope(); |
| let internalError = await device.popErrorScope(); |
| let error = validationError ?? outOfMemoryError ?? internalError; |
| if (error) { |
| log('*'.repeat(25)); |
| log(error[Symbol.toStringTag]); |
| log(error.message); |
| log(label); |
| if (error.stack != `_`) { |
| log(error.stack); |
| } |
| log(location); |
| log('*'.repeat(25)); |
| throw error; |
| } |
| return result; |
| } |
| |
| const videoUrls = [ |
| |
| ]; |
| |
| /** |
| * @param {number} index |
| * @returns {Promise<HTMLVideoElement>} |
| */ |
| function videoWithData(index) { |
| let video = document.createElement('video'); |
| video.src = videoUrls[index % videoUrls.length]; |
| return new Promise(resolve => { |
| video.onloadeddata = () => { |
| resolve(video); |
| }; |
| }); |
| } |
| |
| /** |
| * @returns {Promise<string>} |
| */ |
| async function makeDataUrl(width, height, color0, color1) { |
| let offscreenCanvas = new OffscreenCanvas(width, height); |
| let ctx = offscreenCanvas.getContext('2d'); |
| let gradient = ctx.createLinearGradient(0, 0, width, height); |
| gradient.addColorStop(0, color0); |
| gradient.addColorStop(0.1, color1); |
| gradient.addColorStop(0.3, color0); |
| gradient.addColorStop(0.7, color1); |
| gradient.addColorStop(0.9, color0); |
| gradient.addColorStop(1, color1); |
| ctx.fillStyle = gradient; |
| ctx.fillRect(0, 0, width, height); |
| let blob = await offscreenCanvas.convertToBlob(); |
| let fileReader = new FileReader(); |
| fileReader.readAsDataURL(blob); |
| return new Promise(resolve => { |
| fileReader.onload = () => { |
| resolve(fileReader.result); |
| }; |
| }); |
| } |
| |
| async function imageWithData(width, height, color0, color1) { |
| let dataUrl = await makeDataUrl(width, height, color0, color1); |
| let img = document.createElement('img'); |
| img.src = dataUrl; |
| await img.decode(); |
| return img; |
| } |
| |
| /** |
| * @param {string} payload |
| * @returns {string} |
| */ |
| function toBlobUrl(payload) { |
| let blob = new Blob([payload], {type: 'text/javascript'}); |
| return URL.createObjectURL(blob); |
| } |
| </script> |
| <script> |
| globalThis.testRunner?.waitUntilDone(); |
| |
| async function window0() { |
| let promise0 = navigator.gpu.requestAdapter({powerPreference: 'low-power'}); |
| let adapter0 = await navigator.gpu.requestAdapter({}); |
| let device0 = await adapter0.requestDevice({}); |
| |
| let indexBuffer = device0.createBuffer({ size: 161, usage: GPUBufferUsage.INDEX }); |
| let vertexBuffer = device0.createBuffer({ size: 48, usage: GPUBufferUsage.INDEX | GPUBufferUsage.INDIRECT | GPUBufferUsage.VERTEX }); |
| |
| let texture5 = device0.createTexture({ size: [4, 4, 5], mipLevelCount: 1, dimension: '3d', format: 'rgb10a2uint', usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT, }); |
| let texture15 = device0.createTexture({ size: [105, 1, 106], format: 'rgba8uint', usage: GPUTextureUsage.COPY_SRC | GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.STORAGE_BINDING, viewFormats: [], }); |
| |
| let textureView3 = texture5.createView({ baseMipLevel: 0 }); |
| let textureView19 = texture15.createView({ dimension: '2d', baseArrayLayer: 23 }); |
| |
| let bindGroupLayout = device0.createBindGroupLayout({ |
| entries: [ |
| { binding: 0, visibility: GPUShaderStage.FRAGMENT, storageTexture: { format: 'rgba8uint', access: 'read-only', viewDimension: '2d' }, }, |
| ], |
| }); |
| let pipelineLayout = device0.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }); |
| |
| let shaderModule = device0.createShaderModule({ code: ` |
| struct VertexInput1 { |
| @location(8) location_8: vec2i, |
| } |
| |
| @vertex @must_use fn vertex0(a3: VertexInput1) -> @builtin(position) vec4f { |
| while bool(a3.location_8.y) { |
| } |
| return vec4f(); |
| } |
| |
| @fragment fn fragment0() -> @location(200) vec4u { |
| return vec4u(); |
| } |
| `, }); |
| |
| let pipeline = await device0.createRenderPipelineAsync({ |
| layout: pipelineLayout, |
| fragment: { |
| module: shaderModule, |
| entryPoint: 'fragment0', |
| targets: [ |
| { format: 'rgb10a2uint', writeMask: GPUColorWrite.ALL | GPUColorWrite.GREEN } |
| ], |
| }, |
| vertex: { |
| module: shaderModule, |
| buffers: [ |
| { |
| arrayStride: 16, |
| attributes: [ |
| { format: 'sint32x3', offset: 0, shaderLocation: 8 }, |
| ], |
| } |
| ], |
| }, |
| }); |
| |
| let bindGroup = device0.createBindGroup({ |
| layout: bindGroupLayout, |
| entries: [ |
| { binding: 0, resource: textureView19 }, |
| ], |
| }); |
| |
| let commandEncoder = device0.createCommandEncoder({}); |
| |
| let renderPassEncoder = commandEncoder.beginRenderPass({colorAttachments: [{view: textureView3, depthSlice: 2, loadOp: 'clear', storeOp: 'store'}]}); |
| renderPassEncoder.setPipeline(pipeline); |
| renderPassEncoder.setBindGroup(0, bindGroup, new Uint32Array(6574), 1_991, 0); |
| renderPassEncoder.setIndexBuffer(indexBuffer, 'uint32', 28, 32); |
| renderPassEncoder.setVertexBuffer(0, vertexBuffer); |
| renderPassEncoder.drawIndexed(5, 1, 2, 242_554_081); |
| renderPassEncoder.end(); |
| |
| device0.queue.submit([commandEncoder.finish()]); |
| |
| await device0.queue.onSubmittedWorkDone(); |
| } |
| |
| onload = async () => { |
| try { |
| let sharedScript = document.querySelector('#shared').textContent; |
| |
| let workers = [ |
| |
| ]; |
| let promises = [ window0() ]; |
| log('promises created'); |
| let results = await Promise.allSettled(promises); |
| for (let result of results) { |
| if (result.status === 'rejected') { throw result.reason; } |
| } |
| log('the end') |
| log(location); |
| } catch (e) { |
| log('error'); |
| log(e); |
| log(e[Symbol.toStringTag]); |
| log(e.stack); |
| if (e instanceof GPUPipelineError) { |
| log(`${e} - ${e.reason}`); |
| |
| } else if (e instanceof DOMException) { |
| if (e.name === 'OperationError') { |
| log(e.message); |
| |
| } else if (e.name === 'InvalidStateError') { |
| } else { |
| log(e); |
| |
| } |
| } else if (e instanceof GPUValidationError) { |
| |
| } else if (e instanceof GPUOutOfMemoryError) { |
| |
| } else if (e instanceof TypeError) { |
| log(e); |
| |
| } else { |
| log('unexpected error type'); |
| log(e); |
| |
| } |
| } |
| log('Pass'); |
| globalThis.testRunner?.dumpAsText(); |
| globalThis.testRunner?.notifyDone(); |
| }; |
| </script> |