tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

non_halting.spec.ts (5830B)


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