(device: GPUDevice, options?: LineRendererOptions)
| 111 | }; |
| 112 | |
| 113 | export function createLineRenderer(device: GPUDevice, options?: LineRendererOptions): LineRenderer { |
| 114 | let disposed = false; |
| 115 | const targetFormat = options?.targetFormat ?? DEFAULT_TARGET_FORMAT; |
| 116 | |
| 117 | const bindGroupLayout = device.createBindGroupLayout({ |
| 118 | entries: [ |
| 119 | { binding: 0, visibility: GPUShaderStage.VERTEX, buffer: { type: 'uniform' } }, |
| 120 | { binding: 1, visibility: GPUShaderStage.FRAGMENT, buffer: { type: 'uniform' } }, |
| 121 | ], |
| 122 | }); |
| 123 | |
| 124 | const vsUniformBuffer = createUniformBuffer(device, 64, { label: 'lineRenderer/vsUniforms' }); |
| 125 | const fsUniformBuffer = createUniformBuffer(device, 16, { label: 'lineRenderer/fsUniforms' }); |
| 126 | |
| 127 | // Reused CPU-side staging for uniform writes (avoid per-frame allocations). |
| 128 | const vsUniformScratchBuffer = new ArrayBuffer(64); |
| 129 | const vsUniformScratchF32 = new Float32Array(vsUniformScratchBuffer); |
| 130 | const fsUniformScratchF32 = new Float32Array(4); |
| 131 | |
| 132 | const bindGroup = device.createBindGroup({ |
| 133 | layout: bindGroupLayout, |
| 134 | entries: [ |
| 135 | { binding: 0, resource: { buffer: vsUniformBuffer } }, |
| 136 | { binding: 1, resource: { buffer: fsUniformBuffer } }, |
| 137 | ], |
| 138 | }); |
| 139 | |
| 140 | const pipeline = createRenderPipeline(device, { |
| 141 | label: 'lineRenderer/pipeline', |
| 142 | bindGroupLayouts: [bindGroupLayout], |
| 143 | vertex: { |
| 144 | code: lineWgsl, |
| 145 | label: 'line.wgsl', |
| 146 | buffers: [ |
| 147 | { |
| 148 | arrayStride: 8, |
| 149 | stepMode: 'vertex', |
| 150 | attributes: [{ shaderLocation: 0, format: 'float32x2', offset: 0 }], |
| 151 | }, |
| 152 | ], |
| 153 | }, |
| 154 | fragment: { |
| 155 | code: lineWgsl, |
| 156 | label: 'line.wgsl', |
| 157 | formats: targetFormat, |
| 158 | // Enable standard alpha blending so per-series `lineStyle.opacity` behaves |
| 159 | // correctly against an opaque cleared background. |
| 160 | blend: { |
| 161 | color: { operation: 'add', srcFactor: 'src-alpha', dstFactor: 'one-minus-src-alpha' }, |
| 162 | alpha: { operation: 'add', srcFactor: 'one', dstFactor: 'one-minus-src-alpha' }, |
| 163 | }, |
| 164 | }, |
| 165 | primitive: { topology: 'line-strip', cullMode: 'none' }, |
| 166 | multisample: { count: 1 }, |
| 167 | }); |
| 168 | |
| 169 | let currentVertexBuffer: GPUBuffer | null = null; |
| 170 | let currentVertexCount = 0; |
no test coverage detected