@jbrowse/render-core 4.3.0 → 5.0.0-beta.10
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/RenderCanvas.d.ts +2 -2
- package/esm/RenderLifecycleMixin.d.ts +52 -20
- package/esm/RenderLifecycleMixin.js +89 -23
- package/esm/canvas2dUtils.d.ts +90 -23
- package/esm/canvas2dUtils.js +119 -36
- package/esm/colorRampLut.d.ts +5 -5
- package/esm/colorRampLut.js +6 -6
- package/esm/computePipeline.d.ts +14 -0
- package/esm/computePipeline.js +62 -0
- package/esm/contractReports.d.ts +54 -0
- package/esm/contractReports.js +112 -0
- package/esm/coverageBand.d.ts +13 -8
- package/esm/coverageBand.js +15 -5
- package/esm/coverageBandBuffers.d.ts +2 -9
- package/esm/coverageBandBuffers.js +1 -13
- package/esm/createRenderingBackend.d.ts +14 -18
- package/esm/createRenderingBackend.js +4 -2
- package/esm/displayPhase.d.ts +83 -104
- package/esm/displayPhase.js +42 -82
- package/esm/encodeMemo.d.ts +14 -0
- package/esm/encodeMemo.js +48 -0
- package/esm/gpuContextLostError.d.ts +30 -0
- package/esm/gpuContextLostError.js +40 -0
- package/esm/gpuDevice.d.ts +29 -10
- package/esm/gpuDevice.js +35 -16
- package/esm/graphicsCapabilities.d.ts +27 -19
- package/esm/graphicsCapabilities.js +40 -18
- package/esm/hal/createHal.d.ts +4 -5
- package/esm/hal/createHal.js +14 -4
- package/esm/hal/deviceGpuCache.d.ts +25 -30
- package/esm/hal/deviceGpuCache.js +88 -97
- package/esm/hal/gpuHalBase.d.ts +5 -4
- package/esm/hal/gpuHalBase.js +25 -14
- package/esm/hal/index.d.ts +2 -2
- package/esm/hal/index.js +1 -1
- package/esm/hal/mockHal.d.ts +15 -10
- package/esm/hal/mockHal.js +31 -18
- package/esm/hal/oomReporter.d.ts +7 -0
- package/esm/hal/oomReporter.js +10 -0
- package/esm/hal/passIds.d.ts +8 -7
- package/esm/hal/passIds.js +11 -10
- package/esm/hal/regionRegistry.d.ts +0 -1
- package/esm/hal/regionRegistry.js +3 -15
- package/esm/hal/types.d.ts +55 -18
- package/esm/hal/webgl2Hal.d.ts +23 -6
- package/esm/hal/webgl2Hal.js +161 -155
- package/esm/hal/webgpuHal.d.ts +29 -13
- package/esm/hal/webgpuHal.js +221 -153
- package/esm/installUpload.d.ts +16 -3
- package/esm/installUpload.js +13 -41
- package/esm/instanceCache.d.ts +10 -7
- package/esm/instanceCache.js +14 -15
- package/esm/instancePass.d.ts +2 -1
- package/esm/mapUploadSync.d.ts +2 -10
- package/esm/mapUploadSync.js +2 -3
- package/esm/marks/barMark.d.ts +30 -0
- package/esm/marks/barMark.js +149 -0
- package/esm/marks/colorFill.d.ts +17 -0
- package/esm/marks/colorFill.js +26 -0
- package/esm/marks/drawAgainstHit.d.ts +113 -0
- package/esm/marks/drawAgainstHit.js +407 -0
- package/esm/marks/ellipseDistance.d.ts +10 -0
- package/esm/marks/ellipseDistance.js +136 -0
- package/esm/marks/glyphPaint.d.ts +36 -0
- package/esm/marks/glyphPaint.js +77 -0
- package/esm/marks/index.d.ts +33 -0
- package/esm/marks/index.js +20 -0
- package/esm/marks/lineMark.d.ts +37 -0
- package/esm/marks/lineMark.js +416 -0
- package/esm/marks/linkMark.d.ts +76 -0
- package/esm/marks/linkMark.js +585 -0
- package/esm/marks/markBackend.d.ts +118 -0
- package/esm/marks/markBackend.js +196 -0
- package/esm/marks/markHit.d.ts +32 -0
- package/esm/marks/markHit.js +61 -0
- package/esm/marks/markInk.d.ts +18 -0
- package/esm/marks/markInk.js +71 -0
- package/esm/marks/markPaint.d.ts +14 -0
- package/esm/marks/markPaint.js +32 -0
- package/esm/marks/markPlan.d.ts +25 -0
- package/esm/marks/markPlan.js +20 -0
- package/esm/marks/markRamp.d.ts +72 -0
- package/esm/marks/markRamp.js +197 -0
- package/esm/marks/nearestMarkHit.d.ts +55 -0
- package/esm/marks/nearestMarkHit.js +158 -0
- package/esm/marks/pathRecorder.d.ts +14 -0
- package/esm/marks/pathRecorder.js +80 -0
- package/esm/marks/pointMark.d.ts +42 -0
- package/esm/marks/pointMark.js +125 -0
- package/esm/marks/rowLane.d.ts +39 -0
- package/esm/marks/rowLane.js +41 -0
- package/esm/marks/rowSpanIndex.d.ts +29 -0
- package/esm/marks/rowSpanIndex.js +141 -0
- package/esm/marks/rowTable.d.ts +41 -0
- package/esm/marks/rowTable.js +75 -0
- package/esm/marks/ruleMark.d.ts +21 -0
- package/esm/marks/ruleMark.js +91 -0
- package/esm/marks/spanMark.d.ts +42 -0
- package/esm/marks/spanMark.js +81 -0
- package/esm/marks/types.d.ts +261 -0
- package/esm/marks/types.js +175 -0
- package/esm/marks/valueScale.d.ts +23 -0
- package/esm/marks/valueScale.js +11 -0
- package/esm/namedReactions.d.ts +3 -4
- package/esm/namedReactions.js +3 -4
- package/esm/perRegionRenderingBackend.d.ts +21 -3
- package/esm/perRegionRenderingBackend.js +37 -3
- package/esm/regionDataMap.d.ts +2 -2
- package/esm/regionDataMap.js +25 -23
- package/esm/renderBlock.d.ts +14 -0
- package/esm/renderBlock.js +25 -0
- package/esm/renderingBackendBase.d.ts +20 -14
- package/esm/renderingBackendBase.js +12 -7
- package/esm/scoreScale.d.ts +27 -0
- package/esm/scoreScale.js +88 -0
- package/esm/shaders/barMark.generated.d.ts +3 -0
- package/esm/shaders/barMark.generated.js +7 -0
- package/esm/shaders/barMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/barMark.glsl.generated.js +4 -0
- package/esm/shaders/barMark.iface.generated.d.ts +90 -0
- package/esm/shaders/barMark.iface.generated.js +205 -0
- package/esm/shaders/barMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/barMark.wgsl.generated.js +3 -0
- package/esm/shaders/capsule.js.generated.d.ts +1 -0
- package/esm/shaders/capsule.js.generated.js +11 -0
- package/esm/shaders/clipStrip.generated.d.ts +2 -0
- package/esm/shaders/clipStrip.generated.js +4 -0
- package/esm/shaders/clipStrip.js.generated.d.ts +1 -0
- package/esm/shaders/clipStrip.js.generated.js +21 -0
- package/esm/shaders/colorRampLut.js.generated.d.ts +1 -0
- package/esm/shaders/colorRampLut.js.generated.js +17 -0
- package/esm/shaders/coverageBar.generated.d.ts +2 -3
- package/esm/shaders/coverageBar.generated.js +4 -3
- package/esm/shaders/coverageBar.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageBar.glsl.generated.js +4 -0
- package/esm/shaders/coverageBar.iface.generated.js +1 -1
- package/esm/shaders/coverageBar.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageBar.wgsl.generated.js +3 -0
- package/esm/shaders/coverageClip.generated.d.ts +3 -0
- package/esm/shaders/coverageClip.generated.js +7 -0
- package/esm/shaders/coverageClip.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageClip.glsl.generated.js +4 -0
- package/esm/shaders/coverageClip.iface.generated.d.ts +85 -0
- package/esm/shaders/coverageClip.iface.generated.js +114 -0
- package/esm/shaders/coverageClip.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageClip.wgsl.generated.js +3 -0
- package/esm/shaders/coverageIndicator.generated.d.ts +2 -3
- package/esm/shaders/coverageIndicator.generated.js +4 -3
- package/esm/shaders/coverageIndicator.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageIndicator.glsl.generated.js +4 -0
- package/esm/shaders/coverageIndicator.iface.generated.js +1 -1
- package/esm/shaders/coverageIndicator.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageIndicator.wgsl.generated.js +3 -0
- package/esm/shaders/coverageInterbase.generated.d.ts +2 -3
- package/esm/shaders/coverageInterbase.generated.js +4 -3
- package/esm/shaders/coverageInterbase.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageInterbase.glsl.generated.js +4 -0
- package/esm/shaders/coverageInterbase.iface.generated.js +1 -1
- package/esm/shaders/coverageInterbase.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageInterbase.wgsl.generated.js +3 -0
- package/esm/shaders/coverageMod.generated.d.ts +2 -3
- package/esm/shaders/coverageMod.generated.js +4 -3
- package/esm/shaders/coverageMod.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageMod.glsl.generated.js +4 -0
- package/esm/shaders/coverageMod.iface.generated.js +1 -1
- package/esm/shaders/coverageMod.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageMod.wgsl.generated.js +3 -0
- package/esm/shaders/coverageSnp.generated.d.ts +2 -3
- package/esm/shaders/coverageSnp.generated.js +4 -3
- package/esm/shaders/coverageSnp.glsl.generated.d.ts +2 -0
- package/esm/shaders/coverageSnp.glsl.generated.js +4 -0
- package/esm/shaders/coverageSnp.iface.generated.js +1 -1
- package/esm/shaders/coverageSnp.wgsl.generated.d.ts +1 -0
- package/esm/shaders/coverageSnp.wgsl.generated.js +3 -0
- package/esm/shaders/curveDistance.js.generated.d.ts +5 -0
- package/esm/shaders/curveDistance.js.generated.js +87 -0
- package/esm/shaders/hpmath.js.generated.d.ts +2 -1
- package/esm/shaders/hpmath.js.generated.js +5 -2
- package/esm/shaders/lineCenterMark.generated.d.ts +3 -0
- package/esm/shaders/lineCenterMark.generated.js +7 -0
- package/esm/shaders/lineCenterMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/lineCenterMark.glsl.generated.js +4 -0
- package/esm/shaders/lineCenterMark.iface.generated.d.ts +104 -0
- package/esm/shaders/lineCenterMark.iface.generated.js +237 -0
- package/esm/shaders/lineCenterMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/lineCenterMark.wgsl.generated.js +3 -0
- package/esm/shaders/lineCommon.generated.d.ts +2 -0
- package/esm/shaders/lineCommon.generated.js +4 -0
- package/esm/shaders/lineStepMark.generated.d.ts +3 -0
- package/esm/shaders/lineStepMark.generated.js +7 -0
- package/esm/shaders/lineStepMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/lineStepMark.glsl.generated.js +4 -0
- package/esm/shaders/lineStepMark.iface.generated.d.ts +98 -0
- package/esm/shaders/lineStepMark.iface.generated.js +225 -0
- package/esm/shaders/lineStepMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/lineStepMark.wgsl.generated.js +3 -0
- package/esm/shaders/linkMark.consts.generated.d.ts +14 -0
- package/esm/shaders/linkMark.consts.generated.js +16 -0
- package/esm/shaders/linkMark.generated.d.ts +4 -0
- package/esm/shaders/linkMark.generated.js +8 -0
- package/esm/shaders/linkMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/linkMark.glsl.generated.js +4 -0
- package/esm/shaders/linkMark.iface.generated.d.ts +142 -0
- package/esm/shaders/linkMark.iface.generated.js +1829 -0
- package/esm/shaders/linkMark.js.generated.d.ts +7 -0
- package/esm/shaders/linkMark.js.generated.js +159 -0
- package/esm/shaders/linkMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/linkMark.wgsl.generated.js +3 -0
- package/esm/shaders/markColor.generated.d.ts +9 -0
- package/esm/shaders/markColor.generated.js +11 -0
- package/esm/shaders/pointGlyph.js.generated.d.ts +2 -0
- package/esm/shaders/pointGlyph.js.generated.js +15 -0
- package/esm/shaders/pointMark.consts.generated.d.ts +7 -0
- package/esm/shaders/pointMark.consts.generated.js +9 -0
- package/esm/shaders/pointMark.generated.d.ts +4 -0
- package/esm/shaders/pointMark.generated.js +8 -0
- package/esm/shaders/pointMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/pointMark.glsl.generated.js +4 -0
- package/esm/shaders/pointMark.iface.generated.d.ts +98 -0
- package/esm/shaders/pointMark.iface.generated.js +219 -0
- package/esm/shaders/pointMark.js.generated.d.ts +3 -0
- package/esm/shaders/pointMark.js.generated.js +93 -0
- package/esm/shaders/pointMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/pointMark.wgsl.generated.js +3 -0
- package/esm/shaders/rowRect.generated.d.ts +0 -1
- package/esm/shaders/rowRect.generated.js +0 -1
- package/esm/shaders/rowTable.generated.d.ts +1 -0
- package/esm/shaders/rowTable.generated.js +3 -0
- package/esm/shaders/rowTable.js.generated.d.ts +5 -0
- package/esm/shaders/rowTable.js.generated.js +29 -0
- package/esm/shaders/scoreScale.generated.d.ts +2 -0
- package/esm/shaders/scoreScale.generated.js +4 -0
- package/esm/shaders/scoreScale.js.generated.d.ts +1 -0
- package/esm/shaders/scoreScale.js.generated.js +50 -23
- package/esm/shaders/spanMark.generated.d.ts +3 -0
- package/esm/shaders/spanMark.generated.js +7 -0
- package/esm/shaders/spanMark.glsl.generated.d.ts +2 -0
- package/esm/shaders/spanMark.glsl.generated.js +4 -0
- package/esm/shaders/spanMark.iface.generated.d.ts +81 -0
- package/esm/shaders/spanMark.iface.generated.js +215 -0
- package/esm/shaders/spanMark.wgsl.generated.d.ts +1 -0
- package/esm/shaders/spanMark.wgsl.generated.js +3 -0
- package/esm/sharedBackendKey.d.ts +18 -0
- package/esm/{keyedRenderingBackend.js → sharedBackendKey.js} +5 -0
- package/esm/slangPass.d.ts +18 -11
- package/esm/slangPass.js +12 -4
- package/esm/useGraphicsCapabilities.d.ts +1 -1
- package/esm/useGraphicsCapabilities.js +1 -1
- package/esm/useRenderingBackend.d.ts +13 -13
- package/esm/useRenderingBackend.js +58 -20
- package/esm/webgpuUtils.d.ts +3 -11
- package/esm/webgpuUtils.js +12 -33
- package/package.json +32 -7
- package/src/shaders/antialias.slang +46 -0
- package/src/shaders/arcHull.test.ts +267 -0
- package/src/shaders/barMark.generated.ts +11 -0
- package/src/shaders/barMark.glsl.generated.ts +6 -0
- package/src/shaders/barMark.iface.generated.ts +285 -0
- package/src/shaders/barMark.slang +167 -0
- package/src/shaders/barMark.wgsl.generated.ts +4 -0
- package/src/shaders/capsule.js.generated.ts +14 -0
- package/src/shaders/capsule.slang +12 -4
- package/src/shaders/clipStrip.generated.ts +6 -0
- package/src/shaders/clipStrip.js.generated.ts +22 -0
- package/src/shaders/clipStrip.slang +34 -0
- package/src/shaders/clipStrip.test.ts +39 -0
- package/src/shaders/colorPack.slang +5 -1
- package/src/shaders/colorRampLut.js.generated.ts +22 -0
- package/src/shaders/colorRampLut.slang +15 -1
- package/src/shaders/coverageBand.slang +64 -32
- package/src/shaders/coverageBar.generated.ts +6 -5
- package/src/shaders/coverageBar.glsl.generated.ts +6 -0
- package/src/shaders/coverageBar.iface.generated.ts +1 -1
- package/src/shaders/coverageBar.slang +10 -10
- package/src/shaders/coverageBar.wgsl.generated.ts +4 -0
- package/src/shaders/coverageClip.generated.ts +11 -0
- package/src/shaders/coverageClip.glsl.generated.ts +6 -0
- package/src/shaders/coverageClip.iface.generated.ts +172 -0
- package/src/shaders/coverageClip.slang +38 -0
- package/src/shaders/coverageClip.wgsl.generated.ts +4 -0
- package/src/shaders/coverageIndicator.generated.ts +6 -5
- package/src/shaders/coverageIndicator.glsl.generated.ts +6 -0
- package/src/shaders/coverageIndicator.iface.generated.ts +1 -1
- package/src/shaders/coverageIndicator.wgsl.generated.ts +4 -0
- package/src/shaders/coverageInterbase.generated.ts +6 -5
- package/src/shaders/coverageInterbase.glsl.generated.ts +6 -0
- package/src/shaders/coverageInterbase.iface.generated.ts +1 -1
- package/src/shaders/coverageInterbase.wgsl.generated.ts +4 -0
- package/src/shaders/coverageMod.generated.ts +6 -5
- package/src/shaders/coverageMod.glsl.generated.ts +6 -0
- package/src/shaders/coverageMod.iface.generated.ts +1 -1
- package/src/shaders/coverageMod.wgsl.generated.ts +4 -0
- package/src/shaders/coverageSnp.generated.ts +6 -5
- package/src/shaders/coverageSnp.glsl.generated.ts +6 -0
- package/src/shaders/coverageSnp.iface.generated.ts +1 -1
- package/src/shaders/coverageSnp.wgsl.generated.ts +4 -0
- package/src/shaders/curveDistance.js.generated.ts +91 -0
- package/src/shaders/curveDistance.slang +265 -0
- package/src/shaders/hpClampFloor.test.ts +87 -0
- package/src/shaders/hpmath.js.generated.ts +6 -2
- package/src/shaders/hpmath.slang +100 -48
- package/src/shaders/insetValueScale.test.ts +67 -0
- package/src/shaders/lineCenterMark.generated.ts +11 -0
- package/src/shaders/lineCenterMark.glsl.generated.ts +6 -0
- package/src/shaders/lineCenterMark.iface.generated.ts +328 -0
- package/src/shaders/lineCenterMark.slang +127 -0
- package/src/shaders/lineCenterMark.wgsl.generated.ts +4 -0
- package/src/shaders/lineCommon.generated.ts +6 -0
- package/src/shaders/lineCommon.slang +102 -0
- package/src/shaders/lineStepMark.generated.ts +11 -0
- package/src/shaders/lineStepMark.glsl.generated.ts +6 -0
- package/src/shaders/lineStepMark.iface.generated.ts +311 -0
- package/src/shaders/lineStepMark.slang +125 -0
- package/src/shaders/lineStepMark.wgsl.generated.ts +4 -0
- package/src/shaders/linkMark.consts.generated.ts +30 -0
- package/src/shaders/linkMark.generated.ts +12 -0
- package/src/shaders/linkMark.glsl.generated.ts +6 -0
- package/src/shaders/linkMark.iface.generated.ts +1954 -0
- package/src/shaders/linkMark.js.generated.ts +167 -0
- package/src/shaders/linkMark.slang +439 -0
- package/src/shaders/linkMark.wgsl.generated.ts +4 -0
- package/src/shaders/markColor.generated.ts +20 -0
- package/src/shaders/markColor.slang +128 -0
- package/src/shaders/pointGlyph.js.generated.ts +20 -0
- package/src/shaders/pointGlyph.slang +23 -7
- package/src/shaders/pointGlyphPad.test.ts +242 -0
- package/src/shaders/pointMark.consts.generated.ts +16 -0
- package/src/shaders/pointMark.generated.ts +12 -0
- package/src/shaders/pointMark.glsl.generated.ts +6 -0
- package/src/shaders/pointMark.iface.generated.ts +304 -0
- package/src/shaders/pointMark.js.generated.ts +99 -0
- package/src/shaders/pointMark.slang +227 -0
- package/src/shaders/pointMark.wgsl.generated.ts +4 -0
- package/src/shaders/rowRect.generated.ts +0 -2
- package/src/shaders/rowRect.slang +39 -58
- package/src/shaders/rowTable.generated.ts +4 -0
- package/src/shaders/rowTable.js.generated.ts +37 -0
- package/src/shaders/rowTable.slang +98 -0
- package/src/shaders/scoreScale.generated.ts +6 -0
- package/src/shaders/scoreScale.js.generated.ts +48 -23
- package/src/shaders/scoreScale.slang +49 -55
- package/src/shaders/sdEllipse.test.ts +211 -0
- package/src/shaders/spanMark.generated.ts +11 -0
- package/src/shaders/spanMark.glsl.generated.ts +6 -0
- package/src/shaders/spanMark.iface.generated.ts +289 -0
- package/src/shaders/spanMark.slang +77 -0
- package/src/shaders/spanMark.wgsl.generated.ts +4 -0
- package/src/shaders/valueScale.slang +26 -0
- package/src/shaders/wideCircleLeg.test.ts +85 -0
- package/esm/globalRenderingBackend.d.ts +0 -90
- package/esm/globalRenderingBackend.js +0 -53
- package/esm/keyedRenderingBackend.d.ts +0 -41
package/esm/canvas2dUtils.js
CHANGED
|
@@ -216,7 +216,7 @@ export function clipBlockForCanvas(block, canvasWidth) {
|
|
|
216
216
|
* Clip to one rect, paint, unclip — the `save`/`clip`/`restore` triple with the
|
|
217
217
|
* `restore` in a `finally`.
|
|
218
218
|
*
|
|
219
|
-
* The `finally` is
|
|
219
|
+
* The `finally` is required, and missing it breaks more than the one frame: an
|
|
220
220
|
* on-screen ctx outlives the frame and `prepareCanvas`'s setTransform/clearRect
|
|
221
221
|
* do **not** reset clip state, so one painter throwing once leaves every later
|
|
222
222
|
* frame drawing through a stale clip. A transient error becomes permanent
|
|
@@ -227,10 +227,16 @@ export function clipBlockForCanvas(block, canvasWidth) {
|
|
|
227
227
|
* own. Reach for this one for the clips *nested inside* a block — a display
|
|
228
228
|
* whose bands each own a horizontal strip of the canvas (alignments clips its
|
|
229
229
|
* coverage, pileup and arc bands separately within one block clip), where the
|
|
230
|
-
* nesting
|
|
230
|
+
* nesting makes a hand-rolled pairing easy to get wrong: an early
|
|
231
231
|
* `return` inside the band body unbalances the block's `save` too.
|
|
232
|
+
*
|
|
233
|
+
* An empty rect paints nothing, as the GPU's empty scissor does; the SVG export
|
|
234
|
+
* would otherwise record every path of a band nothing can show.
|
|
232
235
|
*/
|
|
233
236
|
export function withClip(ctx, x, y, w, h, paint) {
|
|
237
|
+
if (w <= 0 || h <= 0) {
|
|
238
|
+
return;
|
|
239
|
+
}
|
|
234
240
|
ctx.save();
|
|
235
241
|
ctx.beginPath();
|
|
236
242
|
ctx.rect(x, y, w, h);
|
|
@@ -334,6 +340,33 @@ export function strokeRectInside(ctx, x, y, w, h, lineWidth = 1) {
|
|
|
334
340
|
export function spanLeft(x1, x2, width) {
|
|
335
341
|
return x2 < x1 ? x1 - width : x1;
|
|
336
342
|
}
|
|
343
|
+
/**
|
|
344
|
+
* The `fillRect` x and width a genomic span paints as, given a bare
|
|
345
|
+
* `makeBpMapper`: `spanLeft`'s pivot and the min-width floor that goes with it,
|
|
346
|
+
* as one value a painter and its hit box can both read.
|
|
347
|
+
*
|
|
348
|
+
* `minWidth` defaults to 0, which makes this plain screen ordering — the
|
|
349
|
+
* leftmost projected edge and the unsigned distance. Pass a floor and the span
|
|
350
|
+
* grows away from `startBp`, which is the reversed-block rule `spanLeft` owns:
|
|
351
|
+
* anchoring the leftmost edge instead slides a sub-pixel mark by up to the floor
|
|
352
|
+
* on a flipped region and never on a forward one.
|
|
353
|
+
*
|
|
354
|
+
* Reach for this over `spanLeft` wherever the *numbers* are wanted rather than a
|
|
355
|
+
* fill — a hover box, an SVG rect, a cull test, an overlay div — which is where
|
|
356
|
+
* the pivot and the floor were being restated separately. The multi-row painter
|
|
357
|
+
* and the hover box it has to line up with each spelled out both.
|
|
358
|
+
* `fillBpSpan` is the same span when a `fillRect` is the only consumer.
|
|
359
|
+
*
|
|
360
|
+
* Not for a per-instance paint loop: this allocates a result per call, so the
|
|
361
|
+
* span mark's painter and wiggle's two bar loops take `spanLeft` and the two
|
|
362
|
+
* numbers inline, and stay the last hand-written copies of this arithmetic.
|
|
363
|
+
*/
|
|
364
|
+
export function spanRect(toX, startBp, endBp, minWidth = 0) {
|
|
365
|
+
const x1 = toX(startBp);
|
|
366
|
+
const x2 = toX(endBp);
|
|
367
|
+
const width = Math.max(minWidth, Math.abs(x2 - x1));
|
|
368
|
+
return { left: spanLeft(x1, x2, width), width };
|
|
369
|
+
}
|
|
337
370
|
// Quantize a 0..1 ramp position to a 256-entry index. Shared so the direct
|
|
338
371
|
// lookup and the fillStyle LUT below can't quantize differently — a half-step
|
|
339
372
|
// of drift between them shows up as a one-shade mismatch between a cell's fill
|
|
@@ -359,26 +392,42 @@ export function makeRampFillStyleLut(ramp) {
|
|
|
359
392
|
return s;
|
|
360
393
|
};
|
|
361
394
|
}
|
|
362
|
-
export function
|
|
363
|
-
const
|
|
395
|
+
export function bpProjection(bounds) {
|
|
396
|
+
const { start, end, screenStartPx, screenEndPx, reversed } = bounds;
|
|
364
397
|
const w = screenEndPx - screenStartPx;
|
|
365
|
-
return
|
|
398
|
+
return {
|
|
399
|
+
originPx: reversed ? screenEndPx : screenStartPx,
|
|
400
|
+
startBp: start,
|
|
401
|
+
spanBp: end - start,
|
|
402
|
+
signedSpanPx: reversed ? -w : w,
|
|
403
|
+
};
|
|
366
404
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
405
|
+
export function projectBp(p, bp) {
|
|
406
|
+
return p.originPx + ((bp - p.startBp) / p.spanBp) * p.signedSpanPx;
|
|
407
|
+
}
|
|
408
|
+
/**
|
|
409
|
+
* One closure literal for both orientations. Split per orientation, a paint
|
|
410
|
+
* loop's mapper call goes megamorphic on a view mixing them, and the loop ran
|
|
411
|
+
* 1.9-2.3x slower (`benches/bpMapper.bench.ts`).
|
|
412
|
+
*/
|
|
370
413
|
export function makeBpMapper(bounds) {
|
|
371
|
-
const {
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
414
|
+
const { originPx, startBp, spanBp, signedSpanPx } = bpProjection(bounds);
|
|
415
|
+
return (bp) => originPx + ((bp - startBp) / spanBp) * signedSpanPx;
|
|
416
|
+
}
|
|
417
|
+
/**
|
|
418
|
+
* Screen px one base occupies in this region: the scale factor, unsigned, with
|
|
419
|
+
* the block's direction left to `makeBpMapper` and `spanLeft`. Shared so a mark
|
|
420
|
+
* sized against it in a draw pass and hit-tested against it in a component
|
|
421
|
+
* read one number.
|
|
422
|
+
*/
|
|
423
|
+
export function pxPerBpOf(bounds) {
|
|
424
|
+
return ((bounds.screenEndPx - bounds.screenStartPx) / (bounds.end - bounds.start));
|
|
377
425
|
}
|
|
378
426
|
/**
|
|
379
|
-
* Left edge of the **1bp cell** covering `bp
|
|
380
|
-
*
|
|
381
|
-
*
|
|
427
|
+
* Left edge of the **1bp cell** covering `bp`, for a painter filling a rect
|
|
428
|
+
* exactly one base wide. A cell floored wider than its base grows from the
|
|
429
|
+
* base's low-coordinate edge instead, leftward on a reversed block, as the
|
|
430
|
+
* alignments pileup's `cellPlacement` does.
|
|
382
431
|
*
|
|
383
432
|
* Use this, not `makeBpMapper`, whenever the mark is a cell rather than a point
|
|
384
433
|
* or a two-edge span. `makeBpMapper(bp)` is the cell's left edge only on a
|
|
@@ -395,24 +444,7 @@ export function makeBpMapper(bounds) {
|
|
|
395
444
|
* `bpToClipX(pos)`→`bpToClipX(pos+1)` unflipped and mirror via `flipX` — and
|
|
396
445
|
* gets its own pivot from `writeBpRangeUniforms`.
|
|
397
446
|
*
|
|
398
|
-
* Callers own the cell *width*: it's a per-plugin rule (MAF uses the raw
|
|
399
|
-
* bp-scale; the pileup floors at 1px and adds a seam fudge). Only the pivot is
|
|
400
|
-
* shared.
|
|
401
447
|
*/
|
|
402
|
-
/**
|
|
403
|
-
* Screen px one base occupies in this region — the scale factor, unsigned, with
|
|
404
|
-
* the block's direction deliberately left out (that lives in `makeBpMapper` and
|
|
405
|
-
* `spanLeft`, and folding it in here would make a *scale* carry an orientation).
|
|
406
|
-
*
|
|
407
|
-
* Shared because it is usually an input to something a second painter has to
|
|
408
|
-
* reproduce exactly: a mark sized against it in a draw pass and hit-tested
|
|
409
|
-
* against it in a component is two spellings of one number, and the hit target
|
|
410
|
-
* silently stops covering the mark if they ever drift. Trivial arithmetic, but
|
|
411
|
-
* the drift is not.
|
|
412
|
-
*/
|
|
413
|
-
export function pxPerBpOf(bounds) {
|
|
414
|
-
return ((bounds.screenEndPx - bounds.screenStartPx) / (bounds.end - bounds.start));
|
|
415
|
-
}
|
|
416
448
|
export function makeCellLeftMapper(bounds) {
|
|
417
449
|
const toX = makeBpMapper(bounds);
|
|
418
450
|
const pxPerBp = pxPerBpOf(bounds);
|
|
@@ -429,7 +461,7 @@ export function makeCellLeftMapper(bounds) {
|
|
|
429
461
|
*
|
|
430
462
|
* Prefer this to `makeCellLeftMapper` + a caller-computed width for anything
|
|
431
463
|
* wider than one base. The pivot in `makeCellLeftMapper` is exactly one base,
|
|
432
|
-
* which is right for a 1bp cell and
|
|
464
|
+
* which is right for a 1bp cell and wrong for an N-bp span — it
|
|
433
465
|
* anchors the rect one base from the correct edge and then grows it the wrong
|
|
434
466
|
* way. `fillBpSpan(bp, bp + 1)` is *identical* to the cell-mapper spelling, so
|
|
435
467
|
* a per-base painter can use this too and never think about orientation again.
|
|
@@ -488,7 +520,7 @@ export function fillBpSpan(ctx, toX, startBp, endBp, top, height, seam = 0) {
|
|
|
488
520
|
* `14468.9936` — and rounding the *offset* and then adding such an anchor
|
|
489
521
|
* returns the anchor's fraction untouched. The result is then not a base at
|
|
490
522
|
* all, and every caller that indexes one by equality (a mismatch column, a
|
|
491
|
-
* coverage bin, the sort-at-this-column anchor)
|
|
523
|
+
* coverage bin, the sort-at-this-column anchor) finds no match: the pileup
|
|
492
524
|
* offered no SNP submenu over a mismatch it was drawing. Rounding
|
|
493
525
|
* `whole + fraction + offset` in one step instead fixes that and hands back the
|
|
494
526
|
* genome-scale addend the paragraph above exists to keep out, so the whole base
|
|
@@ -562,3 +594,54 @@ export function bpAtPxExact(px, bounds) {
|
|
|
562
594
|
export function regionAtPixel(regions, px) {
|
|
563
595
|
return regions.find(r => px >= r.screenStartPx && px < r.screenEndPx);
|
|
564
596
|
}
|
|
597
|
+
/**
|
|
598
|
+
* CSS px a Canvas2D painter adds to the drawn width of a rect whose neighbours
|
|
599
|
+
* abut it. `fillRect` antialiases each edge on its own, so two rects meeting on
|
|
600
|
+
* a fractional column each take partial coverage of it and a hairline of
|
|
601
|
+
* background shows through; abutting GPU quads share an exact clip-space edge
|
|
602
|
+
* and the rasterizer fills it once, so a shader grows no matching pad.
|
|
603
|
+
*/
|
|
604
|
+
export const CANVAS_SEAM_PX = 0.8;
|
|
605
|
+
/**
|
|
606
|
+
* Shapes a `CappedPath` holds before it paints and reopens. Chrome's
|
|
607
|
+
* GPU-rasterized canvas, which is desktop Chrome with a GPU and headless Chrome
|
|
608
|
+
* with the GPU blocklist off, silently paints nothing for a path past about
|
|
609
|
+
* 16 MiB: 180,000 discs, 453,000 rects or 931,000 line segments.
|
|
610
|
+
* `pnpm check-canvas-path-limits` drives the painters past it in a real browser.
|
|
611
|
+
*/
|
|
612
|
+
const MAX_SHAPES_PER_PATH = 10_000;
|
|
613
|
+
/**
|
|
614
|
+
* One batched Canvas2D path of many shapes, painted in pieces a browser will
|
|
615
|
+
* rasterize. Opens a path on construction; call `add()` before appending each
|
|
616
|
+
* shape and `flush()` to paint what it holds and reopen.
|
|
617
|
+
*/
|
|
618
|
+
export class CappedPath {
|
|
619
|
+
shapes = 0;
|
|
620
|
+
ctx;
|
|
621
|
+
paint;
|
|
622
|
+
constructor(ctx, paint) {
|
|
623
|
+
this.ctx = ctx;
|
|
624
|
+
this.paint = paint;
|
|
625
|
+
ctx.beginPath();
|
|
626
|
+
}
|
|
627
|
+
/**
|
|
628
|
+
* True when the path was full and has been painted and reopened, so a
|
|
629
|
+
* polyline must `moveTo` its pen again.
|
|
630
|
+
*/
|
|
631
|
+
add() {
|
|
632
|
+
if (this.shapes === MAX_SHAPES_PER_PATH) {
|
|
633
|
+
this.flush();
|
|
634
|
+
this.shapes = 1;
|
|
635
|
+
return true;
|
|
636
|
+
}
|
|
637
|
+
this.shapes++;
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
flush() {
|
|
641
|
+
if (this.shapes > 0) {
|
|
642
|
+
this.ctx[this.paint]();
|
|
643
|
+
this.ctx.beginPath();
|
|
644
|
+
this.shapes = 0;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
}
|
package/esm/colorRampLut.d.ts
CHANGED
|
@@ -9,9 +9,9 @@ export declare const COLOR_RAMP_LUT_ENTRIES = 256;
|
|
|
9
9
|
/**
|
|
10
10
|
* Upload a 256-entry RGBA colour-ramp LUT as each named pass's 256×1 texture —
|
|
11
11
|
* the runtime half of the shared ramp mechanism whose shader half is
|
|
12
|
-
* `shaders/colorRampLut.slang`.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* LUT contents.
|
|
12
|
+
* `shaders/colorRampLut.slang`. Called by `createMarkBackend` alone now, for
|
|
13
|
+
* every mark declaring a `texture`: hic, LD's two shader variants and wiggle
|
|
14
|
+
* density all put their ramps behind their samplers through it, each keeping
|
|
15
|
+
* its own scale and its own LUT contents.
|
|
16
16
|
*/
|
|
17
|
-
export declare function uploadColorRampLut(hal: GpuHal, ramp: Uint8Array, passIds: readonly string[]): void;
|
|
17
|
+
export declare function uploadColorRampLut(hal: GpuHal, ramp: Uint8Array, passIds: readonly string[], sampler?: string): void;
|
package/esm/colorRampLut.js
CHANGED
|
@@ -9,17 +9,17 @@ export const COLOR_RAMP_LUT_ENTRIES = RAMP_LUT_ENTRIES;
|
|
|
9
9
|
/**
|
|
10
10
|
* Upload a 256-entry RGBA colour-ramp LUT as each named pass's 256×1 texture —
|
|
11
11
|
* the runtime half of the shared ramp mechanism whose shader half is
|
|
12
|
-
* `shaders/colorRampLut.slang`.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
* LUT contents.
|
|
12
|
+
* `shaders/colorRampLut.slang`. Called by `createMarkBackend` alone now, for
|
|
13
|
+
* every mark declaring a `texture`: hic, LD's two shader variants and wiggle
|
|
14
|
+
* density all put their ramps behind their samplers through it, each keeping
|
|
15
|
+
* its own scale and its own LUT contents.
|
|
16
16
|
*/
|
|
17
|
-
export function uploadColorRampLut(hal, ramp, passIds) {
|
|
17
|
+
export function uploadColorRampLut(hal, ramp, passIds, sampler) {
|
|
18
18
|
if (ramp.length !== COLOR_RAMP_LUT_ENTRIES * 4) {
|
|
19
19
|
throw new Error(`uploadColorRampLut: expected a ${COLOR_RAMP_LUT_ENTRIES}-entry RGBA LUT ` +
|
|
20
20
|
`(${COLOR_RAMP_LUT_ENTRIES * 4} bytes), got ${ramp.length} bytes`);
|
|
21
21
|
}
|
|
22
22
|
for (const passId of passIds) {
|
|
23
|
-
hal.uploadTexture(passId, ramp, COLOR_RAMP_LUT_ENTRIES, 1);
|
|
23
|
+
hal.uploadTexture(passId, ramp, COLOR_RAMP_LUT_ENTRIES, 1, sampler);
|
|
24
24
|
}
|
|
25
25
|
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { ShaderBinding, ShaderSource } from './hal/index.ts';
|
|
2
|
+
export interface ComputePipelineState {
|
|
3
|
+
device: GPUDevice;
|
|
4
|
+
pipeline: GPUComputePipeline;
|
|
5
|
+
bindGroupLayout: GPUBindGroupLayout;
|
|
6
|
+
bindings: readonly ShaderBinding[];
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* One compute pipeline per kernel, built on first use against the current
|
|
10
|
+
* device and rebuilt after a device loss. Concurrent first callers share the
|
|
11
|
+
* one async build, which is also when the kernel's WGSL is loaded; a failed
|
|
12
|
+
* one is retried by the next caller rather than kept.
|
|
13
|
+
*/
|
|
14
|
+
export declare function makeComputePipelineCache(source: Pick<ShaderSource, 'wgsl'>, entryPoint: string, bindings: readonly ShaderBinding[]): (device: GPUDevice) => Promise<ComputePipelineState>;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/// <reference types="@webgpu/types" />
|
|
2
|
+
import { onDeviceLost } from './gpuDevice.js';
|
|
3
|
+
import { stageVisibility } from './webgpuUtils.js';
|
|
4
|
+
// Built from the kernel's own reflected binding table rather than restated by
|
|
5
|
+
// the caller, so a mismatch shows up as a validation failure at pipeline
|
|
6
|
+
// creation rather than as a wrong buffer under a right-looking index.
|
|
7
|
+
function makeBindGroupLayout(device, bindings) {
|
|
8
|
+
return device.createBindGroupLayout({
|
|
9
|
+
entries: bindings.map(b => {
|
|
10
|
+
if (b.kind === 'texture' || b.kind === 'sampler') {
|
|
11
|
+
throw new Error(`compute kernel: binding ${b.index} ('${b.name}') is a ${b.kind}, ` +
|
|
12
|
+
`which a buffer-only dispatch does not bind`);
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
binding: b.index,
|
|
16
|
+
visibility: stageVisibility(b.stages),
|
|
17
|
+
buffer: { type: b.kind },
|
|
18
|
+
};
|
|
19
|
+
}),
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* One compute pipeline per kernel, built on first use against the current
|
|
24
|
+
* device and rebuilt after a device loss. Concurrent first callers share the
|
|
25
|
+
* one async build, which is also when the kernel's WGSL is loaded; a failed
|
|
26
|
+
* one is retried by the next caller rather than kept.
|
|
27
|
+
*/
|
|
28
|
+
export function makeComputePipelineCache(source, entryPoint, bindings) {
|
|
29
|
+
let state = null;
|
|
30
|
+
let statePromise = null;
|
|
31
|
+
onDeviceLost(() => {
|
|
32
|
+
state = null;
|
|
33
|
+
statePromise = null;
|
|
34
|
+
});
|
|
35
|
+
return async function ensurePipeline(device) {
|
|
36
|
+
if (state?.device === device) {
|
|
37
|
+
return state;
|
|
38
|
+
}
|
|
39
|
+
if (statePromise) {
|
|
40
|
+
return statePromise;
|
|
41
|
+
}
|
|
42
|
+
statePromise = (async () => {
|
|
43
|
+
try {
|
|
44
|
+
const { WGSL_SOURCE } = await source.wgsl();
|
|
45
|
+
const module = device.createShaderModule({ code: WGSL_SOURCE });
|
|
46
|
+
const bindGroupLayout = makeBindGroupLayout(device, bindings);
|
|
47
|
+
const pipeline = await device.createComputePipelineAsync({
|
|
48
|
+
layout: device.createPipelineLayout({
|
|
49
|
+
bindGroupLayouts: [bindGroupLayout],
|
|
50
|
+
}),
|
|
51
|
+
compute: { module, entryPoint },
|
|
52
|
+
});
|
|
53
|
+
state = { device, pipeline, bindGroupLayout, bindings };
|
|
54
|
+
return state;
|
|
55
|
+
}
|
|
56
|
+
finally {
|
|
57
|
+
statePromise = null;
|
|
58
|
+
}
|
|
59
|
+
})();
|
|
60
|
+
return statePromise;
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A contract family — the `<family>` in the `[jbrowse <family> contract]`
|
|
3
|
+
* prefix every contract check in the tree reports under.
|
|
4
|
+
* `config/jest/console.js` matches `\w+`, so a new one reaches the test gate
|
|
5
|
+
* without touching it.
|
|
6
|
+
*/
|
|
7
|
+
export type ContractFamily = 'display' | 'session' | 'figure';
|
|
8
|
+
export interface ContractReport {
|
|
9
|
+
family: ContractFamily;
|
|
10
|
+
message: string;
|
|
11
|
+
/** what armed the channel, so a host can say why it is showing this */
|
|
12
|
+
armedBy: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Whether the checks should run at all.
|
|
16
|
+
*
|
|
17
|
+
* Read it where a check costs something to run — the `MutationObserver` a live
|
|
18
|
+
* figure installs, the per-frame payload walk in `installUpload`. A check whose
|
|
19
|
+
* cost is a `WeakSet` lookup should run unconditionally and report through
|
|
20
|
+
* {@link reportContractViolation} instead, so that arming the channel late
|
|
21
|
+
* still surfaces what it found.
|
|
22
|
+
*/
|
|
23
|
+
export declare function contractReportsOn(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Turn the channel on in a production build, saying what turned it on.
|
|
26
|
+
*
|
|
27
|
+
* The reason is not decoration: a notification that appears in an app the
|
|
28
|
+
* reader did not build has to answer "why am I seeing this" in its own text, or
|
|
29
|
+
* it reads as the app being broken rather than as a plugin being under
|
|
30
|
+
* development. First caller wins, so the earliest evidence is the one quoted.
|
|
31
|
+
*/
|
|
32
|
+
export declare function enableContractReports(reason: string): void;
|
|
33
|
+
/**
|
|
34
|
+
* Where a host puts contract violations that reach a user — a session
|
|
35
|
+
* notification in the apps. Installing one drains whatever was found before the
|
|
36
|
+
* host existed, and the disposer only clears the sink it installed, so a
|
|
37
|
+
* session torn down after its replacement was built does not take the live
|
|
38
|
+
* one's sink with it.
|
|
39
|
+
*/
|
|
40
|
+
export declare function setContractReportSink(fn: (report: ContractReport) => void): () => void;
|
|
41
|
+
/**
|
|
42
|
+
* Report a violation of an ordering contract no type can state.
|
|
43
|
+
*
|
|
44
|
+
* In tree this is the `console.error` it has always been, and the jest gate is
|
|
45
|
+
* what listens. Out of tree it is the only thing that reaches a plugin author
|
|
46
|
+
* at all: their display runs in a production build of somebody's app, which
|
|
47
|
+
* strips nothing here, and a violation surfaces the moment anything arms the
|
|
48
|
+
* channel — a `localStorage` flag, a plugin loaded from localhost, or a site
|
|
49
|
+
* whose config asks for it.
|
|
50
|
+
*
|
|
51
|
+
* `agent-docs/reference/ARCHITECTURAL_LIMITS.md` §"Ordering is the contract" is
|
|
52
|
+
* the register of what reports here.
|
|
53
|
+
*/
|
|
54
|
+
export declare function reportContractViolation(family: ContractFamily, message: string): void;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
const DEVELOPER_MODE_KEY = 'jbrowseDeveloperMode';
|
|
2
|
+
// The flag a plugin author can set on any deployed JBrowse without owning it or
|
|
3
|
+
// asking anyone, which is the population this whole channel is for.
|
|
4
|
+
function storageFlag() {
|
|
5
|
+
try {
|
|
6
|
+
return typeof localStorage === 'undefined' ||
|
|
7
|
+
localStorage.getItem(DEVELOPER_MODE_KEY) === null
|
|
8
|
+
? undefined
|
|
9
|
+
: `localStorage.${DEVELOPER_MODE_KEY} is set`;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
// storage can be denied outright, and a diagnostic is not the thing to take
|
|
13
|
+
// the app down with
|
|
14
|
+
return undefined;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
// Module scope for the same reason `numberGrouping` is: a check is called from
|
|
18
|
+
// a mixin factory, an MST action and a React effect that cannot share a
|
|
19
|
+
// closure, and each realm resolves this once at startup rather than through an
|
|
20
|
+
// observable a worker could not see.
|
|
21
|
+
let armedBy = process.env.NODE_ENV === 'production'
|
|
22
|
+
? storageFlag()
|
|
23
|
+
: 'this is a development build';
|
|
24
|
+
let sink;
|
|
25
|
+
const unlogged = [];
|
|
26
|
+
const undelivered = [];
|
|
27
|
+
const PENDING_LIMIT = 20;
|
|
28
|
+
function remember(queue, found) {
|
|
29
|
+
if (queue.length < PENDING_LIMIT) {
|
|
30
|
+
queue.push(found);
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Whether the checks should run at all.
|
|
35
|
+
*
|
|
36
|
+
* Read it where a check costs something to run — the `MutationObserver` a live
|
|
37
|
+
* figure installs, the per-frame payload walk in `installUpload`. A check whose
|
|
38
|
+
* cost is a `WeakSet` lookup should run unconditionally and report through
|
|
39
|
+
* {@link reportContractViolation} instead, so that arming the channel late
|
|
40
|
+
* still surfaces what it found.
|
|
41
|
+
*/
|
|
42
|
+
export function contractReportsOn() {
|
|
43
|
+
return armedBy !== undefined;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Turn the channel on in a production build, saying what turned it on.
|
|
47
|
+
*
|
|
48
|
+
* The reason is not decoration: a notification that appears in an app the
|
|
49
|
+
* reader did not build has to answer "why am I seeing this" in its own text, or
|
|
50
|
+
* it reads as the app being broken rather than as a plugin being under
|
|
51
|
+
* development. First caller wins, so the earliest evidence is the one quoted.
|
|
52
|
+
*/
|
|
53
|
+
export function enableContractReports(reason) {
|
|
54
|
+
armedBy ??= reason;
|
|
55
|
+
for (const found of unlogged.splice(0)) {
|
|
56
|
+
emit(found, armedBy);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Where a host puts contract violations that reach a user — a session
|
|
61
|
+
* notification in the apps. Installing one drains whatever was found before the
|
|
62
|
+
* host existed, and the disposer only clears the sink it installed, so a
|
|
63
|
+
* session torn down after its replacement was built does not take the live
|
|
64
|
+
* one's sink with it.
|
|
65
|
+
*/
|
|
66
|
+
export function setContractReportSink(fn) {
|
|
67
|
+
sink = fn;
|
|
68
|
+
if (armedBy !== undefined) {
|
|
69
|
+
for (const found of undelivered.splice(0)) {
|
|
70
|
+
fn({ ...found, armedBy });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return () => {
|
|
74
|
+
if (sink === fn) {
|
|
75
|
+
sink = undefined;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
function emit(found, armed) {
|
|
80
|
+
// `console.error`, never a throw: an error escaping `afterAttach` is read by
|
|
81
|
+
// the session loader as an invalid track and the display is silently dropped,
|
|
82
|
+
// which would hide the very violation being reported. The prefix is what
|
|
83
|
+
// `config/jest/console.js` buffers and `contractGate.js` fails a test on.
|
|
84
|
+
console.error(`[jbrowse ${found.family} contract] ${found.message}`);
|
|
85
|
+
if (sink === undefined) {
|
|
86
|
+
remember(undelivered, found);
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
sink({ ...found, armedBy: armed });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Report a violation of an ordering contract no type can state.
|
|
94
|
+
*
|
|
95
|
+
* In tree this is the `console.error` it has always been, and the jest gate is
|
|
96
|
+
* what listens. Out of tree it is the only thing that reaches a plugin author
|
|
97
|
+
* at all: their display runs in a production build of somebody's app, which
|
|
98
|
+
* strips nothing here, and a violation surfaces the moment anything arms the
|
|
99
|
+
* channel — a `localStorage` flag, a plugin loaded from localhost, or a site
|
|
100
|
+
* whose config asks for it.
|
|
101
|
+
*
|
|
102
|
+
* `agent-docs/reference/ARCHITECTURAL_LIMITS.md` §"Ordering is the contract" is
|
|
103
|
+
* the register of what reports here.
|
|
104
|
+
*/
|
|
105
|
+
export function reportContractViolation(family, message) {
|
|
106
|
+
if (armedBy === undefined) {
|
|
107
|
+
remember(unlogged, { family, message });
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
emit({ family, message }, armedBy);
|
|
111
|
+
}
|
|
112
|
+
}
|
package/esm/coverageBand.d.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import type { CoverageBandBuffers } from './coverageBandBuffers.ts';
|
|
2
2
|
import type { InstancePass } from './instancePass.ts';
|
|
3
|
-
export { coverageBandBuffers } from './coverageBandBuffers.ts';
|
|
4
3
|
export type { CoverageBandBuffers } from './coverageBandBuffers.ts';
|
|
5
4
|
export declare const COVERAGE_BAND_UNIFORMS_SIZE_BYTES = 112;
|
|
6
5
|
/**
|
|
@@ -15,10 +14,10 @@ export interface CoverageBandModBuffer {
|
|
|
15
14
|
/**
|
|
16
15
|
* One draw layer of the coverage band, and the id of the GPU pass that draws it.
|
|
17
16
|
*
|
|
18
|
-
* The band is the same
|
|
17
|
+
* The band is the same six marks wherever it appears — a display either has a
|
|
19
18
|
* layer's data or does not, and no display reorders them.
|
|
20
19
|
*/
|
|
21
|
-
export type CoverageLayerId = 'coverage' | 'snpCov' | 'modCov' | 'interbase' | 'indicator';
|
|
20
|
+
export type CoverageLayerId = 'coverage' | 'snpCov' | 'modCov' | 'interbase' | 'indicator' | 'clipStrip';
|
|
22
21
|
/**
|
|
23
22
|
* The band's z-order, back to front: the depth bars, the SNP slices stacked
|
|
24
23
|
* inside them, the modification slices stacked on those, the interbase histogram
|
|
@@ -47,6 +46,12 @@ export declare const COVERAGE_BAND_LAYER_ORDER: readonly CoverageLayerId[];
|
|
|
47
46
|
*/
|
|
48
47
|
export declare function orderCoverageBandLayers<T>(byId: Record<CoverageLayerId, T | undefined>): (T & ({} | null))[];
|
|
49
48
|
export declare const COVERAGE_BAR_PASS: InstancePass<Pick<CoverageBandBuffers, 'coveragePackedBuffer'>>;
|
|
49
|
+
/**
|
|
50
|
+
* The clip strips over the depth bars the domain cut, off the bar pass's own
|
|
51
|
+
* buffer and last in the order, since every layer between stacks inside the
|
|
52
|
+
* bar and would paint over a strip drawn with it.
|
|
53
|
+
*/
|
|
54
|
+
export declare const COVERAGE_CLIP_PASS: InstancePass<Pick<CoverageBandBuffers, 'coveragePackedBuffer'>>;
|
|
50
55
|
export declare const COVERAGE_SNP_PASS: InstancePass<Pick<CoverageBandBuffers, 'snpPackedBuffer'>>;
|
|
51
56
|
export declare const COVERAGE_MOD_PASS: InstancePass<CoverageBandModBuffer>;
|
|
52
57
|
export declare const COVERAGE_INTERBASE_PASS: InstancePass<Pick<CoverageBandBuffers, 'interbasePackedBuffer'>>;
|
|
@@ -81,7 +86,7 @@ export interface CoverageBandUniformValues {
|
|
|
81
86
|
covHeight: number;
|
|
82
87
|
covYOffset: number;
|
|
83
88
|
covTop: number;
|
|
84
|
-
/** The region's
|
|
89
|
+
/** The region's peak depth; the buffers' `relDepth` is a fraction of it. */
|
|
85
90
|
regionMaxDepth: number;
|
|
86
91
|
/** The display's autoscaled depth domain. `undefined` max = not resolved yet. */
|
|
87
92
|
domainMin: number;
|
|
@@ -99,9 +104,9 @@ export interface CoverageBandUniformValues {
|
|
|
99
104
|
* Fill the coverage band's uniform buffer. Total-write (the generated packer),
|
|
100
105
|
* so a field left out is a compile error rather than last frame's value.
|
|
101
106
|
*
|
|
102
|
-
* `hpZero` is derived here rather than at each call site because
|
|
103
|
-
*
|
|
104
|
-
* math
|
|
105
|
-
*
|
|
107
|
+
* `hpZero` is derived here rather than at each call site because a wrong value
|
|
108
|
+
* draws a plausible but wrong band and raises no error: it MUST be 0, since the
|
|
109
|
+
* HP math adds it to a clamp floor to keep that floor off the compiler's
|
|
110
|
+
* constant table and so stop it folding the hi/lo split away.
|
|
106
111
|
*/
|
|
107
112
|
export declare function writeCoverageBandUniforms(buf: ArrayBuffer, v: CoverageBandUniformValues): void;
|
package/esm/coverageBand.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as coverageBarShader from './shaders/coverageBar.generated.js';
|
|
2
|
+
import * as coverageClipShader from './shaders/coverageClip.generated.js';
|
|
2
3
|
import * as coverageIndicatorShader from './shaders/coverageIndicator.generated.js';
|
|
3
4
|
import * as coverageInterbaseShader from './shaders/coverageInterbase.generated.js';
|
|
4
5
|
import * as coverageModShader from './shaders/coverageMod.generated.js';
|
|
5
6
|
import * as coverageSnpShader from './shaders/coverageSnp.generated.js';
|
|
6
7
|
import { slangPass } from './slangPass.js';
|
|
7
|
-
export { coverageBandBuffers } from './coverageBandBuffers.js';
|
|
8
8
|
export const COVERAGE_BAND_UNIFORMS_SIZE_BYTES = coverageBarShader.UNIFORMS_SIZE_BYTES;
|
|
9
9
|
/**
|
|
10
10
|
* The band's z-order, back to front: the depth bars, the SNP slices stacked
|
|
@@ -27,6 +27,7 @@ export const COVERAGE_BAND_LAYER_ORDER = [
|
|
|
27
27
|
'modCov',
|
|
28
28
|
'interbase',
|
|
29
29
|
'indicator',
|
|
30
|
+
'clipStrip',
|
|
30
31
|
];
|
|
31
32
|
/**
|
|
32
33
|
* Whatever a display attaches to each band layer — a GPU pass, a Canvas2D
|
|
@@ -50,6 +51,15 @@ export const COVERAGE_BAR_PASS = {
|
|
|
50
51
|
...slangPass({ id: 'coverage', mod: coverageBarShader }),
|
|
51
52
|
pack: data => data.coveragePackedBuffer,
|
|
52
53
|
};
|
|
54
|
+
/**
|
|
55
|
+
* The clip strips over the depth bars the domain cut, off the bar pass's own
|
|
56
|
+
* buffer and last in the order, since every layer between stacks inside the
|
|
57
|
+
* bar and would paint over a strip drawn with it.
|
|
58
|
+
*/
|
|
59
|
+
export const COVERAGE_CLIP_PASS = {
|
|
60
|
+
...slangPass({ id: 'clipStrip', mod: coverageClipShader }),
|
|
61
|
+
pack: data => data.coveragePackedBuffer,
|
|
62
|
+
};
|
|
53
63
|
export const COVERAGE_SNP_PASS = {
|
|
54
64
|
...slangPass({ id: 'snpCov', mod: coverageSnpShader }),
|
|
55
65
|
pack: data => data.snpPackedBuffer,
|
|
@@ -70,10 +80,10 @@ export const COVERAGE_INDICATOR_PASS = {
|
|
|
70
80
|
* Fill the coverage band's uniform buffer. Total-write (the generated packer),
|
|
71
81
|
* so a field left out is a compile error rather than last frame's value.
|
|
72
82
|
*
|
|
73
|
-
* `hpZero` is derived here rather than at each call site because
|
|
74
|
-
*
|
|
75
|
-
* math
|
|
76
|
-
*
|
|
83
|
+
* `hpZero` is derived here rather than at each call site because a wrong value
|
|
84
|
+
* draws a plausible but wrong band and raises no error: it MUST be 0, since the
|
|
85
|
+
* HP math adds it to a clamp floor to keep that floor off the compiler's
|
|
86
|
+
* constant table and so stop it folding the hi/lo split away.
|
|
77
87
|
*/
|
|
78
88
|
export function writeCoverageBandUniforms(buf, v) {
|
|
79
89
|
const { domainMax, colors } = v;
|
|
@@ -7,9 +7,8 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Structural rather than nominal, and named after the layout rather than after
|
|
9
9
|
* either display: the alignments worker's `CoverageUploadData` and the MAF
|
|
10
|
-
* worker's `MafCoverageRegion` both satisfy it,
|
|
11
|
-
*
|
|
12
|
-
* restating four field reads.
|
|
10
|
+
* worker's `MafCoverageRegion` both satisfy it, so the passes in
|
|
11
|
+
* `coverageBand.ts` carry the packers and no plugin restates four field reads.
|
|
13
12
|
*
|
|
14
13
|
* Its own module, apart from the GPU passes in `coverageBand.ts`: a state
|
|
15
14
|
* model reaching for just this shape has no reason to statically pull in
|
|
@@ -22,9 +21,3 @@ export interface CoverageBandBuffers {
|
|
|
22
21
|
interbasePackedBuffer: ArrayBuffer;
|
|
23
22
|
indicatorPackedBuffer: ArrayBuffer;
|
|
24
23
|
}
|
|
25
|
-
/**
|
|
26
|
-
* Just the band's four buffers out of a wider per-region payload — the field set
|
|
27
|
-
* stated once, so a display carrying them into its own upload payload cannot
|
|
28
|
-
* spell three of them.
|
|
29
|
-
*/
|
|
30
|
-
export declare function coverageBandBuffers(src: CoverageBandBuffers): CoverageBandBuffers;
|
|
@@ -1,13 +1 @@
|
|
|
1
|
-
|
|
2
|
-
* Just the band's four buffers out of a wider per-region payload — the field set
|
|
3
|
-
* stated once, so a display carrying them into its own upload payload cannot
|
|
4
|
-
* spell three of them.
|
|
5
|
-
*/
|
|
6
|
-
export function coverageBandBuffers(src) {
|
|
7
|
-
return {
|
|
8
|
-
coveragePackedBuffer: src.coveragePackedBuffer,
|
|
9
|
-
snpPackedBuffer: src.snpPackedBuffer,
|
|
10
|
-
interbasePackedBuffer: src.interbasePackedBuffer,
|
|
11
|
-
indicatorPackedBuffer: src.indicatorPackedBuffer,
|
|
12
|
-
};
|
|
13
|
-
}
|
|
1
|
+
export {};
|