vertex_buffers.spec.ts (3776B)
1 export const description = ` 2 Stress tests covering vertex buffer usage. 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 function createHugeVertexBuffer(t: GPUTest, size: number) { 11 const kBufferSize = size * size * 8; 12 const buffer = t.createBufferTracked({ 13 size: kBufferSize, 14 usage: GPUBufferUsage.STORAGE | GPUBufferUsage.COPY_SRC, 15 }); 16 const pipeline = t.device.createComputePipeline({ 17 layout: 'auto', 18 compute: { 19 module: t.device.createShaderModule({ 20 code: ` 21 struct Buffer { data: array<vec2<u32>>, }; 22 @group(0) @binding(0) var<storage, read_write> buffer: Buffer; 23 @compute @workgroup_size(1) fn main( 24 @builtin(global_invocation_id) id: vec3<u32>) { 25 let base = id.x * ${size}u; 26 for (var x: u32 = 0u; x < ${size}u; x = x + 1u) { 27 buffer.data[base + x] = vec2<u32>(x, id.x); 28 } 29 } 30 `, 31 }), 32 entryPoint: 'main', 33 }, 34 }); 35 const bindGroup = t.device.createBindGroup({ 36 layout: pipeline.getBindGroupLayout(0), 37 entries: [ 38 { 39 binding: 0, 40 resource: { buffer }, 41 }, 42 ], 43 }); 44 const encoder = t.device.createCommandEncoder(); 45 const pass = encoder.beginComputePass(); 46 pass.setPipeline(pipeline); 47 pass.setBindGroup(0, bindGroup); 48 pass.dispatchWorkgroups(size); 49 pass.end(); 50 51 const vertexBuffer = t.createBufferTracked({ 52 size: kBufferSize, 53 usage: GPUBufferUsage.VERTEX | GPUBufferUsage.COPY_DST, 54 }); 55 encoder.copyBufferToBuffer(buffer, 0, vertexBuffer, 0, kBufferSize); 56 t.device.queue.submit([encoder.finish()]); 57 return vertexBuffer; 58 } 59 60 g.test('many') 61 .desc(`Tests execution of draw calls using a huge vertex buffer.`) 62 .fn(t => { 63 const kSize = 4096; 64 const buffer = createHugeVertexBuffer(t, kSize); 65 const module = t.device.createShaderModule({ 66 code: ` 67 @vertex fn vmain(@location(0) position: vec2<u32>) 68 -> @builtin(position) vec4<f32> { 69 let r = vec2<f32>(1.0 / f32(${kSize})); 70 let a = 2.0 * r; 71 let b = r - vec2<f32>(1.0); 72 return vec4<f32>(fma(vec2<f32>(position), a, b), 0.0, 1.0); 73 } 74 @fragment fn fmain() -> @location(0) vec4<f32> { 75 return vec4<f32>(1.0, 0.0, 1.0, 1.0); 76 } 77 `, 78 }); 79 const pipeline = t.device.createRenderPipeline({ 80 layout: 'auto', 81 vertex: { 82 module, 83 entryPoint: 'vmain', 84 buffers: [ 85 { 86 arrayStride: 8, 87 attributes: [ 88 { 89 format: 'uint32x2', 90 offset: 0, 91 shaderLocation: 0, 92 }, 93 ], 94 }, 95 ], 96 }, 97 primitive: { topology: 'point-list' }, 98 fragment: { 99 targets: [{ format: 'rgba8unorm' }], 100 module, 101 entryPoint: 'fmain', 102 }, 103 }); 104 const renderTarget = t.createTextureTracked({ 105 size: [kSize, kSize], 106 usage: GPUTextureUsage.RENDER_ATTACHMENT | GPUTextureUsage.COPY_SRC, 107 format: 'rgba8unorm', 108 }); 109 const renderPassDescriptor: GPURenderPassDescriptor = { 110 colorAttachments: [ 111 { 112 view: renderTarget.createView(), 113 loadOp: 'load', 114 storeOp: 'store', 115 }, 116 ], 117 }; 118 119 const encoder = t.device.createCommandEncoder(); 120 const pass = encoder.beginRenderPass(renderPassDescriptor); 121 pass.setPipeline(pipeline); 122 pass.setVertexBuffer(0, buffer); 123 pass.draw(kSize * kSize); 124 pass.end(); 125 t.device.queue.submit([encoder.finish()]); 126 t.expectSingleColor(renderTarget, 'rgba8unorm', { 127 size: [kSize, kSize, 1], 128 exp: { R: 1, G: 0, B: 1, A: 1 }, 129 }); 130 });