@jbrowse/render-core 5.0.0-beta.4 → 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.
- package/esm/RenderLifecycleMixin.d.ts +1 -0
- package/esm/RenderLifecycleMixin.js +8 -0
- package/esm/gpuContextLostError.d.ts +30 -0
- package/esm/gpuContextLostError.js +40 -0
- package/esm/gpuDevice.js +4 -1
- package/esm/hal/gpuHalBase.d.ts +3 -3
- package/esm/hal/index.d.ts +1 -1
- package/esm/hal/mockHal.d.ts +3 -3
- package/esm/hal/mockHal.js +3 -2
- package/esm/hal/oomReporter.d.ts +7 -0
- package/esm/hal/oomReporter.js +10 -0
- package/esm/hal/types.d.ts +8 -1
- package/esm/hal/webgl2Hal.d.ts +2 -2
- package/esm/hal/webgl2Hal.js +8 -1
- package/esm/hal/webgpuHal.d.ts +12 -2
- package/esm/hal/webgpuHal.js +43 -5
- package/esm/marks/barMark.d.ts +28 -0
- package/esm/marks/barMark.js +63 -0
- package/esm/marks/drawAgainstHit.d.ts +85 -14
- package/esm/marks/drawAgainstHit.js +260 -38
- package/esm/marks/glyphPaint.d.ts +10 -2
- package/esm/marks/glyphPaint.js +21 -0
- package/esm/marks/index.d.ts +9 -2
- package/esm/marks/index.js +4 -1
- package/esm/marks/markBackend.d.ts +14 -2
- package/esm/marks/markBackend.js +43 -13
- package/esm/marks/markHit.d.ts +8 -1
- package/esm/marks/markHit.js +15 -0
- package/esm/marks/markInk.d.ts +14 -0
- package/esm/marks/markInk.js +34 -0
- package/esm/marks/markPlan.d.ts +25 -0
- package/esm/marks/markPlan.js +20 -0
- package/esm/marks/markRamp.d.ts +43 -0
- package/esm/marks/markRamp.js +68 -0
- package/esm/marks/pointMark.d.ts +8 -4
- package/esm/marks/pointMark.js +32 -9
- package/esm/marks/spanMark.d.ts +8 -0
- package/esm/marks/spanMark.js +19 -14
- package/esm/marks/types.d.ts +90 -3
- package/esm/marks/types.js +56 -4
- package/esm/shaders/barMark.generated.d.ts +4 -0
- package/esm/shaders/barMark.generated.js +6 -0
- package/esm/shaders/barMark.iface.generated.d.ts +64 -0
- package/esm/shaders/barMark.iface.generated.js +110 -0
- package/esm/shaders/markColor.generated.d.ts +3 -0
- package/esm/shaders/markColor.generated.js +5 -0
- package/esm/shaders/pointMark.generated.d.ts +3 -3
- package/esm/shaders/pointMark.generated.js +3 -3
- package/esm/shaders/pointMark.iface.generated.d.ts +17 -6
- package/esm/shaders/pointMark.iface.generated.js +27 -9
- package/esm/shaders/pointMark.js.generated.d.ts +1 -0
- package/esm/shaders/pointMark.js.generated.js +39 -0
- package/esm/shaders/scoreScale.generated.d.ts +2 -0
- package/esm/shaders/scoreScale.generated.js +4 -0
- package/esm/useRenderingBackend.d.ts +1 -16
- package/esm/useRenderingBackend.js +2 -24
- package/package.json +4 -2
- package/src/shaders/barMark.generated.ts +10 -0
- package/src/shaders/barMark.iface.generated.ts +160 -0
- package/src/shaders/barMark.slang +109 -0
- package/src/shaders/markColor.generated.ts +8 -0
- package/src/shaders/markColor.slang +47 -0
- package/src/shaders/pointMark.generated.ts +3 -3
- package/src/shaders/pointMark.iface.generated.ts +34 -10
- package/src/shaders/pointMark.js.generated.ts +41 -0
- package/src/shaders/pointMark.slang +15 -26
- package/src/shaders/scoreScale.generated.ts +6 -0
- package/src/shaders/scoreScale.slang +1 -0
- package/src/shaders/valueScale.slang +52 -0
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
// AUTO-GENERATED by packages/shader-tools/src/shader-codegen from pointMark.slang.
|
|
2
2
|
// Do not edit. Run `pnpm gen:shaders` to regenerate.
|
|
3
3
|
|
|
4
|
-
import type { VertexAttributeLayout, ShaderBinding } from '@jbrowse/render-core/hal'
|
|
4
|
+
import type { VertexAttributeLayout, ShaderBinding, TextureBinding } from '@jbrowse/render-core/hal'
|
|
5
5
|
|
|
6
6
|
export const BINDINGS: readonly ShaderBinding[] = [
|
|
7
7
|
{ index: 1, kind: 'uniform', name: 'u' },
|
|
8
|
+
{ index: 2, kind: 'texture', name: 'colorRamp' },
|
|
9
|
+
{ index: 3, kind: 'sampler', name: 'colorRamp' },
|
|
8
10
|
]
|
|
9
11
|
|
|
10
12
|
export const VERTS_PER_INSTANCE = 6
|
|
11
13
|
|
|
12
|
-
export const UNIFORMS_SIZE_BYTES =
|
|
14
|
+
export const UNIFORMS_SIZE_BYTES = 64
|
|
13
15
|
|
|
14
16
|
// Word indices into a Float32Array view over the uniform buffer.
|
|
15
17
|
export const UNIFORM_OFFSET_F32 = {
|
|
@@ -17,10 +19,18 @@ export const UNIFORM_OFFSET_F32 = {
|
|
|
17
19
|
canvasHeight: 3,
|
|
18
20
|
domainMin: 4,
|
|
19
21
|
domainMax: 5,
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
rampMin: 8,
|
|
23
|
+
rampMax: 9,
|
|
24
|
+
zero: 10,
|
|
25
|
+
viewportWidth: 11,
|
|
26
|
+
radiusPx: 12,
|
|
27
|
+
devicePixelRatio: 13,
|
|
28
|
+
} as const
|
|
29
|
+
|
|
30
|
+
// Word indices into a Int32Array view over the uniform buffer.
|
|
31
|
+
export const UNIFORM_OFFSET_I32 = {
|
|
32
|
+
valueScaleType: 6,
|
|
33
|
+
rampMode: 7,
|
|
24
34
|
} as const
|
|
25
35
|
|
|
26
36
|
|
|
@@ -29,6 +39,10 @@ export interface Uniforms {
|
|
|
29
39
|
canvasHeight: number
|
|
30
40
|
domainMin: number
|
|
31
41
|
domainMax: number
|
|
42
|
+
valueScaleType: number
|
|
43
|
+
rampMode: number
|
|
44
|
+
rampMin: number
|
|
45
|
+
rampMax: number
|
|
32
46
|
zero: number
|
|
33
47
|
viewportWidth: number
|
|
34
48
|
radiusPx: number
|
|
@@ -37,16 +51,21 @@ export interface Uniforms {
|
|
|
37
51
|
|
|
38
52
|
export function writeUniforms(buf: ArrayBuffer, uniforms: Uniforms) {
|
|
39
53
|
const f32 = new Float32Array(buf)
|
|
54
|
+
const i32 = new Int32Array(buf)
|
|
40
55
|
f32[0] = uniforms.bpRangeX[0]
|
|
41
56
|
f32[1] = uniforms.bpRangeX[1]
|
|
42
57
|
f32[2] = uniforms.bpRangeX[2]
|
|
43
58
|
f32[3] = uniforms.canvasHeight
|
|
44
59
|
f32[4] = uniforms.domainMin
|
|
45
60
|
f32[5] = uniforms.domainMax
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
f32[8] = uniforms.
|
|
49
|
-
f32[9] = uniforms.
|
|
61
|
+
i32[6] = uniforms.valueScaleType
|
|
62
|
+
i32[7] = uniforms.rampMode
|
|
63
|
+
f32[8] = uniforms.rampMin
|
|
64
|
+
f32[9] = uniforms.rampMax
|
|
65
|
+
f32[10] = uniforms.zero
|
|
66
|
+
f32[11] = uniforms.viewportWidth
|
|
67
|
+
f32[12] = uniforms.radiusPx
|
|
68
|
+
f32[13] = uniforms.devicePixelRatio
|
|
50
69
|
}
|
|
51
70
|
|
|
52
71
|
export const INSTANCE_STRIDE_BYTES = 20
|
|
@@ -144,3 +163,8 @@ export function getInstanceGlyph(u32: Uint32Array, i: number) {
|
|
|
144
163
|
export function setInstanceGlyph(u32: Uint32Array, i: number, v: number) {
|
|
145
164
|
u32[i * INSTANCE_STRIDE_WORDS + 4] = v
|
|
146
165
|
}
|
|
166
|
+
|
|
167
|
+
// Combined `Sampler2D` bindings. Texture unit indices start at 0.
|
|
168
|
+
export const TEXTURES: readonly [TextureBinding, ...TextureBinding[]] = [
|
|
169
|
+
{ textureBinding: 2, samplerBinding: 3, glTextureUnit: 0, glUniformName: 'u_colorRamp', filter: 'linear' },
|
|
170
|
+
]
|
|
@@ -16,10 +16,51 @@ function _min(a: number, b: number) {
|
|
|
16
16
|
return b < a || Number.isNaN(a) ? b : a
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
+
function symlogTransform(x: number, c: number): number {
|
|
20
|
+
return ((((Math.sign(x)) | 0)) * Math.log((1.0 + Math.abs((x / c)))))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function normalizeScore(score: number, domainMin: number, domainMax: number, scaleType: number, symlogConstant: number): number {
|
|
24
|
+
if ((scaleType == 2)) {
|
|
25
|
+
let tMin = symlogTransform(domainMin, symlogConstant)
|
|
26
|
+
let tRange = (symlogTransform(domainMax, symlogConstant) - tMin)
|
|
27
|
+
if ((tRange <= 0.0)) {
|
|
28
|
+
return 0.0
|
|
29
|
+
}
|
|
30
|
+
return _clamp(((symlogTransform(score, symlogConstant) - tMin) / tRange), 0.0, 1.0)
|
|
31
|
+
}
|
|
32
|
+
if ((scaleType == 1)) {
|
|
33
|
+
let floorV: number
|
|
34
|
+
if ((domainMin > 0.0)) {
|
|
35
|
+
floorV = domainMin
|
|
36
|
+
} else {
|
|
37
|
+
floorV = 1.0
|
|
38
|
+
}
|
|
39
|
+
let logMin = Math.log2(floorV)
|
|
40
|
+
let logRange = (Math.log2(_max(domainMax, floorV)) - logMin)
|
|
41
|
+
if ((logRange <= 0.0)) {
|
|
42
|
+
return 0.0
|
|
43
|
+
}
|
|
44
|
+
return _clamp(((Math.log2(_max(score, floorV)) - logMin) / logRange), 0.0, 1.0)
|
|
45
|
+
}
|
|
46
|
+
let range = (domainMax - domainMin)
|
|
47
|
+
if ((range <= 0.0)) {
|
|
48
|
+
return 0.0
|
|
49
|
+
}
|
|
50
|
+
return _clamp(((score - domainMin) / range), 0.0, 1.0)
|
|
51
|
+
}
|
|
52
|
+
|
|
19
53
|
export function valueToYPx(value: number, domainMin: number, domainMax: number, h: number): number {
|
|
20
54
|
return ((1.0 - _clamp(((value - domainMin) / _max((domainMax - domainMin), 9.99999997475242708e-07)), 0.0, 1.0)) * h)
|
|
21
55
|
}
|
|
22
56
|
|
|
57
|
+
export function valueToYPxScaled(value: number, domainMin: number, domainMax: number, h: number, scaleType: number): number {
|
|
58
|
+
if ((scaleType == 1)) {
|
|
59
|
+
return ((1.0 - normalizeScore(value, domainMin, domainMax, 1, 1.0)) * h)
|
|
60
|
+
}
|
|
61
|
+
return valueToYPx(value, domainMin, domainMax, h)
|
|
62
|
+
}
|
|
63
|
+
|
|
23
64
|
export function pointDrawsBar(spanPx: number, radiusPx: number): boolean {
|
|
24
65
|
return (spanPx > (radiusPx * 2.0))
|
|
25
66
|
}
|
|
@@ -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, pointDrawsBar
|
|
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,34 +47,12 @@ 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.
|
|
47
|
-
//
|
|
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;
|
|
65
|
-
}
|
|
66
|
-
|
|
67
56
|
// Whether an instance draws as an extent bar rather than a glyph: its span has
|
|
68
57
|
// to beat the glyph it would otherwise be, so a datum wider than its own marker
|
|
69
58
|
// stops pretending to be a point.
|
|
@@ -121,7 +110,7 @@ VsOut vs_main(PointMarkInstance inst, uint vid : SV_VertexID) {
|
|
|
121
110
|
|
|
122
111
|
float startClipX = bpToClipX(inst.x, u);
|
|
123
112
|
float endClipX = bpToClipX(inst.x2, u);
|
|
124
|
-
float yPx =
|
|
113
|
+
float yPx = valueToYPxScaled(inst.y, u.domainMin, u.domainMax, u.canvasHeight, u.valueScaleType);
|
|
125
114
|
float centerClipY = yPxToClipY(yPx, u.canvasHeight);
|
|
126
115
|
|
|
127
116
|
// Genomic span in CSS px (clip width spans -1..1 across viewportWidth).
|
|
@@ -131,7 +120,7 @@ VsOut vs_main(PointMarkInstance inst, uint vid : SV_VertexID) {
|
|
|
131
120
|
bool isBar = pointDrawsBar(spanPx, u.radiusPx);
|
|
132
121
|
|
|
133
122
|
VsOut o;
|
|
134
|
-
o.color =
|
|
123
|
+
o.color = markInstanceColor(colorRamp, inst.color, u.rampMode, u.rampMin, u.rampMax);
|
|
135
124
|
if (isBar) {
|
|
136
125
|
// Horizontal bar from x→x2, height 2*radiusPx px, centered on the value.
|
|
137
126
|
//
|
|
@@ -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
|
+
}
|