@jbrowse/render-core 5.0.0-beta.3 → 5.0.0-beta.7

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.
Files changed (71) hide show
  1. package/esm/RenderLifecycleMixin.d.ts +1 -0
  2. package/esm/RenderLifecycleMixin.js +8 -0
  3. package/esm/gpuContextLostError.d.ts +30 -0
  4. package/esm/gpuContextLostError.js +40 -0
  5. package/esm/gpuDevice.js +4 -1
  6. package/esm/hal/gpuHalBase.d.ts +3 -3
  7. package/esm/hal/index.d.ts +1 -1
  8. package/esm/hal/mockHal.d.ts +3 -3
  9. package/esm/hal/mockHal.js +3 -2
  10. package/esm/hal/oomReporter.d.ts +7 -0
  11. package/esm/hal/oomReporter.js +10 -0
  12. package/esm/hal/types.d.ts +8 -1
  13. package/esm/hal/webgl2Hal.d.ts +2 -2
  14. package/esm/hal/webgl2Hal.js +8 -1
  15. package/esm/hal/webgpuHal.d.ts +12 -2
  16. package/esm/hal/webgpuHal.js +49 -11
  17. package/esm/marks/barMark.d.ts +28 -0
  18. package/esm/marks/barMark.js +63 -0
  19. package/esm/marks/drawAgainstHit.d.ts +85 -14
  20. package/esm/marks/drawAgainstHit.js +260 -38
  21. package/esm/marks/glyphPaint.d.ts +10 -2
  22. package/esm/marks/glyphPaint.js +21 -0
  23. package/esm/marks/index.d.ts +9 -2
  24. package/esm/marks/index.js +4 -1
  25. package/esm/marks/markBackend.d.ts +21 -9
  26. package/esm/marks/markBackend.js +63 -29
  27. package/esm/marks/markHit.d.ts +32 -0
  28. package/esm/marks/markHit.js +61 -0
  29. package/esm/marks/markInk.d.ts +14 -0
  30. package/esm/marks/markInk.js +34 -0
  31. package/esm/marks/markPlan.d.ts +25 -0
  32. package/esm/marks/markPlan.js +20 -0
  33. package/esm/marks/markRamp.d.ts +43 -0
  34. package/esm/marks/markRamp.js +68 -0
  35. package/esm/marks/pointMark.d.ts +8 -4
  36. package/esm/marks/pointMark.js +39 -23
  37. package/esm/marks/spanMark.d.ts +8 -0
  38. package/esm/marks/spanMark.js +19 -26
  39. package/esm/marks/types.d.ts +101 -4
  40. package/esm/marks/types.js +78 -5
  41. package/esm/renderBlock.d.ts +14 -0
  42. package/esm/renderBlock.js +25 -0
  43. package/esm/shaders/barMark.generated.d.ts +4 -0
  44. package/esm/shaders/barMark.generated.js +6 -0
  45. package/esm/shaders/barMark.iface.generated.d.ts +64 -0
  46. package/esm/shaders/barMark.iface.generated.js +110 -0
  47. package/esm/shaders/markColor.generated.d.ts +3 -0
  48. package/esm/shaders/markColor.generated.js +5 -0
  49. package/esm/shaders/pointMark.generated.d.ts +3 -3
  50. package/esm/shaders/pointMark.generated.js +3 -3
  51. package/esm/shaders/pointMark.iface.generated.d.ts +17 -6
  52. package/esm/shaders/pointMark.iface.generated.js +27 -9
  53. package/esm/shaders/pointMark.js.generated.d.ts +2 -0
  54. package/esm/shaders/pointMark.js.generated.js +42 -0
  55. package/esm/shaders/scoreScale.generated.d.ts +2 -0
  56. package/esm/shaders/scoreScale.generated.js +4 -0
  57. package/esm/useRenderingBackend.d.ts +1 -16
  58. package/esm/useRenderingBackend.js +2 -24
  59. package/package.json +5 -2
  60. package/src/shaders/barMark.generated.ts +10 -0
  61. package/src/shaders/barMark.iface.generated.ts +160 -0
  62. package/src/shaders/barMark.slang +109 -0
  63. package/src/shaders/markColor.generated.ts +8 -0
  64. package/src/shaders/markColor.slang +47 -0
  65. package/src/shaders/pointMark.generated.ts +3 -3
  66. package/src/shaders/pointMark.iface.generated.ts +34 -10
  67. package/src/shaders/pointMark.js.generated.ts +45 -0
  68. package/src/shaders/pointMark.slang +35 -33
  69. package/src/shaders/scoreScale.generated.ts +6 -0
  70. package/src/shaders/scoreScale.slang +1 -0
  71. package/src/shaders/valueScale.slang +52 -0
