| <!-- webkit-test-runner [ enableMetalShaderValidation=true ] --> |
| <style> |
| :root { background: #102030e0; color: #99ddbbcc; font-size: 15px; } |
| </style> |
| <script src="../../../resources/js-test-pre.js"></script> |
| <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?.dumpAsText(); |
| globalThis.testRunner?.waitUntilDone(); |
| |
| |
| async function window0() { |
| // START |
| c = await navigator.gpu.requestAdapter(); |
| device0 = await c.requestDevice(); |
| texture1 = device0.createTexture({ |
| size : [], |
| dimension : '1d', |
| format : 'rgba16sint', |
| usage : GPUTextureUsage.STORAGE_BINDING | [] |
| }); |
| veryExplicitBindGroupLayout1 = device0.createBindGroupLayout({ |
| entries : [ |
| { |
| binding : 15, |
| visibility : GPUShaderStage | GPUShaderStage, |
| storageTexture : {format : 'rgba16sint', viewDimension : '1d'} |
| }, |
| {binding : 31, visibility : GPUShaderStage.VERTEX, externalTexture : {}}, |
| {binding : 63, visibility : GPUShaderStage.FRAGMENT, externalTexture : {}}, |
| { |
| binding : 138, |
| visibility : GPUShaderStage.FRAGMENT, |
| buffer : {type : 'storage', hasDynamicOffset : true} |
| }, |
| { |
| binding : 141, |
| visibility : GPUShaderStage.FRAGMENT, |
| buffer : {type : 'storage'} |
| } |
| ] |
| }) |
| textureView2 = texture1.createView() |
| d = device0.createShaderModule({ |
| code : ` |
| fn unconst_u32(f: u32) -> u32 { |
| return f; |
| } |
| @group(0) @binding(141) var<storage, read_write> buffer3: array<array<atomic<u32>, 7>>; |
| @vertex fn vertex0(@location(10) h: vec4u, @location(6) a2: vec2i) -> @builtin(position) vec4f { |
| var i: vec4f; |
| return i; |
| } |
| @fragment fn fragment0() -> @location(200) vec4i { |
| var i: vec4i; |
| if bool(atomicExchange(&buffer3[arrayLength(&buffer3)][unconst_u32(8)], 71)) { |
| } |
| return i; |
| } |
| @compute @workgroup_size(11) fn j() {} |
| ` |
| }) |
| let texture14 = device0.createTexture({ |
| size : [ 120, 176 ], |
| format : 'depth16unorm', |
| usage : GPUTextureUsage.RENDER_ATTACHMENT |
| }) |
| k = device0.createPipelineLayout( |
| {bindGroupLayouts : [ veryExplicitBindGroupLayout1 ]}); |
| l = await device0.createRenderPipelineAsync({ |
| layout : k, |
| fragment : { |
| module : d, |
| targets : [ { |
| format : 'rg16sint', |
| } ] |
| }, |
| depthStencil : { |
| format : 'depth16unorm', |
| depthWriteEnabled : true, |
| depthCompare : 'less-equal' |
| }, |
| vertex : { |
| module : d, |
| buffers : [ { |
| arrayStride : 308, |
| attributes : [ |
| {format : 'sint8x2', offset : 86, shaderLocation : 6}, |
| {format : 'uint32x4', offset : 8, shaderLocation : 10} |
| ] |
| } ] |
| }, |
| primitive : {topology : 'point-list'} |
| }); |
| n = device0.createTexture({ |
| size : [ 120, 176 ], |
| format : 'rg16sint', |
| usage : GPUTextureUsage.RENDER_ATTACHMENT |
| }) |
| let textureView10 = n.createView(); |
| videoFrame0 = new VideoFrame(new ArrayBuffer(16), { |
| codedWidth : 2, |
| codedHeight : 2, |
| format : 'RGBX', |
| timestamp : 0}) |
| o = device0.createComputePipeline({ |
| layout : k, |
| compute : { |
| module : d, |
| } |
| }) |
| p = new VideoFrame( |
| new ArrayBuffer(16), |
| {codedWidth : 2, codedHeight : 2, format : 'RGBX', timestamp : 0}) |
| recycledExplicitBindGroupLayout0 = o.getBindGroupLayout({GPUBufferUsage}) |
| shaderModule1 = device0.createShaderModule({ |
| code : ` @compute @workgroup_size(1) fn compute1() {} |
| ` |
| }) |
| q = device0.createPipelineLayout( |
| {bindGroupLayouts : [ recycledExplicitBindGroupLayout0 ]}) |
| textureView13 = texture14.createView() |
| s = device0.createComputePipeline( |
| {layout : q, compute : {module : shaderModule1}}); |
| recycledExplicitBindGroupLayout1 = s.getBindGroupLayout(0) |
| commandEncoder28 = device0.createCommandEncoder() |
| t = device0.createBuffer({size : 33, usage : GPUBufferUsage.STORAGE}) |
| buffer34 = device0.createBuffer({size : 15286, usage : GPUBufferUsage.STORAGE}) |
| externalTexture4 = device0.importExternalTexture({source : videoFrame0}) |
| u = commandEncoder28.beginRenderPass({ |
| colorAttachments : [ { |
| view : textureView10, |
| clearValue : {r : 121.6, g : 258.5, b : 159.7, a : 317.9}, |
| loadOp : 'load', |
| storeOp : 'store' |
| } ], |
| depthStencilAttachment : |
| {view : textureView13, depthLoadOp : 'load', depthStoreOp : 'store'} |
| }) |
| v = device0.importExternalTexture({source : p}) |
| try { |
| u.setPipeline(l) |
| } catch { |
| } |
| bindGroup31 = device0.createBindGroup({ |
| layout : recycledExplicitBindGroupLayout1, |
| entries : [ |
| {binding : 138, resource : {buffer : buffer34, offset : 2048, size : 3644}}, |
| {binding : 141, resource : {buffer : t, size : 28}}, |
| {binding : 31, resource : v}, {binding : 15, resource : textureView2}, |
| {binding : 63, resource : externalTexture4} |
| ] |
| }); |
| buffer87 = device0.createBuffer({size : 8036, usage : GPUBufferUsage.VERTEX}) |
| try { |
| u.setBindGroup(0, bindGroup31, [ 768 ]) |
| } catch { |
| } |
| try { |
| u.setVertexBuffer(0, buffer87) |
| u.draw(1) |
| } catch { |
| } |
| try { |
| u.end() |
| } catch { |
| } |
| commandBuffer21 = commandEncoder28.finish(); |
| try { |
| device0.queue.submit([ commandBuffer21 ]) |
| } catch { |
| } |
| // END |
| await device0.queue.onSubmittedWorkDone(); |
| } |
| |
| onload = async () => { |
| try { |
| let sharedScript = document.querySelector('#shared').textContent; |
| |
| let workers = [ |
| |
| ]; |
| let promises = [ window0() ]; |
| debug('promises created'); |
| let results = await Promise.allSettled(promises); |
| for (let result of results) { |
| if (result.status === 'rejected') { throw result.reason; } |
| } |
| debug('Pass') |
| } 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); |
| |
| } |
| } |
| globalThis.testRunner?.notifyDone(); |
| }; |
| </script> |
| |