| <script src="../../resources/js-test.js"></script> | |
| <script> | |
| jsTestIsAsync = true; | |
| description("Regression test for bugs.webkit.org/show_bug.cgi?id=325413: draws a render bundle with a " + | |
| "dynamic offset twice on the replay path. Both frames should be green."); | |
| async function main() { | |
| let adapter = await navigator.gpu.requestAdapter({}); | |
| let device = await adapter.requestDevice({}); | |
| device.pushErrorScope('validation'); | |
| const format = 'rgba8unorm'; | |
| let module = device.createShaderModule({ code: ` | |
| struct U { color: vec4f, }; | |
| @group(0) @binding(0) var<uniform> u: U; | |
| @vertex fn vs(@builtin(vertex_index) i: u32) -> @builtin(position) vec4f { | |
| var p = array(vec2f(-1, -3), vec2f(-1, 1), vec2f(3, 1)); | |
| return vec4f(p[i], 0, 1); | |
| } | |
| @fragment fn fs() -> @location(0) vec4f { return u.color; } | |
| ` }); | |
| let bindGroupLayout = device.createBindGroupLayout({ | |
| entries: [{ binding: 0, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform', hasDynamicOffset: true } }], | |
| }); | |
| let pipeline = device.createRenderPipeline({ | |
| layout: device.createPipelineLayout({ bindGroupLayouts: [bindGroupLayout] }), | |
| vertex: { module, entryPoint: 'vs' }, | |
| fragment: { module, entryPoint: 'fs', targets: [{ format }] }, | |
| primitive: { topology: 'triangle-list' }, | |
| multisample: { count: 1, mask: 0x7fffffff }, | |
| }); | |
| let uniform = new Uint8Array(512); | |
| new Uint8Array(uniform.buffer, 0, 16).set(new Uint8Array(new Float32Array([1, 0, 0, 1]).buffer)); | |
| new Uint8Array(uniform.buffer, 256, 16).set(new Uint8Array(new Float32Array([0, 1, 0, 1]).buffer)); | |
| let uniformBuffer = device.createBuffer({ size: 512, usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST }); | |
| device.queue.writeBuffer(uniformBuffer, 0, uniform); | |
| let bindGroup = device.createBindGroup({ | |
| layout: bindGroupLayout, | |
| entries: [{ binding: 0, resource: { buffer: uniformBuffer, size: 16 } }], | |
| }); | |
| let enc = device.createRenderBundleEncoder({ colorFormats: [format] }); | |
| enc.setPipeline(pipeline); | |
| enc.setBindGroup(0, bindGroup, [256]); | |
| enc.draw(3); | |
| let bundle = enc.finish(); | |
| let texture = device.createTexture({ size: [1, 1], format, usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC }); | |
| let readback = device.createBuffer({ size: 256, usage: GPUBufferUsage.COPY_DST | GPUBufferUsage.MAP_READ }); | |
| function drawAndReadback() { | |
| let commandEncoder = device.createCommandEncoder(); | |
| let pass = commandEncoder.beginRenderPass({ | |
| colorAttachments: [{ view: texture.createView(), loadOp: 'clear', storeOp: 'store', clearValue: { r: 0, g: 0, b: 0, a: 1 } }], | |
| }); | |
| pass.executeBundles([bundle]); | |
| pass.end(); | |
| commandEncoder.copyTextureToBuffer({ texture }, { buffer: readback, bytesPerRow: 256 }, [1, 1]); | |
| device.queue.submit([commandEncoder.finish()]); | |
| } | |
| drawAndReadback(); | |
| await device.queue.onSubmittedWorkDone(); | |
| await readback.mapAsync(GPUMapMode.READ); | |
| let frame0 = [...new Uint8Array(readback.getMappedRange(0, 4))]; | |
| readback.unmap(); | |
| drawAndReadback(); | |
| await device.queue.onSubmittedWorkDone(); | |
| await readback.mapAsync(GPUMapMode.READ); | |
| let frame1 = [...new Uint8Array(readback.getMappedRange(0, 4))]; | |
| readback.unmap(); | |
| window.frame0 = frame0; | |
| window.frame1 = frame1; | |
| shouldBeEqualToString('frame0.join()', '0,255,0,255'); | |
| shouldBeEqualToString('frame1.join()', '0,255,0,255'); | |
| let error = await device.popErrorScope(); | |
| if (error) | |
| testFailed(error.message); | |
| } | |
| main().catch(e => { | |
| testFailed("Exception: " + e); | |
| }).finally(() => { | |
| finishJSTest(); | |
| }); | |
| </script> |