resolvcharts 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +74 -31
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +42 -6
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +42 -6
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +74 -32
- package/dist/index.mjs.map +1 -1
- package/dist/resolvcharts.global.min.js +195 -25
- package/dist/resolvcharts.global.min.js.map +1 -1
- package/dist/series-PmAjztEh.cjs +1191 -0
- package/dist/series-PmAjztEh.cjs.map +1 -0
- package/dist/series-wyqYpkXm.mjs +1191 -0
- package/dist/series-wyqYpkXm.mjs.map +1 -0
- package/package.json +17 -14
- package/dist/series-BdprL87H.mjs +0 -479
- package/dist/series-BdprL87H.mjs.map +0 -1
- package/dist/series-J_5Z6dah.cjs +0 -479
- package/dist/series-J_5Z6dah.cjs.map +0 -1
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"series-BdprL87H.mjs","names":[],"sources":["../src/gpu/color.ts","../src/gpu/device.ts","../src/gpu/series.ts"],"sourcesContent":["/** Parse a CSS color (#rgb, #rrggbb, rgb(), rgba()) into linear-ish 0-1 rgba. */\nexport function parseColor(c: string): [number, number, number, number] {\n if (c.startsWith(\"#\")) {\n const h = c.slice(1);\n if (h.length === 3) {\n return [\n parseInt(h[0] as string, 16) / 15,\n parseInt(h[1] as string, 16) / 15,\n parseInt(h[2] as string, 16) / 15,\n 1,\n ];\n }\n if (h.length === 6) {\n return [\n parseInt(h.slice(0, 2), 16) / 255,\n parseInt(h.slice(2, 4), 16) / 255,\n parseInt(h.slice(4, 6), 16) / 255,\n 1,\n ];\n }\n }\n const m = /rgba?\\(([^)]+)\\)/.exec(c);\n if (m) {\n const parts = (m[1] as string).split(\",\").map((v) => Number.parseFloat(v));\n return [\n (parts[0] ?? 0) / 255,\n (parts[1] ?? 0) / 255,\n (parts[2] ?? 0) / 255,\n parts[3] ?? 1,\n ];\n }\n return [0, 0, 0, 1];\n}\n","export interface GpuRequestOptions {\n powerPreference?: \"default\" | \"low-power\" | \"high-performance\";\n /** use WebGPU compatibility mode (GLES 3.1 / D3D11 reach) */\n compat?: boolean;\n /** request \"timestamp-query\" when the adapter supports it */\n timing?: boolean;\n}\n\n/** Shared GPUDevice across charts — adapters/devices are expensive to acquire. */\nconst cache = new Map<string, Promise<GPUDevice | null>>();\n\nexport function getGpuDevice(\n opts: GpuRequestOptions = {},\n): Promise<GPUDevice | null> {\n const key = JSON.stringify(opts);\n let p = cache.get(key);\n if (!p) {\n p = (async (): Promise<GPUDevice | null> => {\n const nav = typeof navigator === \"undefined\" ? null : navigator;\n const gpu = (nav as Navigator | null)?.gpu;\n if (!gpu) return null;\n const req: GPURequestAdapterOptions = {};\n if (opts.powerPreference && opts.powerPreference !== \"default\") {\n req.powerPreference = opts.powerPreference;\n }\n if (opts.compat) {\n (req as { featureLevel?: \"compatibility\" }).featureLevel =\n \"compatibility\";\n }\n const adapter = await gpu.requestAdapter(req);\n if (!adapter) return null;\n const requiredFeatures: GPUFeatureName[] = [];\n if (opts.timing && adapter.features.has(\"timestamp-query\")) {\n requiredFeatures.push(\"timestamp-query\");\n }\n return adapter.requestDevice({ requiredFeatures });\n })();\n p.catch(() => cache.delete(key));\n cache.set(key, p);\n }\n return p;\n}\n","import type { Rect } from \"../core/types\";\nimport { parseColor } from \"./color\";\nimport { type GpuRequestOptions, getGpuDevice } from \"./device\";\n\n/**\n * WebGPU series renderer. Points arrive as interleaved [x, y] CSS-pixel pairs\n * (the same Float32Array the canvas path decimates into) uploaded as vertex\n * buffers; the GPU only rasterizes — instanced segment quads for lines, a\n * triangle strip to the baseline for areas, SDF circle sprites for scatter.\n *\n * Vertex-pulling via attributes is used everywhere (no vertex-stage storage\n * buffers), so the same pipelines work in WebGPU compatibility mode.\n */\n\nconst HEADER = /* wgsl */ `\nstruct U {\n res: vec4f, // canvas w, h (device px), dpr, unused\n color: vec4f,\n p: vec4f, // line: width | area: baseY, plotTop, plotH | points: radius\n};\n@group(0) @binding(0) var<uniform> u: U;\n\nfn toClip(p: vec2f) -> vec4f {\n let d = p * u.res.z;\n return vec4f(d.x / u.res.x * 2.0 - 1.0, 1.0 - d.y / u.res.y * 2.0, 0.0, 1.0);\n}\n`;\n\nconst LINE_WGSL = /* wgsl */ `\n${HEADER}\nconst OFF = array<vec2f, 6>(\n vec2f(0.0, -1.0), vec2f(0.0, 1.0), vec2f(1.0, -1.0),\n vec2f(0.0, 1.0), vec2f(1.0, 1.0), vec2f(1.0, -1.0),\n);\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) edge: f32,\n};\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) a: vec2f,\n @location(1) b: vec2f,\n) -> VOut {\n let v = OFF[vi];\n var dir = b - a;\n let len = length(dir);\n if (len < 1e-6) {\n dir = vec2f(1.0, 0.0);\n } else {\n dir = dir / len;\n }\n let nrm = vec2f(-dir.y, dir.x);\n let halfW = u.p.x * 0.5;\n let aa = 0.9;\n let p = mix(a, b, v.x) + nrm * v.y * (halfW + aa);\n var o: VOut;\n o.pos = toClip(p);\n o.edge = v.y * (halfW + aa);\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let halfW = u.p.x * 0.5;\n let a = 1.0 - smoothstep(halfW - 0.5, halfW + 0.9, abs(o.edge));\n return vec4f(u.color.rgb, u.color.a * a);\n}\n`;\n\nconst AREA_WGSL = /* wgsl */ `\n${HEADER}\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) grad: f32,\n};\n// triangle strip over a doubled buffer: buf[2k] and buf[2k+1] both hold\n// point k; even verts land on the path, odd verts drop to the baseline\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) top: vec2f,\n) -> VOut {\n let isTop = (vi & 1u) == 0u;\n let baseY = u.p.x;\n let y = select(baseY, top.y, isTop);\n var o: VOut;\n o.pos = toClip(vec2f(top.x, y));\n o.grad = clamp((top.y - u.p.y) / max(u.p.z, 1.0), 0.0, 1.0);\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let a = mix(0.16, 0.0, o.grad) * u.color.a;\n return vec4f(u.color.rgb, a);\n}\n`;\n\nconst POINTS_WGSL = /* wgsl */ `\n${HEADER}\nconst QUAD = array<vec2f, 6>(\n vec2f(-1.0, -1.0), vec2f(1.0, -1.0), vec2f(-1.0, 1.0),\n vec2f(-1.0, 1.0), vec2f(1.0, -1.0), vec2f(1.0, 1.0),\n);\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) local: vec2f,\n};\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) c: vec2f,\n) -> VOut {\n let r = u.p.x;\n let q = QUAD[vi];\n var o: VOut;\n o.pos = toClip(c + q * r);\n o.local = q * r;\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let r = u.p.x;\n let a = 1.0 - smoothstep(r - 1.2, r, length(o.local));\n return vec4f(u.color.rgb, u.color.a * a);\n}\n`;\n\nconst UNIFORM_SIZE = 64; // 4 x vec4f\nconst BLEND: GPUBlendState = {\n color: {\n srcFactor: \"src-alpha\",\n dstFactor: \"one-minus-src-alpha\",\n operation: \"add\",\n },\n alpha: {\n srcFactor: \"one\",\n dstFactor: \"one-minus-src-alpha\",\n operation: \"add\",\n },\n};\n\n// GPUBufferUsage flags (lib.dom has the types but not the const objects)\nconst BUF_VERTEX_DST = 0x28; // VERTEX | COPY_DST\nconst BUF_UNIFORM_DST = 0x48; // UNIFORM | COPY_DST\nconst BUF_RESOLVE_SRC = 0x204; // QUERY_RESOLVE | COPY_SRC\nconst BUF_MAPREAD_DST = 0x09; // MAP_READ | COPY_DST\nconst MAP_READ = 0x1;\n\nexport class GpuSeries {\n readonly canvas: HTMLCanvasElement;\n private device: GPUDevice;\n private ctx: GPUCanvasContext;\n private format: GPUTextureFormat;\n private pipes: {\n line: GPURenderPipeline;\n area: GPURenderPipeline;\n points: GPURenderPipeline;\n };\n private layout: GPUBindGroupLayout;\n private dpr = 1;\n private drawIdx = 0;\n private bufs: GPUBuffer[] = [];\n private encoder: GPUCommandEncoder | null = null;\n private pass: GPURenderPassEncoder | null = null;\n /** last measured GPU execution time in ms (when timing enabled) */\n gpuMs: number | null = null;\n private querySet: GPUQuerySet | null = null;\n private queryBuf: GPUBuffer | null = null;\n private readBuf: GPUBuffer | null = null;\n private reading = false;\n private areaScratch = new Float32Array(0);\n\n private constructor(\n device: GPUDevice,\n canvas: HTMLCanvasElement,\n timing: boolean,\n ) {\n this.device = device;\n if (timing && device.features.has(\"timestamp-query\")) {\n this.querySet = device.createQuerySet({ type: \"timestamp\", count: 2 });\n this.queryBuf = device.createBuffer({\n size: 16,\n usage: BUF_RESOLVE_SRC,\n });\n this.readBuf = device.createBuffer({\n size: 16,\n usage: BUF_MAPREAD_DST,\n });\n }\n this.canvas = canvas;\n canvas.style.cssText =\n \"position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none\";\n const ctx = canvas.getContext(\"webgpu\") as GPUCanvasContext | null;\n if (!ctx) throw new Error(\"resolvcharts: webgpu context unavailable\");\n this.ctx = ctx;\n this.format = navigator.gpu.getPreferredCanvasFormat();\n\n this.layout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n // GPUShaderStage.VERTEX | FRAGMENT\n visibility: 3,\n buffer: { type: \"uniform\" },\n },\n ],\n });\n const pl = device.createPipelineLayout({ bindGroupLayouts: [this.layout] });\n const mk = (\n code: string,\n topology: GPUPrimitiveTopology,\n buffers: GPUVertexBufferLayout[],\n ) =>\n device.createRenderPipeline({\n layout: pl,\n vertex: {\n module: device.createShaderModule({ code }),\n entryPoint: \"vs\",\n buffers,\n },\n fragment: {\n module: device.createShaderModule({ code }),\n entryPoint: \"fs\",\n targets: [{ format: this.format, blend: BLEND }],\n },\n primitive: { topology },\n });\n // line: same points buffer bound twice — slot 0 yields pts[i],\n // slot 1 (bound at +8 bytes) yields pts[i+1]\n const pairLayout: GPUVertexBufferLayout[] = [\n {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n },\n {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 1, offset: 0, format: \"float32x2\" }],\n },\n ];\n const ptLayout: GPUVertexBufferLayout = {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n };\n const areaLayout: GPUVertexBufferLayout = {\n arrayStride: 8,\n stepMode: \"vertex\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n };\n this.pipes = {\n line: mk(LINE_WGSL, \"triangle-list\", pairLayout),\n area: mk(AREA_WGSL, \"triangle-strip\", [areaLayout]),\n points: mk(POINTS_WGSL, \"triangle-list\", [ptLayout]),\n };\n }\n\n static async create(opts: GpuRequestOptions = {}): Promise<GpuSeries | null> {\n const device = await getGpuDevice(opts);\n if (!device) return null;\n const canvas = document.createElement(\"canvas\");\n try {\n const g = new GpuSeries(device, canvas, !!opts.timing);\n return g;\n } catch {\n return null;\n }\n }\n\n setSize(cssW: number, cssH: number, dpr: number): void {\n this.dpr = dpr;\n this.canvas.width = Math.max(1, Math.round(cssW * dpr));\n this.canvas.height = Math.max(1, Math.round(cssH * dpr));\n this.ctx.configure({\n device: this.device,\n format: this.format,\n alphaMode: \"premultiplied\",\n });\n }\n\n private bufferFor(idx: number, bytes: number): GPUBuffer {\n let b = this.bufs[idx];\n if (!b || b.size < bytes) {\n b?.destroy();\n b = this.device.createBuffer({\n size: Math.max(256, bytes),\n usage: BUF_VERTEX_DST,\n });\n this.bufs[idx] = b;\n }\n return b;\n }\n\n begin(plot: Rect): void {\n this.encoder = this.device.createCommandEncoder();\n const view = this.ctx.getCurrentTexture().createView();\n this.pass = this.encoder.beginRenderPass({\n colorAttachments: [\n {\n view,\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n ...(this.querySet\n ? {\n timestampWrites: {\n querySet: this.querySet,\n beginningOfPassWriteIndex: 0,\n endOfPassWriteIndex: 1,\n },\n }\n : {}),\n });\n const d = this.dpr;\n this.pass.setScissorRect(\n Math.max(0, Math.floor(plot.x * d)),\n Math.max(0, Math.floor(plot.y * d)),\n Math.max(1, Math.floor(plot.w * d)),\n Math.max(1, Math.floor(plot.h * d)),\n );\n this.drawIdx = 0;\n }\n\n private draw(\n pipe: GPURenderPipeline,\n vbufs: { buf: GPUBuffer; offset: number }[],\n color: string,\n alpha: number,\n params: [number, number, number],\n vertCount: number,\n instances: number,\n ): void {\n const pass = this.pass;\n if (!pass || instances <= 0) return;\n const [r, g, b, a] = parseColor(color);\n const udata = new Float32Array(16);\n udata.set([this.canvas.width, this.canvas.height, this.dpr, 0]);\n udata.set([r, g, b, a * alpha], 4);\n udata.set(params, 8);\n const ubuf = this.device.createBuffer({\n size: UNIFORM_SIZE,\n usage: BUF_UNIFORM_DST,\n });\n this.device.queue.writeBuffer(ubuf, 0, udata);\n\n const bind = this.device.createBindGroup({\n layout: this.layout,\n entries: [{ binding: 0, resource: { buffer: ubuf } }],\n });\n pass.setPipeline(pipe);\n pass.setBindGroup(0, bind);\n for (let i = 0; i < vbufs.length; i++) {\n const v = vbufs[i];\n if (v) pass.setVertexBuffer(i, v.buf, v.offset);\n }\n pass.draw(vertCount, instances);\n }\n\n line(pts: Float32Array, color: string, width = 2): void {\n const n = pts.length / 2;\n const idx = this.drawIdx++;\n const pbuf = this.bufferFor(idx, pts.byteLength);\n this.device.queue.writeBuffer(pbuf, 0, pts as Float32Array<ArrayBuffer>);\n this.draw(\n this.pipes.line,\n [\n { buf: pbuf, offset: 0 },\n { buf: pbuf, offset: 8 },\n ],\n color,\n 1,\n [width, 0, 0],\n 6,\n n - 1,\n );\n }\n\n area(pts: Float32Array, color: string, baseY: number, plot: Rect): void {\n const n = pts.length / 2;\n // double each point so vertex_index can pick top vs baseline by parity\n if (this.areaScratch.length < n * 4) {\n this.areaScratch = new Float32Array(n * 4);\n }\n const d = this.areaScratch;\n for (let i = 0; i < n; i++) {\n const x = pts[2 * i] as number;\n const y = pts[2 * i + 1] as number;\n const o = 4 * i;\n d[o] = x;\n d[o + 1] = y;\n d[o + 2] = x;\n d[o + 3] = y;\n }\n const out = d.subarray(0, n * 4);\n const idx = this.drawIdx++;\n const pbuf = this.bufferFor(idx, out.byteLength);\n this.device.queue.writeBuffer(pbuf, 0, out as Float32Array<ArrayBuffer>);\n this.draw(\n this.pipes.area,\n [{ buf: pbuf, offset: 0 }],\n color,\n 1,\n [baseY, plot.y, plot.h],\n n * 2,\n 1,\n );\n }\n\n points(pts: Float32Array, color: string, radius = 2.5, alpha = 0.65): void {\n const n = pts.length / 2;\n const idx = this.drawIdx++;\n const pbuf = this.bufferFor(idx, pts.byteLength);\n this.device.queue.writeBuffer(pbuf, 0, pts as Float32Array<ArrayBuffer>);\n this.draw(\n this.pipes.points,\n [{ buf: pbuf, offset: 0 }],\n color,\n alpha,\n [radius, 0, 0],\n 6,\n n,\n );\n }\n\n end(): void {\n if (!this.pass || !this.encoder) return;\n this.pass.end();\n const qs = this.querySet;\n const qb = this.queryBuf;\n const rb = this.readBuf;\n if (qs && qb && rb && !this.reading) {\n this.encoder.resolveQuerySet(qs, 0, 2, qb, 0);\n this.encoder.copyBufferToBuffer(qb, 0, rb, 0, 16);\n this.reading = true;\n this.device.queue.submit([this.encoder.finish()]);\n void rb.mapAsync(MAP_READ).then(() => {\n const v = new BigUint64Array(rb.getMappedRange());\n const t0 = v[0];\n const t1 = v[1];\n if (t0 !== undefined && t1 !== undefined) {\n this.gpuMs = Number(t1 - t0) / 1e6;\n }\n rb.unmap();\n this.reading = false;\n });\n } else {\n this.device.queue.submit([this.encoder.finish()]);\n }\n this.pass = null;\n this.encoder = null;\n }\n\n destroy(): void {\n for (const b of this.bufs) b.destroy();\n this.queryBuf?.destroy();\n this.readBuf?.destroy();\n this.querySet?.destroy();\n this.bufs = [];\n this.ctx.unconfigure();\n this.canvas.remove();\n }\n}\n"],"mappings":"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"}
|
package/dist/series-J_5Z6dah.cjs
DELETED
|
@@ -1,479 +0,0 @@
|
|
|
1
|
-
//#region src/gpu/color.ts
|
|
2
|
-
/** Parse a CSS color (#rgb, #rrggbb, rgb(), rgba()) into linear-ish 0-1 rgba. */
|
|
3
|
-
function parseColor(c) {
|
|
4
|
-
if (c.startsWith("#")) {
|
|
5
|
-
const h = c.slice(1);
|
|
6
|
-
if (h.length === 3) return [
|
|
7
|
-
parseInt(h[0], 16) / 15,
|
|
8
|
-
parseInt(h[1], 16) / 15,
|
|
9
|
-
parseInt(h[2], 16) / 15,
|
|
10
|
-
1
|
|
11
|
-
];
|
|
12
|
-
if (h.length === 6) return [
|
|
13
|
-
parseInt(h.slice(0, 2), 16) / 255,
|
|
14
|
-
parseInt(h.slice(2, 4), 16) / 255,
|
|
15
|
-
parseInt(h.slice(4, 6), 16) / 255,
|
|
16
|
-
1
|
|
17
|
-
];
|
|
18
|
-
}
|
|
19
|
-
const m = /rgba?\(([^)]+)\)/.exec(c);
|
|
20
|
-
if (m) {
|
|
21
|
-
const parts = m[1].split(",").map((v) => Number.parseFloat(v));
|
|
22
|
-
return [
|
|
23
|
-
(parts[0] ?? 0) / 255,
|
|
24
|
-
(parts[1] ?? 0) / 255,
|
|
25
|
-
(parts[2] ?? 0) / 255,
|
|
26
|
-
parts[3] ?? 1
|
|
27
|
-
];
|
|
28
|
-
}
|
|
29
|
-
return [
|
|
30
|
-
0,
|
|
31
|
-
0,
|
|
32
|
-
0,
|
|
33
|
-
1
|
|
34
|
-
];
|
|
35
|
-
}
|
|
36
|
-
//#endregion
|
|
37
|
-
//#region src/gpu/device.ts
|
|
38
|
-
/** Shared GPUDevice across charts — adapters/devices are expensive to acquire. */
|
|
39
|
-
const cache = /* @__PURE__ */ new Map();
|
|
40
|
-
function getGpuDevice(opts = {}) {
|
|
41
|
-
const key = JSON.stringify(opts);
|
|
42
|
-
let p = cache.get(key);
|
|
43
|
-
if (!p) {
|
|
44
|
-
p = (async () => {
|
|
45
|
-
const gpu = (typeof navigator === "undefined" ? null : navigator)?.gpu;
|
|
46
|
-
if (!gpu) return null;
|
|
47
|
-
const req = {};
|
|
48
|
-
if (opts.powerPreference && opts.powerPreference !== "default") req.powerPreference = opts.powerPreference;
|
|
49
|
-
if (opts.compat) req.featureLevel = "compatibility";
|
|
50
|
-
const adapter = await gpu.requestAdapter(req);
|
|
51
|
-
if (!adapter) return null;
|
|
52
|
-
const requiredFeatures = [];
|
|
53
|
-
if (opts.timing && adapter.features.has("timestamp-query")) requiredFeatures.push("timestamp-query");
|
|
54
|
-
return adapter.requestDevice({ requiredFeatures });
|
|
55
|
-
})();
|
|
56
|
-
p.catch(() => cache.delete(key));
|
|
57
|
-
cache.set(key, p);
|
|
58
|
-
}
|
|
59
|
-
return p;
|
|
60
|
-
}
|
|
61
|
-
//#endregion
|
|
62
|
-
//#region src/gpu/series.ts
|
|
63
|
-
/**
|
|
64
|
-
* WebGPU series renderer. Points arrive as interleaved [x, y] CSS-pixel pairs
|
|
65
|
-
* (the same Float32Array the canvas path decimates into) uploaded as vertex
|
|
66
|
-
* buffers; the GPU only rasterizes — instanced segment quads for lines, a
|
|
67
|
-
* triangle strip to the baseline for areas, SDF circle sprites for scatter.
|
|
68
|
-
*
|
|
69
|
-
* Vertex-pulling via attributes is used everywhere (no vertex-stage storage
|
|
70
|
-
* buffers), so the same pipelines work in WebGPU compatibility mode.
|
|
71
|
-
*/
|
|
72
|
-
const HEADER = `
|
|
73
|
-
struct U {
|
|
74
|
-
res: vec4f, // canvas w, h (device px), dpr, unused
|
|
75
|
-
color: vec4f,
|
|
76
|
-
p: vec4f, // line: width | area: baseY, plotTop, plotH | points: radius
|
|
77
|
-
};
|
|
78
|
-
@group(0) @binding(0) var<uniform> u: U;
|
|
79
|
-
|
|
80
|
-
fn toClip(p: vec2f) -> vec4f {
|
|
81
|
-
let d = p * u.res.z;
|
|
82
|
-
return vec4f(d.x / u.res.x * 2.0 - 1.0, 1.0 - d.y / u.res.y * 2.0, 0.0, 1.0);
|
|
83
|
-
}
|
|
84
|
-
`;
|
|
85
|
-
const LINE_WGSL = `
|
|
86
|
-
${HEADER}
|
|
87
|
-
const OFF = array<vec2f, 6>(
|
|
88
|
-
vec2f(0.0, -1.0), vec2f(0.0, 1.0), vec2f(1.0, -1.0),
|
|
89
|
-
vec2f(0.0, 1.0), vec2f(1.0, 1.0), vec2f(1.0, -1.0),
|
|
90
|
-
);
|
|
91
|
-
struct VOut {
|
|
92
|
-
@builtin(position) pos: vec4f,
|
|
93
|
-
@location(0) edge: f32,
|
|
94
|
-
};
|
|
95
|
-
@vertex fn vs(
|
|
96
|
-
@builtin(vertex_index) vi: u32,
|
|
97
|
-
@location(0) a: vec2f,
|
|
98
|
-
@location(1) b: vec2f,
|
|
99
|
-
) -> VOut {
|
|
100
|
-
let v = OFF[vi];
|
|
101
|
-
var dir = b - a;
|
|
102
|
-
let len = length(dir);
|
|
103
|
-
if (len < 1e-6) {
|
|
104
|
-
dir = vec2f(1.0, 0.0);
|
|
105
|
-
} else {
|
|
106
|
-
dir = dir / len;
|
|
107
|
-
}
|
|
108
|
-
let nrm = vec2f(-dir.y, dir.x);
|
|
109
|
-
let halfW = u.p.x * 0.5;
|
|
110
|
-
let aa = 0.9;
|
|
111
|
-
let p = mix(a, b, v.x) + nrm * v.y * (halfW + aa);
|
|
112
|
-
var o: VOut;
|
|
113
|
-
o.pos = toClip(p);
|
|
114
|
-
o.edge = v.y * (halfW + aa);
|
|
115
|
-
return o;
|
|
116
|
-
}
|
|
117
|
-
@fragment fn fs(o: VOut) -> @location(0) vec4f {
|
|
118
|
-
let halfW = u.p.x * 0.5;
|
|
119
|
-
let a = 1.0 - smoothstep(halfW - 0.5, halfW + 0.9, abs(o.edge));
|
|
120
|
-
return vec4f(u.color.rgb, u.color.a * a);
|
|
121
|
-
}
|
|
122
|
-
`;
|
|
123
|
-
const AREA_WGSL = `
|
|
124
|
-
${HEADER}
|
|
125
|
-
struct VOut {
|
|
126
|
-
@builtin(position) pos: vec4f,
|
|
127
|
-
@location(0) grad: f32,
|
|
128
|
-
};
|
|
129
|
-
// triangle strip over a doubled buffer: buf[2k] and buf[2k+1] both hold
|
|
130
|
-
// point k; even verts land on the path, odd verts drop to the baseline
|
|
131
|
-
@vertex fn vs(
|
|
132
|
-
@builtin(vertex_index) vi: u32,
|
|
133
|
-
@location(0) top: vec2f,
|
|
134
|
-
) -> VOut {
|
|
135
|
-
let isTop = (vi & 1u) == 0u;
|
|
136
|
-
let baseY = u.p.x;
|
|
137
|
-
let y = select(baseY, top.y, isTop);
|
|
138
|
-
var o: VOut;
|
|
139
|
-
o.pos = toClip(vec2f(top.x, y));
|
|
140
|
-
o.grad = clamp((top.y - u.p.y) / max(u.p.z, 1.0), 0.0, 1.0);
|
|
141
|
-
return o;
|
|
142
|
-
}
|
|
143
|
-
@fragment fn fs(o: VOut) -> @location(0) vec4f {
|
|
144
|
-
let a = mix(0.16, 0.0, o.grad) * u.color.a;
|
|
145
|
-
return vec4f(u.color.rgb, a);
|
|
146
|
-
}
|
|
147
|
-
`;
|
|
148
|
-
const POINTS_WGSL = `
|
|
149
|
-
${HEADER}
|
|
150
|
-
const QUAD = array<vec2f, 6>(
|
|
151
|
-
vec2f(-1.0, -1.0), vec2f(1.0, -1.0), vec2f(-1.0, 1.0),
|
|
152
|
-
vec2f(-1.0, 1.0), vec2f(1.0, -1.0), vec2f(1.0, 1.0),
|
|
153
|
-
);
|
|
154
|
-
struct VOut {
|
|
155
|
-
@builtin(position) pos: vec4f,
|
|
156
|
-
@location(0) local: vec2f,
|
|
157
|
-
};
|
|
158
|
-
@vertex fn vs(
|
|
159
|
-
@builtin(vertex_index) vi: u32,
|
|
160
|
-
@location(0) c: vec2f,
|
|
161
|
-
) -> VOut {
|
|
162
|
-
let r = u.p.x;
|
|
163
|
-
let q = QUAD[vi];
|
|
164
|
-
var o: VOut;
|
|
165
|
-
o.pos = toClip(c + q * r);
|
|
166
|
-
o.local = q * r;
|
|
167
|
-
return o;
|
|
168
|
-
}
|
|
169
|
-
@fragment fn fs(o: VOut) -> @location(0) vec4f {
|
|
170
|
-
let r = u.p.x;
|
|
171
|
-
let a = 1.0 - smoothstep(r - 1.2, r, length(o.local));
|
|
172
|
-
return vec4f(u.color.rgb, u.color.a * a);
|
|
173
|
-
}
|
|
174
|
-
`;
|
|
175
|
-
const UNIFORM_SIZE = 64;
|
|
176
|
-
const BLEND = {
|
|
177
|
-
color: {
|
|
178
|
-
srcFactor: "src-alpha",
|
|
179
|
-
dstFactor: "one-minus-src-alpha",
|
|
180
|
-
operation: "add"
|
|
181
|
-
},
|
|
182
|
-
alpha: {
|
|
183
|
-
srcFactor: "one",
|
|
184
|
-
dstFactor: "one-minus-src-alpha",
|
|
185
|
-
operation: "add"
|
|
186
|
-
}
|
|
187
|
-
};
|
|
188
|
-
const BUF_VERTEX_DST = 40;
|
|
189
|
-
const BUF_UNIFORM_DST = 72;
|
|
190
|
-
const BUF_RESOLVE_SRC = 516;
|
|
191
|
-
const BUF_MAPREAD_DST = 9;
|
|
192
|
-
const MAP_READ = 1;
|
|
193
|
-
var GpuSeries = class GpuSeries {
|
|
194
|
-
constructor(device, canvas, timing) {
|
|
195
|
-
this.dpr = 1;
|
|
196
|
-
this.drawIdx = 0;
|
|
197
|
-
this.bufs = [];
|
|
198
|
-
this.encoder = null;
|
|
199
|
-
this.pass = null;
|
|
200
|
-
this.gpuMs = null;
|
|
201
|
-
this.querySet = null;
|
|
202
|
-
this.queryBuf = null;
|
|
203
|
-
this.readBuf = null;
|
|
204
|
-
this.reading = false;
|
|
205
|
-
this.areaScratch = /* @__PURE__ */ new Float32Array(0);
|
|
206
|
-
this.device = device;
|
|
207
|
-
if (timing && device.features.has("timestamp-query")) {
|
|
208
|
-
this.querySet = device.createQuerySet({
|
|
209
|
-
type: "timestamp",
|
|
210
|
-
count: 2
|
|
211
|
-
});
|
|
212
|
-
this.queryBuf = device.createBuffer({
|
|
213
|
-
size: 16,
|
|
214
|
-
usage: BUF_RESOLVE_SRC
|
|
215
|
-
});
|
|
216
|
-
this.readBuf = device.createBuffer({
|
|
217
|
-
size: 16,
|
|
218
|
-
usage: BUF_MAPREAD_DST
|
|
219
|
-
});
|
|
220
|
-
}
|
|
221
|
-
this.canvas = canvas;
|
|
222
|
-
canvas.style.cssText = "position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none";
|
|
223
|
-
const ctx = canvas.getContext("webgpu");
|
|
224
|
-
if (!ctx) throw new Error("resolvcharts: webgpu context unavailable");
|
|
225
|
-
this.ctx = ctx;
|
|
226
|
-
this.format = navigator.gpu.getPreferredCanvasFormat();
|
|
227
|
-
this.layout = device.createBindGroupLayout({ entries: [{
|
|
228
|
-
binding: 0,
|
|
229
|
-
visibility: 3,
|
|
230
|
-
buffer: { type: "uniform" }
|
|
231
|
-
}] });
|
|
232
|
-
const pl = device.createPipelineLayout({ bindGroupLayouts: [this.layout] });
|
|
233
|
-
const mk = (code, topology, buffers) => device.createRenderPipeline({
|
|
234
|
-
layout: pl,
|
|
235
|
-
vertex: {
|
|
236
|
-
module: device.createShaderModule({ code }),
|
|
237
|
-
entryPoint: "vs",
|
|
238
|
-
buffers
|
|
239
|
-
},
|
|
240
|
-
fragment: {
|
|
241
|
-
module: device.createShaderModule({ code }),
|
|
242
|
-
entryPoint: "fs",
|
|
243
|
-
targets: [{
|
|
244
|
-
format: this.format,
|
|
245
|
-
blend: BLEND
|
|
246
|
-
}]
|
|
247
|
-
},
|
|
248
|
-
primitive: { topology }
|
|
249
|
-
});
|
|
250
|
-
const pairLayout = [{
|
|
251
|
-
arrayStride: 8,
|
|
252
|
-
stepMode: "instance",
|
|
253
|
-
attributes: [{
|
|
254
|
-
shaderLocation: 0,
|
|
255
|
-
offset: 0,
|
|
256
|
-
format: "float32x2"
|
|
257
|
-
}]
|
|
258
|
-
}, {
|
|
259
|
-
arrayStride: 8,
|
|
260
|
-
stepMode: "instance",
|
|
261
|
-
attributes: [{
|
|
262
|
-
shaderLocation: 1,
|
|
263
|
-
offset: 0,
|
|
264
|
-
format: "float32x2"
|
|
265
|
-
}]
|
|
266
|
-
}];
|
|
267
|
-
const ptLayout = {
|
|
268
|
-
arrayStride: 8,
|
|
269
|
-
stepMode: "instance",
|
|
270
|
-
attributes: [{
|
|
271
|
-
shaderLocation: 0,
|
|
272
|
-
offset: 0,
|
|
273
|
-
format: "float32x2"
|
|
274
|
-
}]
|
|
275
|
-
};
|
|
276
|
-
const areaLayout = {
|
|
277
|
-
arrayStride: 8,
|
|
278
|
-
stepMode: "vertex",
|
|
279
|
-
attributes: [{
|
|
280
|
-
shaderLocation: 0,
|
|
281
|
-
offset: 0,
|
|
282
|
-
format: "float32x2"
|
|
283
|
-
}]
|
|
284
|
-
};
|
|
285
|
-
this.pipes = {
|
|
286
|
-
line: mk(LINE_WGSL, "triangle-list", pairLayout),
|
|
287
|
-
area: mk(AREA_WGSL, "triangle-strip", [areaLayout]),
|
|
288
|
-
points: mk(POINTS_WGSL, "triangle-list", [ptLayout])
|
|
289
|
-
};
|
|
290
|
-
}
|
|
291
|
-
static async create(opts = {}) {
|
|
292
|
-
const device = await getGpuDevice(opts);
|
|
293
|
-
if (!device) return null;
|
|
294
|
-
const canvas = document.createElement("canvas");
|
|
295
|
-
try {
|
|
296
|
-
return new GpuSeries(device, canvas, !!opts.timing);
|
|
297
|
-
} catch {
|
|
298
|
-
return null;
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
setSize(cssW, cssH, dpr) {
|
|
302
|
-
this.dpr = dpr;
|
|
303
|
-
this.canvas.width = Math.max(1, Math.round(cssW * dpr));
|
|
304
|
-
this.canvas.height = Math.max(1, Math.round(cssH * dpr));
|
|
305
|
-
this.ctx.configure({
|
|
306
|
-
device: this.device,
|
|
307
|
-
format: this.format,
|
|
308
|
-
alphaMode: "premultiplied"
|
|
309
|
-
});
|
|
310
|
-
}
|
|
311
|
-
bufferFor(idx, bytes) {
|
|
312
|
-
let b = this.bufs[idx];
|
|
313
|
-
if (!b || b.size < bytes) {
|
|
314
|
-
b?.destroy();
|
|
315
|
-
b = this.device.createBuffer({
|
|
316
|
-
size: Math.max(256, bytes),
|
|
317
|
-
usage: BUF_VERTEX_DST
|
|
318
|
-
});
|
|
319
|
-
this.bufs[idx] = b;
|
|
320
|
-
}
|
|
321
|
-
return b;
|
|
322
|
-
}
|
|
323
|
-
begin(plot) {
|
|
324
|
-
this.encoder = this.device.createCommandEncoder();
|
|
325
|
-
const view = this.ctx.getCurrentTexture().createView();
|
|
326
|
-
this.pass = this.encoder.beginRenderPass({
|
|
327
|
-
colorAttachments: [{
|
|
328
|
-
view,
|
|
329
|
-
loadOp: "clear",
|
|
330
|
-
storeOp: "store",
|
|
331
|
-
clearValue: {
|
|
332
|
-
r: 0,
|
|
333
|
-
g: 0,
|
|
334
|
-
b: 0,
|
|
335
|
-
a: 0
|
|
336
|
-
}
|
|
337
|
-
}],
|
|
338
|
-
...this.querySet ? { timestampWrites: {
|
|
339
|
-
querySet: this.querySet,
|
|
340
|
-
beginningOfPassWriteIndex: 0,
|
|
341
|
-
endOfPassWriteIndex: 1
|
|
342
|
-
} } : {}
|
|
343
|
-
});
|
|
344
|
-
const d = this.dpr;
|
|
345
|
-
this.pass.setScissorRect(Math.max(0, Math.floor(plot.x * d)), Math.max(0, Math.floor(plot.y * d)), Math.max(1, Math.floor(plot.w * d)), Math.max(1, Math.floor(plot.h * d)));
|
|
346
|
-
this.drawIdx = 0;
|
|
347
|
-
}
|
|
348
|
-
draw(pipe, vbufs, color, alpha, params, vertCount, instances) {
|
|
349
|
-
const pass = this.pass;
|
|
350
|
-
if (!pass || instances <= 0) return;
|
|
351
|
-
const [r, g, b, a] = parseColor(color);
|
|
352
|
-
const udata = /* @__PURE__ */ new Float32Array(16);
|
|
353
|
-
udata.set([
|
|
354
|
-
this.canvas.width,
|
|
355
|
-
this.canvas.height,
|
|
356
|
-
this.dpr,
|
|
357
|
-
0
|
|
358
|
-
]);
|
|
359
|
-
udata.set([
|
|
360
|
-
r,
|
|
361
|
-
g,
|
|
362
|
-
b,
|
|
363
|
-
a * alpha
|
|
364
|
-
], 4);
|
|
365
|
-
udata.set(params, 8);
|
|
366
|
-
const ubuf = this.device.createBuffer({
|
|
367
|
-
size: UNIFORM_SIZE,
|
|
368
|
-
usage: BUF_UNIFORM_DST
|
|
369
|
-
});
|
|
370
|
-
this.device.queue.writeBuffer(ubuf, 0, udata);
|
|
371
|
-
const bind = this.device.createBindGroup({
|
|
372
|
-
layout: this.layout,
|
|
373
|
-
entries: [{
|
|
374
|
-
binding: 0,
|
|
375
|
-
resource: { buffer: ubuf }
|
|
376
|
-
}]
|
|
377
|
-
});
|
|
378
|
-
pass.setPipeline(pipe);
|
|
379
|
-
pass.setBindGroup(0, bind);
|
|
380
|
-
for (let i = 0; i < vbufs.length; i++) {
|
|
381
|
-
const v = vbufs[i];
|
|
382
|
-
if (v) pass.setVertexBuffer(i, v.buf, v.offset);
|
|
383
|
-
}
|
|
384
|
-
pass.draw(vertCount, instances);
|
|
385
|
-
}
|
|
386
|
-
line(pts, color, width = 2) {
|
|
387
|
-
const n = pts.length / 2;
|
|
388
|
-
const idx = this.drawIdx++;
|
|
389
|
-
const pbuf = this.bufferFor(idx, pts.byteLength);
|
|
390
|
-
this.device.queue.writeBuffer(pbuf, 0, pts);
|
|
391
|
-
this.draw(this.pipes.line, [{
|
|
392
|
-
buf: pbuf,
|
|
393
|
-
offset: 0
|
|
394
|
-
}, {
|
|
395
|
-
buf: pbuf,
|
|
396
|
-
offset: 8
|
|
397
|
-
}], color, 1, [
|
|
398
|
-
width,
|
|
399
|
-
0,
|
|
400
|
-
0
|
|
401
|
-
], 6, n - 1);
|
|
402
|
-
}
|
|
403
|
-
area(pts, color, baseY, plot) {
|
|
404
|
-
const n = pts.length / 2;
|
|
405
|
-
if (this.areaScratch.length < n * 4) this.areaScratch = new Float32Array(n * 4);
|
|
406
|
-
const d = this.areaScratch;
|
|
407
|
-
for (let i = 0; i < n; i++) {
|
|
408
|
-
const x = pts[2 * i];
|
|
409
|
-
const y = pts[2 * i + 1];
|
|
410
|
-
const o = 4 * i;
|
|
411
|
-
d[o] = x;
|
|
412
|
-
d[o + 1] = y;
|
|
413
|
-
d[o + 2] = x;
|
|
414
|
-
d[o + 3] = y;
|
|
415
|
-
}
|
|
416
|
-
const out = d.subarray(0, n * 4);
|
|
417
|
-
const idx = this.drawIdx++;
|
|
418
|
-
const pbuf = this.bufferFor(idx, out.byteLength);
|
|
419
|
-
this.device.queue.writeBuffer(pbuf, 0, out);
|
|
420
|
-
this.draw(this.pipes.area, [{
|
|
421
|
-
buf: pbuf,
|
|
422
|
-
offset: 0
|
|
423
|
-
}], color, 1, [
|
|
424
|
-
baseY,
|
|
425
|
-
plot.y,
|
|
426
|
-
plot.h
|
|
427
|
-
], n * 2, 1);
|
|
428
|
-
}
|
|
429
|
-
points(pts, color, radius = 2.5, alpha = .65) {
|
|
430
|
-
const n = pts.length / 2;
|
|
431
|
-
const idx = this.drawIdx++;
|
|
432
|
-
const pbuf = this.bufferFor(idx, pts.byteLength);
|
|
433
|
-
this.device.queue.writeBuffer(pbuf, 0, pts);
|
|
434
|
-
this.draw(this.pipes.points, [{
|
|
435
|
-
buf: pbuf,
|
|
436
|
-
offset: 0
|
|
437
|
-
}], color, alpha, [
|
|
438
|
-
radius,
|
|
439
|
-
0,
|
|
440
|
-
0
|
|
441
|
-
], 6, n);
|
|
442
|
-
}
|
|
443
|
-
end() {
|
|
444
|
-
if (!this.pass || !this.encoder) return;
|
|
445
|
-
this.pass.end();
|
|
446
|
-
const qs = this.querySet;
|
|
447
|
-
const qb = this.queryBuf;
|
|
448
|
-
const rb = this.readBuf;
|
|
449
|
-
if (qs && qb && rb && !this.reading) {
|
|
450
|
-
this.encoder.resolveQuerySet(qs, 0, 2, qb, 0);
|
|
451
|
-
this.encoder.copyBufferToBuffer(qb, 0, rb, 0, 16);
|
|
452
|
-
this.reading = true;
|
|
453
|
-
this.device.queue.submit([this.encoder.finish()]);
|
|
454
|
-
rb.mapAsync(MAP_READ).then(() => {
|
|
455
|
-
const v = new BigUint64Array(rb.getMappedRange());
|
|
456
|
-
const t0 = v[0];
|
|
457
|
-
const t1 = v[1];
|
|
458
|
-
if (t0 !== void 0 && t1 !== void 0) this.gpuMs = Number(t1 - t0) / 1e6;
|
|
459
|
-
rb.unmap();
|
|
460
|
-
this.reading = false;
|
|
461
|
-
});
|
|
462
|
-
} else this.device.queue.submit([this.encoder.finish()]);
|
|
463
|
-
this.pass = null;
|
|
464
|
-
this.encoder = null;
|
|
465
|
-
}
|
|
466
|
-
destroy() {
|
|
467
|
-
for (const b of this.bufs) b.destroy();
|
|
468
|
-
this.queryBuf?.destroy();
|
|
469
|
-
this.readBuf?.destroy();
|
|
470
|
-
this.querySet?.destroy();
|
|
471
|
-
this.bufs = [];
|
|
472
|
-
this.ctx.unconfigure();
|
|
473
|
-
this.canvas.remove();
|
|
474
|
-
}
|
|
475
|
-
};
|
|
476
|
-
//#endregion
|
|
477
|
-
exports.GpuSeries = GpuSeries;
|
|
478
|
-
|
|
479
|
-
//# sourceMappingURL=series-J_5Z6dah.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"series-J_5Z6dah.cjs","names":[],"sources":["../src/gpu/color.ts","../src/gpu/device.ts","../src/gpu/series.ts"],"sourcesContent":["/** Parse a CSS color (#rgb, #rrggbb, rgb(), rgba()) into linear-ish 0-1 rgba. */\nexport function parseColor(c: string): [number, number, number, number] {\n if (c.startsWith(\"#\")) {\n const h = c.slice(1);\n if (h.length === 3) {\n return [\n parseInt(h[0] as string, 16) / 15,\n parseInt(h[1] as string, 16) / 15,\n parseInt(h[2] as string, 16) / 15,\n 1,\n ];\n }\n if (h.length === 6) {\n return [\n parseInt(h.slice(0, 2), 16) / 255,\n parseInt(h.slice(2, 4), 16) / 255,\n parseInt(h.slice(4, 6), 16) / 255,\n 1,\n ];\n }\n }\n const m = /rgba?\\(([^)]+)\\)/.exec(c);\n if (m) {\n const parts = (m[1] as string).split(\",\").map((v) => Number.parseFloat(v));\n return [\n (parts[0] ?? 0) / 255,\n (parts[1] ?? 0) / 255,\n (parts[2] ?? 0) / 255,\n parts[3] ?? 1,\n ];\n }\n return [0, 0, 0, 1];\n}\n","export interface GpuRequestOptions {\n powerPreference?: \"default\" | \"low-power\" | \"high-performance\";\n /** use WebGPU compatibility mode (GLES 3.1 / D3D11 reach) */\n compat?: boolean;\n /** request \"timestamp-query\" when the adapter supports it */\n timing?: boolean;\n}\n\n/** Shared GPUDevice across charts — adapters/devices are expensive to acquire. */\nconst cache = new Map<string, Promise<GPUDevice | null>>();\n\nexport function getGpuDevice(\n opts: GpuRequestOptions = {},\n): Promise<GPUDevice | null> {\n const key = JSON.stringify(opts);\n let p = cache.get(key);\n if (!p) {\n p = (async (): Promise<GPUDevice | null> => {\n const nav = typeof navigator === \"undefined\" ? null : navigator;\n const gpu = (nav as Navigator | null)?.gpu;\n if (!gpu) return null;\n const req: GPURequestAdapterOptions = {};\n if (opts.powerPreference && opts.powerPreference !== \"default\") {\n req.powerPreference = opts.powerPreference;\n }\n if (opts.compat) {\n (req as { featureLevel?: \"compatibility\" }).featureLevel =\n \"compatibility\";\n }\n const adapter = await gpu.requestAdapter(req);\n if (!adapter) return null;\n const requiredFeatures: GPUFeatureName[] = [];\n if (opts.timing && adapter.features.has(\"timestamp-query\")) {\n requiredFeatures.push(\"timestamp-query\");\n }\n return adapter.requestDevice({ requiredFeatures });\n })();\n p.catch(() => cache.delete(key));\n cache.set(key, p);\n }\n return p;\n}\n","import type { Rect } from \"../core/types\";\nimport { parseColor } from \"./color\";\nimport { type GpuRequestOptions, getGpuDevice } from \"./device\";\n\n/**\n * WebGPU series renderer. Points arrive as interleaved [x, y] CSS-pixel pairs\n * (the same Float32Array the canvas path decimates into) uploaded as vertex\n * buffers; the GPU only rasterizes — instanced segment quads for lines, a\n * triangle strip to the baseline for areas, SDF circle sprites for scatter.\n *\n * Vertex-pulling via attributes is used everywhere (no vertex-stage storage\n * buffers), so the same pipelines work in WebGPU compatibility mode.\n */\n\nconst HEADER = /* wgsl */ `\nstruct U {\n res: vec4f, // canvas w, h (device px), dpr, unused\n color: vec4f,\n p: vec4f, // line: width | area: baseY, plotTop, plotH | points: radius\n};\n@group(0) @binding(0) var<uniform> u: U;\n\nfn toClip(p: vec2f) -> vec4f {\n let d = p * u.res.z;\n return vec4f(d.x / u.res.x * 2.0 - 1.0, 1.0 - d.y / u.res.y * 2.0, 0.0, 1.0);\n}\n`;\n\nconst LINE_WGSL = /* wgsl */ `\n${HEADER}\nconst OFF = array<vec2f, 6>(\n vec2f(0.0, -1.0), vec2f(0.0, 1.0), vec2f(1.0, -1.0),\n vec2f(0.0, 1.0), vec2f(1.0, 1.0), vec2f(1.0, -1.0),\n);\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) edge: f32,\n};\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) a: vec2f,\n @location(1) b: vec2f,\n) -> VOut {\n let v = OFF[vi];\n var dir = b - a;\n let len = length(dir);\n if (len < 1e-6) {\n dir = vec2f(1.0, 0.0);\n } else {\n dir = dir / len;\n }\n let nrm = vec2f(-dir.y, dir.x);\n let halfW = u.p.x * 0.5;\n let aa = 0.9;\n let p = mix(a, b, v.x) + nrm * v.y * (halfW + aa);\n var o: VOut;\n o.pos = toClip(p);\n o.edge = v.y * (halfW + aa);\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let halfW = u.p.x * 0.5;\n let a = 1.0 - smoothstep(halfW - 0.5, halfW + 0.9, abs(o.edge));\n return vec4f(u.color.rgb, u.color.a * a);\n}\n`;\n\nconst AREA_WGSL = /* wgsl */ `\n${HEADER}\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) grad: f32,\n};\n// triangle strip over a doubled buffer: buf[2k] and buf[2k+1] both hold\n// point k; even verts land on the path, odd verts drop to the baseline\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) top: vec2f,\n) -> VOut {\n let isTop = (vi & 1u) == 0u;\n let baseY = u.p.x;\n let y = select(baseY, top.y, isTop);\n var o: VOut;\n o.pos = toClip(vec2f(top.x, y));\n o.grad = clamp((top.y - u.p.y) / max(u.p.z, 1.0), 0.0, 1.0);\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let a = mix(0.16, 0.0, o.grad) * u.color.a;\n return vec4f(u.color.rgb, a);\n}\n`;\n\nconst POINTS_WGSL = /* wgsl */ `\n${HEADER}\nconst QUAD = array<vec2f, 6>(\n vec2f(-1.0, -1.0), vec2f(1.0, -1.0), vec2f(-1.0, 1.0),\n vec2f(-1.0, 1.0), vec2f(1.0, -1.0), vec2f(1.0, 1.0),\n);\nstruct VOut {\n @builtin(position) pos: vec4f,\n @location(0) local: vec2f,\n};\n@vertex fn vs(\n @builtin(vertex_index) vi: u32,\n @location(0) c: vec2f,\n) -> VOut {\n let r = u.p.x;\n let q = QUAD[vi];\n var o: VOut;\n o.pos = toClip(c + q * r);\n o.local = q * r;\n return o;\n}\n@fragment fn fs(o: VOut) -> @location(0) vec4f {\n let r = u.p.x;\n let a = 1.0 - smoothstep(r - 1.2, r, length(o.local));\n return vec4f(u.color.rgb, u.color.a * a);\n}\n`;\n\nconst UNIFORM_SIZE = 64; // 4 x vec4f\nconst BLEND: GPUBlendState = {\n color: {\n srcFactor: \"src-alpha\",\n dstFactor: \"one-minus-src-alpha\",\n operation: \"add\",\n },\n alpha: {\n srcFactor: \"one\",\n dstFactor: \"one-minus-src-alpha\",\n operation: \"add\",\n },\n};\n\n// GPUBufferUsage flags (lib.dom has the types but not the const objects)\nconst BUF_VERTEX_DST = 0x28; // VERTEX | COPY_DST\nconst BUF_UNIFORM_DST = 0x48; // UNIFORM | COPY_DST\nconst BUF_RESOLVE_SRC = 0x204; // QUERY_RESOLVE | COPY_SRC\nconst BUF_MAPREAD_DST = 0x09; // MAP_READ | COPY_DST\nconst MAP_READ = 0x1;\n\nexport class GpuSeries {\n readonly canvas: HTMLCanvasElement;\n private device: GPUDevice;\n private ctx: GPUCanvasContext;\n private format: GPUTextureFormat;\n private pipes: {\n line: GPURenderPipeline;\n area: GPURenderPipeline;\n points: GPURenderPipeline;\n };\n private layout: GPUBindGroupLayout;\n private dpr = 1;\n private drawIdx = 0;\n private bufs: GPUBuffer[] = [];\n private encoder: GPUCommandEncoder | null = null;\n private pass: GPURenderPassEncoder | null = null;\n /** last measured GPU execution time in ms (when timing enabled) */\n gpuMs: number | null = null;\n private querySet: GPUQuerySet | null = null;\n private queryBuf: GPUBuffer | null = null;\n private readBuf: GPUBuffer | null = null;\n private reading = false;\n private areaScratch = new Float32Array(0);\n\n private constructor(\n device: GPUDevice,\n canvas: HTMLCanvasElement,\n timing: boolean,\n ) {\n this.device = device;\n if (timing && device.features.has(\"timestamp-query\")) {\n this.querySet = device.createQuerySet({ type: \"timestamp\", count: 2 });\n this.queryBuf = device.createBuffer({\n size: 16,\n usage: BUF_RESOLVE_SRC,\n });\n this.readBuf = device.createBuffer({\n size: 16,\n usage: BUF_MAPREAD_DST,\n });\n }\n this.canvas = canvas;\n canvas.style.cssText =\n \"position:absolute;inset:0;width:100%;height:100%;display:block;pointer-events:none\";\n const ctx = canvas.getContext(\"webgpu\") as GPUCanvasContext | null;\n if (!ctx) throw new Error(\"resolvcharts: webgpu context unavailable\");\n this.ctx = ctx;\n this.format = navigator.gpu.getPreferredCanvasFormat();\n\n this.layout = device.createBindGroupLayout({\n entries: [\n {\n binding: 0,\n // GPUShaderStage.VERTEX | FRAGMENT\n visibility: 3,\n buffer: { type: \"uniform\" },\n },\n ],\n });\n const pl = device.createPipelineLayout({ bindGroupLayouts: [this.layout] });\n const mk = (\n code: string,\n topology: GPUPrimitiveTopology,\n buffers: GPUVertexBufferLayout[],\n ) =>\n device.createRenderPipeline({\n layout: pl,\n vertex: {\n module: device.createShaderModule({ code }),\n entryPoint: \"vs\",\n buffers,\n },\n fragment: {\n module: device.createShaderModule({ code }),\n entryPoint: \"fs\",\n targets: [{ format: this.format, blend: BLEND }],\n },\n primitive: { topology },\n });\n // line: same points buffer bound twice — slot 0 yields pts[i],\n // slot 1 (bound at +8 bytes) yields pts[i+1]\n const pairLayout: GPUVertexBufferLayout[] = [\n {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n },\n {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 1, offset: 0, format: \"float32x2\" }],\n },\n ];\n const ptLayout: GPUVertexBufferLayout = {\n arrayStride: 8,\n stepMode: \"instance\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n };\n const areaLayout: GPUVertexBufferLayout = {\n arrayStride: 8,\n stepMode: \"vertex\",\n attributes: [{ shaderLocation: 0, offset: 0, format: \"float32x2\" }],\n };\n this.pipes = {\n line: mk(LINE_WGSL, \"triangle-list\", pairLayout),\n area: mk(AREA_WGSL, \"triangle-strip\", [areaLayout]),\n points: mk(POINTS_WGSL, \"triangle-list\", [ptLayout]),\n };\n }\n\n static async create(opts: GpuRequestOptions = {}): Promise<GpuSeries | null> {\n const device = await getGpuDevice(opts);\n if (!device) return null;\n const canvas = document.createElement(\"canvas\");\n try {\n const g = new GpuSeries(device, canvas, !!opts.timing);\n return g;\n } catch {\n return null;\n }\n }\n\n setSize(cssW: number, cssH: number, dpr: number): void {\n this.dpr = dpr;\n this.canvas.width = Math.max(1, Math.round(cssW * dpr));\n this.canvas.height = Math.max(1, Math.round(cssH * dpr));\n this.ctx.configure({\n device: this.device,\n format: this.format,\n alphaMode: \"premultiplied\",\n });\n }\n\n private bufferFor(idx: number, bytes: number): GPUBuffer {\n let b = this.bufs[idx];\n if (!b || b.size < bytes) {\n b?.destroy();\n b = this.device.createBuffer({\n size: Math.max(256, bytes),\n usage: BUF_VERTEX_DST,\n });\n this.bufs[idx] = b;\n }\n return b;\n }\n\n begin(plot: Rect): void {\n this.encoder = this.device.createCommandEncoder();\n const view = this.ctx.getCurrentTexture().createView();\n this.pass = this.encoder.beginRenderPass({\n colorAttachments: [\n {\n view,\n loadOp: \"clear\",\n storeOp: \"store\",\n clearValue: { r: 0, g: 0, b: 0, a: 0 },\n },\n ],\n ...(this.querySet\n ? {\n timestampWrites: {\n querySet: this.querySet,\n beginningOfPassWriteIndex: 0,\n endOfPassWriteIndex: 1,\n },\n }\n : {}),\n });\n const d = this.dpr;\n this.pass.setScissorRect(\n Math.max(0, Math.floor(plot.x * d)),\n Math.max(0, Math.floor(plot.y * d)),\n Math.max(1, Math.floor(plot.w * d)),\n Math.max(1, Math.floor(plot.h * d)),\n );\n this.drawIdx = 0;\n }\n\n private draw(\n pipe: GPURenderPipeline,\n vbufs: { buf: GPUBuffer; offset: number }[],\n color: string,\n alpha: number,\n params: [number, number, number],\n vertCount: number,\n instances: number,\n ): void {\n const pass = this.pass;\n if (!pass || instances <= 0) return;\n const [r, g, b, a] = parseColor(color);\n const udata = new Float32Array(16);\n udata.set([this.canvas.width, this.canvas.height, this.dpr, 0]);\n udata.set([r, g, b, a * alpha], 4);\n udata.set(params, 8);\n const ubuf = this.device.createBuffer({\n size: UNIFORM_SIZE,\n usage: BUF_UNIFORM_DST,\n });\n this.device.queue.writeBuffer(ubuf, 0, udata);\n\n const bind = this.device.createBindGroup({\n layout: this.layout,\n entries: [{ binding: 0, resource: { buffer: ubuf } }],\n });\n pass.setPipeline(pipe);\n pass.setBindGroup(0, bind);\n for (let i = 0; i < vbufs.length; i++) {\n const v = vbufs[i];\n if (v) pass.setVertexBuffer(i, v.buf, v.offset);\n }\n pass.draw(vertCount, instances);\n }\n\n line(pts: Float32Array, color: string, width = 2): void {\n const n = pts.length / 2;\n const idx = this.drawIdx++;\n const pbuf = this.bufferFor(idx, pts.byteLength);\n this.device.queue.writeBuffer(pbuf, 0, pts as Float32Array<ArrayBuffer>);\n this.draw(\n this.pipes.line,\n [\n { buf: pbuf, offset: 0 },\n { buf: pbuf, offset: 8 },\n ],\n color,\n 1,\n [width, 0, 0],\n 6,\n n - 1,\n );\n }\n\n area(pts: Float32Array, color: string, baseY: number, plot: Rect): void {\n const n = pts.length / 2;\n // double each point so vertex_index can pick top vs baseline by parity\n if (this.areaScratch.length < n * 4) {\n this.areaScratch = new Float32Array(n * 4);\n }\n const d = this.areaScratch;\n for (let i = 0; i < n; i++) {\n const x = pts[2 * i] as number;\n const y = pts[2 * i + 1] as number;\n const o = 4 * i;\n d[o] = x;\n d[o + 1] = y;\n d[o + 2] = x;\n d[o + 3] = y;\n }\n const out = d.subarray(0, n * 4);\n const idx = this.drawIdx++;\n const pbuf = this.bufferFor(idx, out.byteLength);\n this.device.queue.writeBuffer(pbuf, 0, out as Float32Array<ArrayBuffer>);\n this.draw(\n this.pipes.area,\n [{ buf: pbuf, offset: 0 }],\n color,\n 1,\n [baseY, plot.y, plot.h],\n n * 2,\n 1,\n );\n }\n\n points(pts: Float32Array, color: string, radius = 2.5, alpha = 0.65): void {\n const n = pts.length / 2;\n const idx = this.drawIdx++;\n const pbuf = this.bufferFor(idx, pts.byteLength);\n this.device.queue.writeBuffer(pbuf, 0, pts as Float32Array<ArrayBuffer>);\n this.draw(\n this.pipes.points,\n [{ buf: pbuf, offset: 0 }],\n color,\n alpha,\n [radius, 0, 0],\n 6,\n n,\n );\n }\n\n end(): void {\n if (!this.pass || !this.encoder) return;\n this.pass.end();\n const qs = this.querySet;\n const qb = this.queryBuf;\n const rb = this.readBuf;\n if (qs && qb && rb && !this.reading) {\n this.encoder.resolveQuerySet(qs, 0, 2, qb, 0);\n this.encoder.copyBufferToBuffer(qb, 0, rb, 0, 16);\n this.reading = true;\n this.device.queue.submit([this.encoder.finish()]);\n void rb.mapAsync(MAP_READ).then(() => {\n const v = new BigUint64Array(rb.getMappedRange());\n const t0 = v[0];\n const t1 = v[1];\n if (t0 !== undefined && t1 !== undefined) {\n this.gpuMs = Number(t1 - t0) / 1e6;\n }\n rb.unmap();\n this.reading = false;\n });\n } else {\n this.device.queue.submit([this.encoder.finish()]);\n }\n this.pass = null;\n this.encoder = null;\n }\n\n destroy(): void {\n for (const b of this.bufs) b.destroy();\n this.queryBuf?.destroy();\n this.readBuf?.destroy();\n this.querySet?.destroy();\n this.bufs = [];\n this.ctx.unconfigure();\n this.canvas.remove();\n }\n}\n"],"mappings":"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"}
|