Skip to main content

runmat_plot/gpu/shaders/
line.rs

1pub const F32: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
2
3struct VertexRaw {
4    data: array<f32, 12u>,
5};
6
7struct LineParams {
8    color: vec4<f32>,
9    count: u32,
10    half_width_data: f32,
11    line_style: u32,
12    thick: u32,
13};
14
15@group(0) @binding(0)
16var<storage, read> buf_x: array<f32>;
17
18@group(0) @binding(1)
19var<storage, read> buf_y: array<f32>;
20
21@group(0) @binding(2)
22var<storage, read_write> out_vertices: array<VertexRaw>;
23
24@group(0) @binding(3)
25var<uniform> params: LineParams;
26
27fn should_draw(segment: u32, style: u32) -> bool {
28    switch(style) {
29        case 0u: { return true; } // Solid
30        case 1u: { return (segment % 4u) < 2u; } // Dashed: on,on,off,off
31        case 2u: { return (segment % 4u) < 2u; } // Dotted approximated via dashed pattern
32        case 3u: {
33            let m = segment % 6u;
34            return (m < 2u) || (m == 3u); // DashDot: on,on,off,on,off,off
35        }
36        default: { return true; }
37    }
38}
39
40fn write_vertex(index: u32, pos: vec2<f32>, color: vec4<f32>) {
41    var vertex: VertexRaw;
42    vertex.data[0u] = pos.x;
43    vertex.data[1u] = pos.y;
44    vertex.data[2u] = 0.0;
45    vertex.data[3u] = color.x;
46    vertex.data[4u] = color.y;
47    vertex.data[5u] = color.z;
48    vertex.data[6u] = color.w;
49    vertex.data[7u] = 0.0;
50    vertex.data[8u] = 0.0;
51    vertex.data[9u] = 1.0;
52    vertex.data[10u] = 0.0;
53    vertex.data[11u] = 0.0;
54    out_vertices[index] = vertex;
55}
56
57@compute @workgroup_size(WORKGROUP_SIZE)
58fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
59    if (params.count < 2u) {
60        return;
61    }
62    let segments = params.count - 1u;
63    let idx = gid.x;
64    if (idx >= segments) {
65        return;
66    }
67
68    let p0 = vec2<f32>(buf_x[idx], buf_y[idx]);
69    let p1 = vec2<f32>(buf_x[idx + 1u], buf_y[idx + 1u]);
70    let delta = p1 - p0;
71    let len = length(delta);
72    let draw = should_draw(idx, params.line_style) && (len != 0.0);
73    var color = params.color;
74    if (!draw) {
75        color.w = 0.0;
76    }
77
78    let thick = params.thick != 0u;
79    if (!thick) {
80        let base = idx * 2u;
81        write_vertex(base + 0u, p0, color);
82        write_vertex(base + 1u, p1, color);
83        return;
84    }
85
86    if (!draw) {
87        let base = idx * 6u;
88        // Emit fully transparent degenerate geometry for skipped/degenerate segments.
89        write_vertex(base + 0u, p0, color);
90        write_vertex(base + 1u, p0, color);
91        write_vertex(base + 2u, p0, color);
92        write_vertex(base + 3u, p0, color);
93        write_vertex(base + 4u, p0, color);
94        write_vertex(base + 5u, p0, color);
95        return;
96    }
97
98    var half_width = params.half_width_data;
99    if (half_width < 0.0001) {
100        half_width = 0.0001;
101    }
102    let dir = normalize(delta);
103    let normal = vec2<f32>(-dir.y, dir.x);
104    let offset = normal * half_width;
105    let v0 = p0 + offset;
106    let v1 = p1 + offset;
107    let v2 = p1 - offset;
108    let v3 = p0 - offset;
109
110    let base = idx * 6u;
111    write_vertex(base + 0u, v0, params.color);
112    write_vertex(base + 1u, v1, params.color);
113    write_vertex(base + 2u, v2, params.color);
114    write_vertex(base + 3u, v0, params.color);
115    write_vertex(base + 4u, v2, params.color);
116    write_vertex(base + 5u, v3, params.color);
117}
118"#;
119
120pub const F64: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
121
122struct VertexRaw {
123    data: array<f32, 12u>,
124};
125
126struct LineParams {
127    color: vec4<f32>,
128    count: u32,
129    half_width_data: f32,
130    line_style: u32,
131    thick: u32,
132};
133
134@group(0) @binding(0)
135var<storage, read> buf_x: array<f64>;
136
137@group(0) @binding(1)
138var<storage, read> buf_y: array<f64>;
139
140@group(0) @binding(2)
141var<storage, read_write> out_vertices: array<VertexRaw>;
142
143@group(0) @binding(3)
144var<uniform> params: LineParams;
145
146fn should_draw(segment: u32, style: u32) -> bool {
147    switch(style) {
148        case 0u: { return true; }
149        case 1u: { return (segment % 4u) < 2u; }
150        case 2u: { return (segment % 4u) < 2u; }
151        case 3u: {
152            let m = segment % 6u;
153            return (m < 2u) || (m == 3u);
154        }
155        default: { return true; }
156    }
157}
158
159fn write_vertex(index: u32, pos: vec2<f32>, color: vec4<f32>) {
160    var vertex: VertexRaw;
161    vertex.data[0u] = pos.x;
162    vertex.data[1u] = pos.y;
163    vertex.data[2u] = 0.0;
164    vertex.data[3u] = color.x;
165    vertex.data[4u] = color.y;
166    vertex.data[5u] = color.z;
167    vertex.data[6u] = color.w;
168    vertex.data[7u] = 0.0;
169    vertex.data[8u] = 0.0;
170    vertex.data[9u] = 1.0;
171    vertex.data[10u] = 0.0;
172    vertex.data[11u] = 0.0;
173    out_vertices[index] = vertex;
174}
175
176@compute @workgroup_size(WORKGROUP_SIZE)
177fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
178    if (params.count < 2u) {
179        return;
180    }
181    let segments = params.count - 1u;
182    let idx = gid.x;
183    if (idx >= segments) {
184        return;
185    }
186
187    let p0 = vec2<f32>(f32(buf_x[idx]), f32(buf_y[idx]));
188    let p1 = vec2<f32>(f32(buf_x[idx + 1u]), f32(buf_y[idx + 1u]));
189    let delta = p1 - p0;
190    let len = length(delta);
191    let draw = should_draw(idx, params.line_style) && (len != 0.0);
192    var color = params.color;
193    if (!draw) {
194        color.w = 0.0;
195    }
196
197    let thick = params.thick != 0u;
198    if (!thick) {
199        let base = idx * 2u;
200        write_vertex(base + 0u, p0, color);
201        write_vertex(base + 1u, p1, color);
202        return;
203    }
204
205    if (!draw) {
206        let base = idx * 6u;
207        write_vertex(base + 0u, p0, color);
208        write_vertex(base + 1u, p0, color);
209        write_vertex(base + 2u, p0, color);
210        write_vertex(base + 3u, p0, color);
211        write_vertex(base + 4u, p0, color);
212        write_vertex(base + 5u, p0, color);
213        return;
214    }
215
216    var half_width = params.half_width_data;
217    if (half_width < 0.0001) {
218        half_width = 0.0001;
219    }
220    let dir = normalize(delta);
221    let normal = vec2<f32>(-dir.y, dir.x);
222    let offset = normal * half_width;
223    let v0 = p0 + offset;
224    let v1 = p1 + offset;
225    let v2 = p1 - offset;
226    let v3 = p0 - offset;
227
228    let base = idx * 6u;
229    write_vertex(base + 0u, v0, params.color);
230    write_vertex(base + 1u, v1, params.color);
231    write_vertex(base + 2u, v2, params.color);
232    write_vertex(base + 3u, v0, params.color);
233    write_vertex(base + 4u, v2, params.color);
234    write_vertex(base + 5u, v3, params.color);
235}
236"#;
237
238pub const MARKER_F32: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
239
240struct VertexRaw {
241    data: array<f32, 12u>,
242};
243
244struct MarkerParams {
245    color: vec4<f32>,
246    count: u32,
247    size: f32,
248    _pad: vec2<u32>,
249};
250
251@group(0) @binding(0)
252var<storage, read> buf_x: array<f32>;
253
254@group(0) @binding(1)
255var<storage, read> buf_y: array<f32>;
256
257@group(0) @binding(2)
258var<storage, read_write> out_vertices: array<VertexRaw>;
259
260@group(0) @binding(3)
261var<uniform> params: MarkerParams;
262
263@compute @workgroup_size(WORKGROUP_SIZE)
264fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
265    let idx = gid.x;
266    if (idx >= params.count) {
267        return;
268    }
269
270    let px = buf_x[idx];
271    let py = buf_y[idx];
272
273    let base = idx * 6u;
274    let corners = array<vec2<f32>, 6u>(
275        vec2<f32>(-1.0, -1.0),
276        vec2<f32>( 1.0, -1.0),
277        vec2<f32>( 1.0,  1.0),
278        vec2<f32>(-1.0, -1.0),
279        vec2<f32>( 1.0,  1.0),
280        vec2<f32>(-1.0,  1.0)
281    );
282    for (var i: u32 = 0u; i < 6u; i = i + 1u) {
283    var vertex: VertexRaw;
284    vertex.data[0u] = px;
285    vertex.data[1u] = py;
286    vertex.data[2u] = 0.0;
287    vertex.data[3u] = params.color.x;
288    vertex.data[4u] = params.color.y;
289    vertex.data[5u] = params.color.z;
290    vertex.data[6u] = params.color.w;
291    vertex.data[7u] = 0.0;
292    vertex.data[8u] = 0.0;
293    vertex.data[9u] = params.size;
294        vertex.data[10u] = corners[i].x;
295        vertex.data[11u] = corners[i].y;
296        out_vertices[base + i] = vertex;
297    }
298}
299"#;
300
301pub const MARKER_F64: &str = r#"const WORKGROUP_SIZE: u32 = {{WORKGROUP_SIZE}}u;
302
303struct VertexRaw {
304    data: array<f32, 12u>,
305};
306
307struct MarkerParams {
308    color: vec4<f32>,
309    count: u32,
310    size: f32,
311    _pad: vec2<u32>,
312};
313
314@group(0) @binding(0)
315var<storage, read> buf_x: array<f64>;
316
317@group(0) @binding(1)
318var<storage, read> buf_y: array<f64>;
319
320@group(0) @binding(2)
321var<storage, read_write> out_vertices: array<VertexRaw>;
322
323@group(0) @binding(3)
324var<uniform> params: MarkerParams;
325
326@compute @workgroup_size(WORKGROUP_SIZE)
327fn main(@builtin(global_invocation_id) gid: vec3<u32>) {
328    let idx = gid.x;
329    if (idx >= params.count) {
330        return;
331    }
332
333    let px = f32(buf_x[idx]);
334    let py = f32(buf_y[idx]);
335
336    let base = idx * 6u;
337    let corners = array<vec2<f32>, 6u>(
338        vec2<f32>(-1.0, -1.0),
339        vec2<f32>( 1.0, -1.0),
340        vec2<f32>( 1.0,  1.0),
341        vec2<f32>(-1.0, -1.0),
342        vec2<f32>( 1.0,  1.0),
343        vec2<f32>(-1.0,  1.0)
344    );
345    for (var i: u32 = 0u; i < 6u; i = i + 1u) {
346    var vertex: VertexRaw;
347    vertex.data[0u] = px;
348    vertex.data[1u] = py;
349    vertex.data[2u] = 0.0;
350    vertex.data[3u] = params.color.x;
351    vertex.data[4u] = params.color.y;
352    vertex.data[5u] = params.color.z;
353    vertex.data[6u] = params.color.w;
354    vertex.data[7u] = 0.0;
355    vertex.data[8u] = 0.0;
356    vertex.data[9u] = params.size;
357        vertex.data[10u] = corners[i].x;
358        vertex.data[11u] = corners[i].y;
359        out_vertices[base + i] = vertex;
360    }
361}
362"#;