tor-browser

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

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  });