@@ -7,12 +7,16 @@
7
7
  // All four are a 6-vertex quad; the fragment shader carves the shape.
8
8
  //! targets: wgsl, glsl
9
9
  //! export-consts: DIAMOND_GLYPH_SCALE, GLYPH_DISC, GLYPH_TRIANGLE, GLYPH_DIAMOND
10
- //! js-export: valueToYPx
10
+ //! js-export: valueToYPx, valueToYPxScaled, pointDrawsBar
11
+ // `valueToYPx` is `valueScale`'s; it is lifted here, once, for every consumer
12
+ // of the scale — the bar shape's painter and hit test import this twin too.
11
13
 
12
14
  import antialias;
13
15
  import hpmath;
14
16
  import colorPack;
17
+ import markColor;
15
18
  import pointGlyph;
19
+ import valueScale;
16
20
 
17
21
  public static const uint VERTS_PER_INSTANCE = 6u;
18
22
 
@@ -29,6 +33,13 @@ struct Uniforms {
29
33
  float canvasHeight;
30
34
  float domainMin;
31
35
  float domainMax;
36
+ // `scoreScale`'s scale-type vocabulary, for the declared y scale.
37
+ int valueScaleType;
38
+ // `markColor`'s: 0 packs the instance's colour, 1 and 2 read its slot as a
39
+ // value through the ramp below.
40
+ int rampMode;
41
+ float rampMin;
42
+ float rampMax;
32
43
  float zero;
33
44
  float viewportWidth;
34
45
  float radiusPx;
@@ -36,32 +47,23 @@ struct Uniforms {
36
47
  float devicePixelRatio;
37
48
  };
38
49
  [[vk::binding(1, 0)]] ConstantBuffer<Uniforms> u;
50
+ [[vk::binding(2, 0)]] Sampler2D<float4> colorRamp;
39
51
 
40
52
  float bpToClipX(uint bp, Uniforms u) {
41
53
  return hpToClipX(hpSplitUint(bp), u.bpRangeX, u.zero);
42
54
  }
43
55
 
44
- // The shape's y scale: clamp into the domain, invert (a bigger value sits
45
- // higher), scale to the canvas. Linear only — a consumer that wants log
46
- // pre-transforms its values, which is what GWAS -log10 p already is.
56
+ // Whether an instance draws as an extent bar rather than a glyph: its span has
57
+ // to beat the glyph it would otherwise be, so a datum wider than its own marker
58
+ // stops pretending to be a point.
47
59
  //
48
- // `//! js-export`ed because the Canvas2D painter AND the hit test run the JS
49
- // twin: a drift would move the grab target off the drawn glyph on the no-GPU
50
- // path only.
51
- //
52
- // max(range, 1e-6) guards a degenerate (min == max) domain from dividing by
53
- // zero. JS spelled that guard `|| 1`, and the two are NOT the same: `|| 1`
54
- // invents a phantom unit-wide domain, so with bounds pinned to a single value
55
- // a value half a unit above it drew half-way up the Canvas2D canvas while the
56
- // GPU clamped it to the top. Pinning a degenerate domain means everything above
57
- // it is off the top, which is what this does; the parity test pins the case.
58
- float valueToYPx(float value, float domainMin, float domainMax, float h) {
59
- float norm = clamp(
60
- (value - domainMin) / max(domainMax - domainMin, 1e-6),
61
- 0.0,
62
- 1.0,
63
- );
64
- return (1.0 - norm) * h;
60
+ // `//! js-export`ed because this one decision is read in three places — the
61
+ // vertex branch below, the painter's rect-vs-glyph fork and the hit test's
62
+ // rect-vs-centre fork — and a display whose hit test took the other branch from
63
+ // the draw would grab a bar at its midpoint. `rectDrawsOutline` and `arrowDraws`
64
+ // are the same lift for the same reason.
65
+ bool pointDrawsBar(float spanPx, float radiusPx) {
66
+ return spanPx > radiusPx * 2.0;
65
67
  }
66
68
 
67
69
  struct VsOut {
@@ -73,10 +75,6 @@ struct VsOut {
73
75
  nointerpolation float shape : TEXCOORD1;
74
76
  };
75
77
 
76
- // Solid ink each side of a bar's genomic span, in CSS px, so a run of adjacent
77
- // bars abuts. SHAPE_BAR's fragment coverage is a constant 1.
78
- static const float BAR_OVERDRAW_PX = 1.0;
79
-
80
78
  // Shape discriminators for the fragment shader. SMALL_POINT_MAX_DIAMETER and
81
79
  // the disc SDF come from the shared pointGlyph module so they stay in lockstep
82
80
  // with wiggle.slang.
@@ -112,24 +110,28 @@ VsOut vs_main(PointMarkInstance inst, uint vid : SV_VertexID) {
112
110
 
113
111
  float startClipX = bpToClipX(inst.x, u);
114
112
  float endClipX = bpToClipX(inst.x2, u);
115
- float yPx = valueToYPx(inst.y, u.domainMin, u.domainMax, u.canvasHeight);
113
+ float yPx = valueToYPxScaled(inst.y, u.domainMin, u.domainMax, u.canvasHeight, u.valueScaleType);
116
114
  float centerClipY = yPxToClipY(yPx, u.canvasHeight);
117
115
 
118
116
  // Genomic span in CSS px (clip width spans -1..1 across viewportWidth).
119
117
  // abs() because reversal is baked into bpRangeX (negated length), so
120
118
  // endClipX < startClipX on reversed regions — matches wiggle.slang.
121
119
  float spanPx = clipLenToPx(abs(endClipX - startClipX), u.viewportWidth);
122
- bool isBar = spanPx > u.radiusPx * 2.0;
120
+ bool isBar = pointDrawsBar(spanPx, u.radiusPx);
123
121
 
124
122
  VsOut o;
125
- o.color = unpackRGBA(inst.color);
123
+ o.color = markInstanceColor(colorRamp, inst.color, u.rampMode, u.rampMin, u.rampMax);
126
124
  if (isBar) {
127
125
  // Horizontal bar from x→x2, height 2*radiusPx px, centered on the value.
128
- float overdrawClipX = pxToClipLen(BAR_OVERDRAW_PX, u.viewportWidth);
129
- // min/max so a reversed region (endClipX < startClipX) still spans the full
130
- // bar extent instead of drawing an inverted quad — matches wiggle.slang.
131
- float x = xZero ? (min(startClipX, endClipX) - overdrawClipX)
132
- : (max(startClipX, endClipX) + overdrawClipX);
126
+ //
127
+ // NO SEAM PAD, and this reverses a deliberate one: `c7ff9d459d` kept the
128
+ // 1 px overdraw on the claim that abutting bars leave hairline gaps without
129
+ // it (the claim is that commit's, not the ADR-098 document's).
130
+ // Measured against a fixture built to test that (38 of 39 boundaries on a
131
+ // shared pixel row), padded and unpadded have the same interior gap
132
+ // columns — none opens. A hairline at a fractional `fillRect` edge is a
133
+ // Canvas2D problem and takes a Canvas2D pad; see `spanMark`'s `seamPx`.
134
+ float x = xZero ? min(startClipX, endClipX) : max(startClipX, endClipX);
133
135
  float halfBandPx = u.radiusPx;
134
136
  float y = centerClipY + pxToClipLen(local.y * halfBandPx, u.canvasHeight);
135
137
  o.position = float4(x, y, 0.0, 1.0);
@@ -0,0 +1,6 @@
1
+ // AUTO-GENERATED by packages/shader-tools/src/shader-codegen from scoreScale.slang.
2
+ // Do not edit. Run `pnpm gen:shaders` to regenerate.
3
+
4
+ export const SCALE_TYPE_LOG = 1
5
+
6
+ export const SCALE_TYPE_SYMLOG = 2
@@ -16,6 +16,7 @@
16
16
  //
17
17
  // `SCALE_TYPE_LINEAR` is deliberately absent: it is "neither of these", and a
18
18
  // third constant would be a value nothing compares against.
19
+ //! export-consts: SCALE_TYPE_LOG, SCALE_TYPE_SYMLOG
19
20
  //! js-export: normalizeScore
20
21
  //! js-skip: symlogTransform — the JS twin (wiggle-core normalize.ts) spells it Math.log1p, which is accurate near zero where the shader's log(1.0 + x) is not; a generated twin would be a faithful copy of the worse of the two. What both backends must agree on is normalizeScore, which is exported and swept by normalizeScoreParity.test.ts
21
22
  module scoreScale;
@@ -0,0 +1,52 @@
1
+ // The linear value → canvas-y scale a quantitative mark places its datum
2
+ // through: clamp into the domain, invert (a bigger value sits higher), scale to
3
+ // the canvas. `valueToYPx` is the linear scale on its own, which is what a
4
+ // consumer with no scale type of its own reads (Manhattan pins linear, and its
5
+ // -log10 p is already a pre-transform); `valueToYPxScaled` below takes a
6
+ // declared one.
7
+ //
8
+ // Two shapes compose it (ADR-095): `pointMark` reads it for a glyph centre and
9
+ // `barMark` for both cuts of a bar. Each keeps its own anchor (ADR-097) — a
10
+ // point centres on the value, a bar grows from `origin` to it — so only the
11
+ // scale lives here.
12
+ //
13
+ // max(range, 1e-6) guards a degenerate (min == max) domain from dividing by
14
+ // zero. JS spelled that guard `|| 1`, and the two are NOT the same: `|| 1`
15
+ // invents a phantom unit-wide domain, so with bounds pinned to a single value
16
+ // a value half a unit above it drew half-way up the Canvas2D canvas while the
17
+ // GPU clamped it to the top. Pinning a degenerate domain means everything above
18
+ // it is off the top, which is what this does; the parity test pins the case.
19
+ //
20
+ // A declared log scale takes the log arm of `scoreScale`'s `normalizeScore`,
21
+ // the normalizer wiggle and the coverage band are already placed by, so a mark
22
+ // display's axis ticks and its shader agree by construction. The linear arm
23
+ // stays this module's own: `normalizeScore` answers 0 on a degenerate domain
24
+ // and this answers 1, and that difference is a pinned cross-backend value
25
+ // (ADR-097).
26
+ //
27
+ // The JS twin is lifted by `pointMark.slang`'s `//! js-export` rather than
28
+ // here, the way hpmath's `expandToMinWidthPx` reaches JS through
29
+ // `coverageBar.slang`: one twin, in the generated module every consumer of the
30
+ // scale already imports.
31
+ module valueScale;
32
+
33
+ import scoreScale;
34
+
35
+ public float valueToYPx(float value, float domainMin, float domainMax, float h) {
36
+ float norm = clamp(
37
+ (value - domainMin) / max(domainMax - domainMin, 1e-6),
38
+ 0.0,
39
+ 1.0,
40
+ );
41
+ return (1.0 - norm) * h;
42
+ }
43
+
44
+ // The same placement under a declared scale type: `SCALE_TYPE_LOG` reads the
45
+ // value through `scoreScale`'s log arm, anything else through the linear one
46
+ // above.
47
+ public float valueToYPxScaled(float value, float domainMin, float domainMax, float h, int scaleType) {
48
+ if (scaleType == SCALE_TYPE_LOG) {
49
+ return (1.0 - normalizeScore(value, domainMin, domainMax, SCALE_TYPE_LOG, 1.0)) * h;
50
+ }
51
+ return valueToYPx(value, domainMin, domainMax, h);
52
+ }