slow.spec.ts (6147B)
1 export const description = ` 2 Stress tests covering robustness in the presence of slow shaders. 3 `; 4 5 import { makeTestGroup } from '../../common/framework/test_group.js'; 6 import { GPUTest } from '../../webgpu/gpu_test.js'; 7 import * as ttu from '../../webgpu/texture_test_utils.js'; 8 9 export const g = makeTestGroup(GPUTest); 10 11 g.test('compute') 12 .desc(`Tests execution of compute passes with very long-running dispatch operations.`) 13 .fn(t => { 14 const kDispatchSize = 1000; 15 const data = new Uint32Array(kDispatchSize); 16 const buffer = t.makeBufferWithContents(data, GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC); 17 const module = t.device.createShaderModule({ 18 code: ` 19 struct Buffer { data: array<u32>, }; 20 @group(0) @binding(0) var<storage, read_write> buffer: Buffer; 21 @compute @workgroup_size(1) fn main( 22 @builtin(global_invocation_id) id: vec3<u32>) { 23 loop { 24 if (buffer.data[id.x] == 1000000u) { 25 break; 26 } 27 buffer.data[id.x] = buffer.data[id.x] + 1u; 28 } 29 } 30 `, 31 }); 32 const pipeline = t.device.createComputePipeline({ 33 layout: 'auto', 34 compute: { module, entryPoint: 'main' }, 35 }); 36 const encoder = t.device.createCommandEncoder(); 37 const pass = encoder.beginComputePass(); 38 pass.setPipeline(pipeline); 39 const bindGroup = t.device.createBindGroup({ 40 layout: pipeline.getBindGroupLayout(0), 41 entries: [{ binding: 0, resource: { buffer } }], 42 }); 43 pass.setBindGroup(0, bindGroup); 44 pass.dispatchWorkgroups(kDispatchSize); 45 pass.end(); 46 t.device.queue.submit([encoder.finish()]); 47 t.expectGPUBufferValuesEqual(buffer, new Uint32Array(new Array(kDispatchSize).fill(1000000))); 48 }); 49 50 g.test('vertex') 51 .desc(`Tests execution of render passes with a very long-running vertex stage.`) 52 .fn(t => { 53 const module = t.device.createShaderModule({ 54 code: ` 55 struct Data { counter: u32, increment: u32, }; 56 @group(0) @binding(0) var<uniform> data: Data; 57 @vertex fn vmain() -> @builtin(position) vec4<f32> { 58 var counter: u32 = data.counter; 59 loop { 60 counter = counter + data.increment; 61 if (counter % 50000000u == 0u) { 62 break; 63 } 64 } 65 return vec4<f32>(1.0, 1.0, 0.0, f32(counter)); 66 } 67 @fragment fn fmain() -> @location(0) vec4<f32> { 68 return vec4<f32>(1.0, 1.0, 0.0, 1.0); 69 } 70 `, 71 }); 72 73 const pipeline = t.device.createRenderPipeline({ 74 layout: 'auto', 75 vertex: { module, entryPoint: 'vmain', buffers: [] }, 76 primitive: { topology: 'point-list' }, 77 fragment: { 78 targets: [{ format: 'rgba8unorm' }], 79 module, 80 entryPoint: 'fmain', 81 }, 82 }); 83 const uniforms = t.makeBufferWithContents(new Uint32Array([0, 1]), GPUBufferUsage.UNIFORM); 84 const bindGroup = t.device.createBindGroup({ 85 layout: pipeline.getBindGroupLayout(0), 86 entries: [ 87 { 88 binding: 0, 89 resource: { buffer: uniforms }, 90 }, 91 ], 92 }); 93 const renderTarget = t.createTextureTracked({ 94 size: [3, 3], 95 usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, 96 format: 'rgba8unorm', 97 }); 98 const encoder = t.device.createCommandEncoder(); 99 const pass = encoder.beginRenderPass({ 100 colorAttachments: [ 101 { 102 view: renderTarget.createView(), 103 clearValue: [0, 0, 0, 0], 104 loadOp: 'clear', 105 storeOp: 'store', 106 }, 107 ], 108 }); 109 pass.setPipeline(pipeline); 110 pass.setBindGroup(0, bindGroup); 111 pass.draw(1); 112 pass.end(); 113 t.device.queue.submit([encoder.finish()]); 114 ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: renderTarget }, [ 115 { 116 coord: { x: 1, y: 1 }, 117 exp: new Uint8Array([255, 255, 0, 255]), 118 }, 119 ]); 120 }); 121 122 g.test('fragment') 123 .desc(`Tests execution of render passes with a very long-running fragment stage.`) 124 .fn(t => { 125 const module = t.device.createShaderModule({ 126 code: ` 127 struct Data { counter: u32, increment: u32, }; 128 @group(0) @binding(0) var<uniform> data: Data; 129 @vertex fn vmain() -> @builtin(position) vec4<f32> { 130 return vec4<f32>(0.0, 0.0, 0.0, 1.0); 131 } 132 @fragment fn fmain() -> @location(0) vec4<f32> { 133 var counter: u32 = data.counter; 134 loop { 135 counter = counter + data.increment; 136 if (counter % 50000000u == 0u) { 137 break; 138 } 139 } 140 return vec4<f32>(1.0, 1.0, 1.0 / f32(counter), 1.0); 141 } 142 `, 143 }); 144 145 const pipeline = t.device.createRenderPipeline({ 146 layout: 'auto', 147 vertex: { module, entryPoint: 'vmain', buffers: [] }, 148 primitive: { topology: 'point-list' }, 149 fragment: { 150 targets: [{ format: 'rgba8unorm' }], 151 module, 152 entryPoint: 'fmain', 153 }, 154 }); 155 const uniforms = t.makeBufferWithContents(new Uint32Array([0, 1]), GPUBufferUsage.UNIFORM); 156 const bindGroup = t.device.createBindGroup({ 157 layout: pipeline.getBindGroupLayout(0), 158 entries: [ 159 { 160 binding: 0, 161 resource: { buffer: uniforms }, 162 }, 163 ], 164 }); 165 const renderTarget = t.createTextureTracked({ 166 size: [3, 3], 167 usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, 168 format: 'rgba8unorm', 169 }); 170 const encoder = t.device.createCommandEncoder(); 171 const pass = encoder.beginRenderPass({ 172 colorAttachments: [ 173 { 174 view: renderTarget.createView(), 175 clearValue: [0, 0, 0, 0], 176 loadOp: 'clear', 177 storeOp: 'store', 178 }, 179 ], 180 }); 181 pass.setPipeline(pipeline); 182 pass.setBindGroup(0, bindGroup); 183 pass.draw(1); 184 pass.end(); 185 t.device.queue.submit([encoder.finish()]); 186 ttu.expectSinglePixelComparisonsAreOkInTexture(t, { texture: renderTarget }, [ 187 { 188 coord: { x: 1, y: 1 }, 189 exp: new Uint8Array([255, 255, 0, 255]), 190 }, 191 ]); 192 });