@jbrowse/render-core 5.0.0-beta.1 → 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/hal/webgl2Hal.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { syncCanvasSize } from '../canvas2dUtils.js';
|
|
1
|
+
import { getDpr, syncCanvasSize } from '../canvas2dUtils.js';
|
|
2
2
|
import { canvasContextError, noteCanvasContext } from '../canvasContext.js';
|
|
3
3
|
import { GpuHalBase } from './gpuHalBase.js';
|
|
4
4
|
function createShader(gl, type, source) {
|
|
@@ -43,8 +43,7 @@ function bindUniformBlock(gl, program, blockName, bindingPoint) {
|
|
|
43
43
|
gl.uniformBlockBinding(program, idx, bindingPoint);
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
//
|
|
47
|
-
// enable verbose logging. Kept guarded so production builds stay quiet.
|
|
46
|
+
// `DEBUG.webgl2 = true` in devtools, or `?webgl2-debug=1`, logs verbosely.
|
|
48
47
|
function debugEnabled() {
|
|
49
48
|
if (typeof window === 'undefined') {
|
|
50
49
|
return false;
|
|
@@ -91,59 +90,35 @@ function glBlendFactor(gl, factor) {
|
|
|
91
90
|
return gl.ONE_MINUS_SRC_ALPHA;
|
|
92
91
|
}
|
|
93
92
|
}
|
|
94
|
-
//
|
|
95
|
-
//
|
|
96
|
-
// lose. These counters surface the leak when it happens.
|
|
93
|
+
// Live-context counts for the debug log: a leaked context evicts the oldest
|
|
94
|
+
// once the browser's cap is reached.
|
|
97
95
|
let totalCreated = 0;
|
|
98
96
|
let totalDisposed = 0;
|
|
99
|
-
//
|
|
100
|
-
//
|
|
101
|
-
//
|
|
102
|
-
// nothing to ask — but "ask the driver" was never what the guard was for. Its
|
|
103
|
-
// job is to turn one pathological upload into the "zoom in" banner, and without
|
|
104
|
-
// it the same upload that banners on WebGPU takes Chrome's context down here
|
|
105
|
-
// instead. That is strictly worse than a blank track on a page at the context
|
|
106
|
-
// ceiling: the loss evicts a sibling, whose recovery evicts another, and
|
|
107
|
-
// GPU_CONTEXT_BUDGET.md is that cascade.
|
|
108
|
-
//
|
|
109
|
-
// 256 MiB is WebGPU's *spec default* `maxBufferSize`. It is not parity with
|
|
110
|
-
// what the WebGPU backend actually refuses at: `gpuDevice.acquire` raises the
|
|
111
|
-
// limit to `adapter.limits.maxBufferSize`, which is 2147483644 bytes (~2 GiB)
|
|
112
|
-
// on the Firefox Nightly / Intel UHD 630 this was checked on, so WebGL2 is the
|
|
113
|
-
// stricter of the two and a region can banner here while rendering there. That
|
|
114
|
-
// asymmetry is accepted — a quarter-gigabyte single vertex buffer is not
|
|
115
|
-
// something to hand an API that answers a failed allocation by dropping the
|
|
116
|
-
// context.
|
|
117
|
-
//
|
|
118
|
-
// Deliberately a ceiling and not a budget: it catches the single upload
|
|
119
|
-
// nothing else bounds, and says nothing about the total, which is
|
|
120
|
-
// ARCHITECTURAL_LIMITS.md §"No session-level GPU memory budget".
|
|
97
|
+
// WebGPU's spec-default `maxBufferSize`, since WebGL2 has none to query: an
|
|
98
|
+
// upload past it banners rather than dropping the context
|
|
99
|
+
// (ARCHITECTURAL_LIMITS.md).
|
|
121
100
|
const MAX_VERTEX_BUFFER_BYTES = 256 * 1024 * 1024;
|
|
122
|
-
|
|
123
|
-
// products/jbrowse-web/browser-tests/compare-backends.ts pixel-diffs webgl vs
|
|
124
|
-
// webgpu vs canvas2d output, and shared buffer bookkeeping is covered by
|
|
125
|
-
// hal/regionRegistry.test.ts. Neither HAL is where attribute layout is checked —
|
|
126
|
-
// `assertVertexInputsMatch` does that at `pnpm gen:shaders` time, per shader and
|
|
127
|
-
// per target. Mirror any behavior change in webgpuHal.ts — and note that
|
|
128
|
-
// `GpuHalBase` already holds the parts that were only ever mirrored: the
|
|
129
|
-
// descriptor map, the buffer registry, both upload shells and their over-limit
|
|
130
|
-
// wording, and the dispose guard.
|
|
101
|
+
const NO_TEXTURES = [];
|
|
131
102
|
export class WebGL2Hal extends GpuHalBase {
|
|
132
103
|
gl;
|
|
133
104
|
canvas;
|
|
134
|
-
//
|
|
135
|
-
|
|
136
|
-
|
|
105
|
+
// `null` is a pass whose link failed, so it is reported once, not per frame.
|
|
106
|
+
passes = new Map();
|
|
107
|
+
glsl;
|
|
108
|
+
// By vertex source, then fragment source, attribute names and sampler as
|
|
109
|
+
// JSON: every pass id over one program shares it, and a failed link keeps
|
|
110
|
+
// its error.
|
|
111
|
+
programs = new Map();
|
|
112
|
+
// Each pass's textures, by the sampler that reads each.
|
|
113
|
+
passTextures = new Map();
|
|
137
114
|
ubo;
|
|
138
|
-
//
|
|
139
|
-
// now read on every upload, not only on a texture one.
|
|
115
|
+
// `getParameter` is a synchronous driver query; `limits()` runs per upload.
|
|
140
116
|
maxTextureDim;
|
|
141
117
|
debug = false;
|
|
142
118
|
instanceId = 0;
|
|
143
119
|
firstDrawSeen = new Set();
|
|
144
|
-
//
|
|
145
|
-
//
|
|
146
|
-
// check alone can't guard dispose().
|
|
120
|
+
// Never cleared: GL objects from before a loss stay invalid after restore,
|
|
121
|
+
// when isContextLost() already answers false.
|
|
147
122
|
contextWasLost = false;
|
|
148
123
|
contextLostListener = null;
|
|
149
124
|
contextRestoredListener = null;
|
|
@@ -156,9 +131,18 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
156
131
|
console.error(`[WebGL2Hal] GL error at "${label}": ${glErrorName(this.gl, err)}`);
|
|
157
132
|
}
|
|
158
133
|
}
|
|
159
|
-
|
|
134
|
+
/**
|
|
135
|
+
* Loads every pass's GLSL before the context is acquired, so a load that
|
|
136
|
+
* fails leaves the canvas free for Canvas2D.
|
|
137
|
+
*/
|
|
138
|
+
static async create(canvas, descriptors, sampleCount = 4) {
|
|
139
|
+
const glsl = await Promise.all(descriptors.map(async (d) => [d.id, await d.source.glsl()]));
|
|
140
|
+
return new WebGL2Hal(canvas, descriptors, new Map(glsl), sampleCount);
|
|
141
|
+
}
|
|
142
|
+
constructor(canvas, descriptors, glsl, sampleCount) {
|
|
160
143
|
super(descriptors, 'WebGL2Hal');
|
|
161
144
|
this.canvas = canvas;
|
|
145
|
+
this.glsl = glsl;
|
|
162
146
|
this.debug = debugEnabled();
|
|
163
147
|
totalCreated += 1;
|
|
164
148
|
this.instanceId = totalCreated;
|
|
@@ -178,23 +162,14 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
178
162
|
canvas.addEventListener('webglcontextrestored', onContextRestored, false);
|
|
179
163
|
this.contextLostListener = onContextLost;
|
|
180
164
|
this.contextRestoredListener = onContextRestored;
|
|
181
|
-
//
|
|
182
|
-
//
|
|
183
|
-
//
|
|
184
|
-
// (edge pixel: rgb = color*alpha, a = alpha). With premultipliedAlpha:true
|
|
185
|
-
// the browser compositor reads those as premultiplied and composites correctly:
|
|
186
|
-
// output = fb.rgb + bg*(1-fb.a)
|
|
187
|
-
// With premultipliedAlpha:false the compositor treats them as straight alpha and
|
|
188
|
-
// multiplies rgb by alpha a second time, making AA edges appear too dark.
|
|
189
|
-
// The WebGPU HAL uses alphaMode:'premultiplied' for the same reason.
|
|
165
|
+
// The blend leaves premultiplied values in the framebuffer, which a
|
|
166
|
+
// straight-alpha compositor would darken at AA edges; WebGPU's alphaMode
|
|
167
|
+
// matches.
|
|
190
168
|
const gl = canvas.getContext('webgl2', {
|
|
191
|
-
antialias:
|
|
169
|
+
antialias: sampleCount > 1,
|
|
192
170
|
premultipliedAlpha: true,
|
|
193
171
|
});
|
|
194
172
|
if (!gl) {
|
|
195
|
-
// Was a bare 'WebGL2 not supported', which is the wrong diagnosis for the
|
|
196
|
-
// case that actually reaches here in production: a re-init on a canvas the
|
|
197
|
-
// WebGPU rung already committed. See canvasContext.ts.
|
|
198
173
|
throw canvasContextError(canvas, 'webgl2');
|
|
199
174
|
}
|
|
200
175
|
noteCanvasContext(canvas, 'webgl2');
|
|
@@ -202,30 +177,21 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
202
177
|
this.maxTextureDim = Number(gl.getParameter(gl.MAX_TEXTURE_SIZE));
|
|
203
178
|
this.ubo = gl.createBuffer();
|
|
204
179
|
gl.bindBuffer(gl.UNIFORM_BUFFER, this.ubo);
|
|
205
|
-
gl.bufferData(gl.UNIFORM_BUFFER, uniformByteSize, gl.DYNAMIC_DRAW);
|
|
206
|
-
|
|
207
|
-
//
|
|
208
|
-
//
|
|
209
|
-
// most of them behind a colorBy/arc/per-base setting — and linking one
|
|
210
|
-
// costs tens of ms of driver time on the main thread. A profile of a
|
|
211
|
-
// three-track LGV linked 29 programs and drew with 14.
|
|
212
|
-
//
|
|
213
|
-
// The first descriptor still links eagerly as a canary, so a GL stack that
|
|
214
|
-
// can't compile our shaders at all throws from the constructor and
|
|
215
|
-
// `createGpuHal` falls back to Canvas2D — the ladder only runs at
|
|
216
|
-
// construction. Per-pass compile failures after that are caught in
|
|
217
|
-
// `getPass` and surfaced through the error handler.
|
|
180
|
+
gl.bufferData(gl.UNIFORM_BUFFER, this.uniformByteSize, gl.DYNAMIC_DRAW);
|
|
181
|
+
// Programs link on first draw (`getPass`). The first links here as a
|
|
182
|
+
// canary, so a GL stack that cannot compile our shaders throws while
|
|
183
|
+
// `createGpuHal` can still fall back to Canvas2D.
|
|
218
184
|
const canary = descriptors[0];
|
|
219
185
|
if (canary) {
|
|
220
|
-
this.
|
|
186
|
+
this.passes.set(canary.id, {
|
|
187
|
+
descriptor: canary,
|
|
188
|
+
linked: this.link(canary),
|
|
189
|
+
});
|
|
221
190
|
}
|
|
222
191
|
gl.enable(gl.BLEND);
|
|
223
192
|
}
|
|
224
|
-
//
|
|
225
|
-
//
|
|
226
|
-
// is WebGPU's. Past it, an unguarded bufferData loses the context in Chrome
|
|
227
|
-
// and throws RangeError in Firefox; neither is a getError() case, so the
|
|
228
|
-
// base's report is the only place the display can be told.
|
|
193
|
+
// Past the ceiling an unguarded bufferData loses the context in Chrome and
|
|
194
|
+
// throws in Firefox, neither of them a getError() case.
|
|
229
195
|
limits() {
|
|
230
196
|
return {
|
|
231
197
|
maxBufferBytes: MAX_VERTEX_BUFFER_BYTES,
|
|
@@ -239,28 +205,55 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
239
205
|
gl.bufferData(gl.ARRAY_BUFFER, data, gl.STATIC_DRAW);
|
|
240
206
|
return { vbo, count };
|
|
241
207
|
}
|
|
242
|
-
// No mid-frame deferral, unlike `WebGPUHal
|
|
243
|
-
//
|
|
244
|
-
// beginFrame and endFrame is defined. The parity that matters is the
|
|
245
|
-
// caller's — the same upload sequence is legal on both.
|
|
208
|
+
// No mid-frame deferral, unlike `WebGPUHal`: GL is immediate-mode, so a draw
|
|
209
|
+
// already issued has consumed the buffer.
|
|
246
210
|
destroyBuffer(buf) {
|
|
247
211
|
const gl = this.gl;
|
|
248
212
|
if (!this.contextWasLost && !gl.isContextLost()) {
|
|
249
213
|
gl.deleteBuffer(buf.vbo);
|
|
250
214
|
}
|
|
251
215
|
}
|
|
252
|
-
|
|
216
|
+
// Throws on a failed link, and again on every later ask for that content.
|
|
217
|
+
link(desc) {
|
|
253
218
|
const gl = this.gl;
|
|
254
|
-
const
|
|
219
|
+
const stages = this.glsl.get(desc.id);
|
|
220
|
+
if (!stages) {
|
|
221
|
+
throw new Error(`no GLSL was loaded for pass "${desc.id}"`);
|
|
222
|
+
}
|
|
223
|
+
const { GLSL_VERTEX, GLSL_FRAGMENT } = stages;
|
|
224
|
+
const textures = desc.textures ?? [];
|
|
225
|
+
const names = desc.vertexAttributes.map(attr => attr.name);
|
|
226
|
+
const samplers = textures.map(t => [t.glUniformName, t.glTextureUnit]);
|
|
227
|
+
const key = JSON.stringify([GLSL_FRAGMENT, names, samplers]);
|
|
228
|
+
let byVertex = this.programs.get(GLSL_VERTEX);
|
|
229
|
+
if (!byVertex) {
|
|
230
|
+
byVertex = new Map();
|
|
231
|
+
this.programs.set(GLSL_VERTEX, byVertex);
|
|
232
|
+
}
|
|
233
|
+
const known = byVertex.get(key);
|
|
234
|
+
if (known instanceof Error) {
|
|
235
|
+
throw known;
|
|
236
|
+
}
|
|
237
|
+
if (known) {
|
|
238
|
+
return known;
|
|
239
|
+
}
|
|
240
|
+
let program;
|
|
241
|
+
try {
|
|
242
|
+
program = createProgram(gl, GLSL_VERTEX, GLSL_FRAGMENT);
|
|
243
|
+
}
|
|
244
|
+
catch (e) {
|
|
245
|
+
byVertex.set(key, e instanceof Error ? e : new Error(String(e)));
|
|
246
|
+
throw e;
|
|
247
|
+
}
|
|
255
248
|
bindUniformBlock(gl, program, 'Uniforms', 0);
|
|
256
249
|
this.checkGlError(`link pass "${desc.id}"`);
|
|
257
|
-
const attrLocs =
|
|
250
|
+
const attrLocs = names.map(name => gl.getAttribLocation(program, name));
|
|
258
251
|
if (this.debug) {
|
|
259
|
-
const pairs =
|
|
252
|
+
const pairs = names.map((name, i) => `${name}@${attrLocs[i]}`);
|
|
260
253
|
console.warn(`[WebGL2Hal] pass "${desc.id}" stride=${desc.instanceStride} attrs: ${pairs.join(', ')}`);
|
|
261
|
-
const missing =
|
|
254
|
+
const missing = names.filter((_, i) => attrLocs[i] < 0);
|
|
262
255
|
if (missing.length > 0) {
|
|
263
|
-
console.warn(`[WebGL2Hal] pass "${desc.id}" missing attribute locations: ${missing.
|
|
256
|
+
console.warn(`[WebGL2Hal] pass "${desc.id}" missing attribute locations: ${missing.join(', ')}`);
|
|
264
257
|
}
|
|
265
258
|
}
|
|
266
259
|
const vao = gl.createVertexArray();
|
|
@@ -272,26 +265,16 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
272
265
|
}
|
|
273
266
|
}
|
|
274
267
|
gl.bindVertexArray(null);
|
|
275
|
-
|
|
276
|
-
const tb = desc.textures?.[0];
|
|
277
|
-
if (tb) {
|
|
278
|
-
// Bind the sampler uniform to the texture unit once — it never changes.
|
|
268
|
+
if (textures.length > 0) {
|
|
279
269
|
gl.useProgram(program);
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
textureState,
|
|
288
|
-
attrLocs,
|
|
289
|
-
};
|
|
290
|
-
this.passes.set(desc.id, state);
|
|
291
|
-
return state;
|
|
270
|
+
for (const tb of textures) {
|
|
271
|
+
gl.uniform1i(gl.getUniformLocation(program, tb.glUniformName), tb.glTextureUnit);
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
const linked = { program, vao, attrLocs };
|
|
275
|
+
byVertex.set(key, linked);
|
|
276
|
+
return linked;
|
|
292
277
|
}
|
|
293
|
-
// Compiled pass for `passId`, building it the first time it's asked for.
|
|
294
|
-
// Returns undefined for an unknown id or a pass whose program failed to link.
|
|
295
278
|
getPass(passId) {
|
|
296
279
|
const existing = this.passes.get(passId);
|
|
297
280
|
if (existing !== undefined) {
|
|
@@ -302,7 +285,9 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
302
285
|
return undefined;
|
|
303
286
|
}
|
|
304
287
|
try {
|
|
305
|
-
|
|
288
|
+
const pass = { descriptor: desc, linked: this.link(desc) };
|
|
289
|
+
this.passes.set(passId, pass);
|
|
290
|
+
return pass;
|
|
306
291
|
}
|
|
307
292
|
catch (e) {
|
|
308
293
|
this.passes.set(passId, null);
|
|
@@ -311,26 +296,50 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
311
296
|
}
|
|
312
297
|
}
|
|
313
298
|
resize(width, height) {
|
|
299
|
+
// A render autorun can fire between `dispose` and the model dropping its
|
|
300
|
+
// backend reference, and nothing destroys what a disposed HAL allocates.
|
|
301
|
+
if (this.disposed) {
|
|
302
|
+
return { x: getDpr(), y: getDpr() };
|
|
303
|
+
}
|
|
314
304
|
return syncCanvasSize(this.canvas, width, height).scale;
|
|
315
305
|
}
|
|
306
|
+
/**
|
|
307
|
+
* Nothing to give back. WebGL2 multisamples in the drawing buffer the context
|
|
308
|
+
* owns (`antialias` above one sample), so this HAL holds no separate target —
|
|
309
|
+
* releasing its samples means dropping the context, which costs a re-acquire
|
|
310
|
+
* against a hard 16-context ceiling and a full shader recompile per display.
|
|
311
|
+
* `agent-docs/reference/GPU_CONTEXT_BUDGET.md` measured that trade and
|
|
312
|
+
* declined it; what makes the WebGPU side worth doing is that it pays
|
|
313
|
+
* neither.
|
|
314
|
+
*/
|
|
315
|
+
releaseRenderTargets() { }
|
|
316
316
|
createTexture(passId, binding, data, width, height) {
|
|
317
317
|
const gl = this.gl;
|
|
318
|
-
|
|
319
|
-
if (!
|
|
320
|
-
|
|
318
|
+
let byName = this.passTextures.get(passId);
|
|
319
|
+
if (!byName) {
|
|
320
|
+
byName = new Map();
|
|
321
|
+
this.passTextures.set(passId, byName);
|
|
321
322
|
}
|
|
322
|
-
|
|
323
|
-
|
|
323
|
+
const existing = byName.get(binding.name);
|
|
324
|
+
if (existing) {
|
|
325
|
+
gl.deleteTexture(existing);
|
|
324
326
|
}
|
|
325
327
|
const tex = gl.createTexture();
|
|
326
328
|
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
327
|
-
|
|
329
|
+
if (data instanceof Uint8Array) {
|
|
330
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
331
|
+
}
|
|
332
|
+
else {
|
|
333
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, true);
|
|
334
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, data);
|
|
335
|
+
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
|
|
336
|
+
}
|
|
328
337
|
const filter = binding.filter === 'linear' ? gl.LINEAR : gl.NEAREST;
|
|
329
338
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, filter);
|
|
330
339
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, filter);
|
|
331
340
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
|
|
332
341
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
|
|
333
|
-
|
|
342
|
+
byName.set(binding.name, tex);
|
|
334
343
|
}
|
|
335
344
|
writeUniforms(data) {
|
|
336
345
|
const gl = this.gl;
|
|
@@ -360,10 +369,9 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
360
369
|
clearViewport() {
|
|
361
370
|
this.gl.viewport(0, 0, this.canvas.width, this.canvas.height);
|
|
362
371
|
}
|
|
363
|
-
drawPass(passId, regionKey, bufferPassId) {
|
|
372
|
+
drawPass(passId, regionKey, bufferPassId, verticesPerInstance) {
|
|
364
373
|
const gl = this.gl;
|
|
365
|
-
// Buffer first,
|
|
366
|
-
// the reason its shader gets compiled.
|
|
374
|
+
// Buffer first, so a pass with nothing to draw links no program.
|
|
367
375
|
const regionBuf = this.regions.get(regionKey, bufferPassId ?? passId);
|
|
368
376
|
if (!regionBuf || regionBuf.count === 0) {
|
|
369
377
|
return;
|
|
@@ -372,18 +380,26 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
372
380
|
if (!pass) {
|
|
373
381
|
return;
|
|
374
382
|
}
|
|
383
|
+
const textures = this.passTextures.get(passId);
|
|
384
|
+
const samplers = pass.descriptor.textures ?? NO_TEXTURES;
|
|
385
|
+
if (samplers.some(tb => !textures?.has(tb.name))) {
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
375
388
|
this.applyBlendState(pass.descriptor);
|
|
376
|
-
gl.useProgram(pass.program);
|
|
377
|
-
gl.bindVertexArray(pass.vao);
|
|
389
|
+
gl.useProgram(pass.linked.program);
|
|
390
|
+
gl.bindVertexArray(pass.linked.vao);
|
|
378
391
|
this.bindAttributes(pass, regionBuf.vbo);
|
|
379
|
-
|
|
392
|
+
for (const tb of samplers) {
|
|
393
|
+
gl.activeTexture(gl.TEXTURE0 + tb.glTextureUnit);
|
|
394
|
+
gl.bindTexture(gl.TEXTURE_2D, textures.get(tb.name));
|
|
395
|
+
}
|
|
380
396
|
const topo = pass.descriptor.topology ?? 'triangle-list';
|
|
381
397
|
const glMode = topo === 'triangle-strip'
|
|
382
398
|
? gl.TRIANGLE_STRIP
|
|
383
399
|
: topo === 'line-list'
|
|
384
400
|
? gl.LINES
|
|
385
401
|
: gl.TRIANGLES;
|
|
386
|
-
gl.drawArraysInstanced(glMode, 0, pass.descriptor.verticesPerInstance, regionBuf.count);
|
|
402
|
+
gl.drawArraysInstanced(glMode, 0, verticesPerInstance ?? pass.descriptor.verticesPerInstance, regionBuf.count);
|
|
387
403
|
if (this.debug && !this.firstDrawSeen.has(passId)) {
|
|
388
404
|
this.firstDrawSeen.add(passId);
|
|
389
405
|
const err = gl.getError();
|
|
@@ -402,10 +418,6 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
402
418
|
if (this.debug) {
|
|
403
419
|
console.warn(`[WebGL2Hal #${this.instanceId}] DISPOSING context (live=${totalCreated - totalDisposed}/${totalCreated})`);
|
|
404
420
|
}
|
|
405
|
-
// Remove canvas event listeners to prevent closure references from keeping
|
|
406
|
-
// the context alive after disposal. This is critical for test suites where
|
|
407
|
-
// multiple contexts are created in sequence (e.g. Puppeteer page navigation).
|
|
408
|
-
// Double-dispose is short-circuited above, so listeners are guaranteed set.
|
|
409
421
|
if (this.contextLostListener) {
|
|
410
422
|
this.canvas.removeEventListener('webglcontextlost', this.contextLostListener);
|
|
411
423
|
}
|
|
@@ -414,24 +426,26 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
414
426
|
}
|
|
415
427
|
this.regions.deleteAll();
|
|
416
428
|
if (!this.contextWasLost && !gl.isContextLost()) {
|
|
417
|
-
for (const
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
gl.deleteTexture(pass.textureState.texture);
|
|
429
|
+
for (const byVertex of this.programs.values()) {
|
|
430
|
+
for (const linked of byVertex.values()) {
|
|
431
|
+
if (!(linked instanceof Error)) {
|
|
432
|
+
gl.deleteVertexArray(linked.vao);
|
|
433
|
+
gl.deleteProgram(linked.program);
|
|
423
434
|
}
|
|
424
435
|
}
|
|
425
436
|
}
|
|
437
|
+
for (const byName of this.passTextures.values()) {
|
|
438
|
+
for (const texture of byName.values()) {
|
|
439
|
+
gl.deleteTexture(texture);
|
|
440
|
+
}
|
|
441
|
+
}
|
|
426
442
|
gl.deleteBuffer(this.ubo);
|
|
427
443
|
}
|
|
428
444
|
this.passes.clear();
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
//
|
|
432
|
-
//
|
|
433
|
-
// let the browser reclaim the context when the canvas is GC'd. If we
|
|
434
|
-
// need explicit release again, gate it on navigator.userAgent.
|
|
445
|
+
this.programs.clear();
|
|
446
|
+
this.passTextures.clear();
|
|
447
|
+
// No WEBGL_lose_context.loseContext(): Firefox treats it as a driver-wide
|
|
448
|
+
// reset that blanks sibling live contexts, so the canvas's GC reclaims it.
|
|
435
449
|
}
|
|
436
450
|
applyBlendState(desc) {
|
|
437
451
|
const gl = this.gl;
|
|
@@ -442,38 +456,30 @@ export class WebGL2Hal extends GpuHalBase {
|
|
|
442
456
|
gl.enable(gl.BLEND);
|
|
443
457
|
const bs = desc.blendState;
|
|
444
458
|
if (bs?.op === 'max') {
|
|
445
|
-
// MIN/MAX ignore blend factors: the framebuffer keeps the per-channel
|
|
446
|
-
// max(src, dst). Used by same-color AA lines so overlapping segments union
|
|
447
|
-
// instead of darkening. Reset explicitly below for every other pass.
|
|
448
459
|
gl.blendEquation(gl.MAX);
|
|
449
460
|
}
|
|
461
|
+
else if (bs?.op === 'min') {
|
|
462
|
+
gl.blendEquation(gl.MIN);
|
|
463
|
+
}
|
|
464
|
+
else if (bs?.op === 'behind') {
|
|
465
|
+
gl.blendEquation(gl.FUNC_ADD);
|
|
466
|
+
gl.blendFuncSeparate(gl.ONE_MINUS_DST_ALPHA, gl.ONE, gl.ONE_MINUS_DST_ALPHA, gl.ONE);
|
|
467
|
+
}
|
|
450
468
|
else {
|
|
451
469
|
gl.blendEquation(gl.FUNC_ADD);
|
|
452
|
-
//
|
|
453
|
-
//
|
|
454
|
-
// Alpha: out = src_alpha * 1 + dst_alpha * (1 - src_alpha)
|
|
455
|
-
// The alpha channel uses ONE/ONE_MINUS_SRC_ALPHA regardless of the custom blend state;
|
|
456
|
-
// using the RGB srcFactor for alpha too would give out_alpha = src_alpha² + ..., which is wrong.
|
|
470
|
+
// Alpha keeps ONE / ONE_MINUS_SRC_ALPHA whatever the RGB factors: the
|
|
471
|
+
// RGB srcFactor on alpha would square it.
|
|
457
472
|
const src = bs ? glBlendFactor(gl, bs.srcFactor) : gl.SRC_ALPHA;
|
|
458
473
|
const dst = bs ? glBlendFactor(gl, bs.dstFactor) : gl.ONE_MINUS_SRC_ALPHA;
|
|
459
474
|
gl.blendFuncSeparate(src, dst, gl.ONE, gl.ONE_MINUS_SRC_ALPHA);
|
|
460
475
|
}
|
|
461
476
|
}
|
|
462
|
-
bindTextures(pass) {
|
|
463
|
-
const gl = this.gl;
|
|
464
|
-
const ts = pass.textureState;
|
|
465
|
-
if (ts?.texture) {
|
|
466
|
-
gl.activeTexture(gl.TEXTURE0 + ts.unit);
|
|
467
|
-
gl.bindTexture(gl.TEXTURE_2D, ts.texture);
|
|
468
|
-
// sampler uniform set once at construction — no uniform1i here
|
|
469
|
-
}
|
|
470
|
-
}
|
|
471
477
|
bindAttributes(pass, vbo) {
|
|
472
478
|
const gl = this.gl;
|
|
473
479
|
const desc = pass.descriptor;
|
|
474
480
|
gl.bindBuffer(gl.ARRAY_BUFFER, vbo);
|
|
475
481
|
for (let i = 0; i < desc.vertexAttributes.length; i++) {
|
|
476
|
-
const loc = pass.attrLocs[i];
|
|
482
|
+
const loc = pass.linked.attrLocs[i];
|
|
477
483
|
if (loc < 0) {
|
|
478
484
|
continue;
|
|
479
485
|
}
|
package/esm/hal/webgpuHal.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { GpuHalBase } from './gpuHalBase.ts';
|
|
2
|
-
import type { GpuHal, PipelineDescriptor, SampleCount, TextureBinding } from './types.ts';
|
|
2
|
+
import type { GpuHal, PipelineDescriptor, SampleCount, TextureBinding, TextureSource } from './types.ts';
|
|
3
3
|
interface RegionPassBuffer {
|
|
4
4
|
dataBuffer: GPUBuffer;
|
|
5
5
|
count: number;
|
|
@@ -11,13 +11,13 @@ export declare class WebGPUHal extends GpuHalBase<RegionPassBuffer> implements G
|
|
|
11
11
|
private pipelines;
|
|
12
12
|
private passTextures;
|
|
13
13
|
private passBindGroups;
|
|
14
|
-
private layouts;
|
|
15
14
|
private alignedUniformSize;
|
|
16
15
|
private uniformRingBuffer;
|
|
17
16
|
private uniformStaging;
|
|
17
|
+
private uniformSlots;
|
|
18
18
|
private uniformSlot;
|
|
19
|
+
private outgrownRings;
|
|
19
20
|
private warnedUniformSlots;
|
|
20
|
-
private uniformOnlyBindGroup;
|
|
21
21
|
private sampleCount;
|
|
22
22
|
private msaaTexture;
|
|
23
23
|
private msaaView;
|
|
@@ -36,7 +36,7 @@ export declare class WebGPUHal extends GpuHalBase<RegionPassBuffer> implements G
|
|
|
36
36
|
* selection spanning two sections re-uploads `OVERLAY_REGION` once per
|
|
37
37
|
* section, inside the block loop.
|
|
38
38
|
*
|
|
39
|
-
* Deferring
|
|
39
|
+
* Deferring the destroy makes mid-frame replacement legal instead of merely
|
|
40
40
|
* warned about; synteny's `ensureUploaded` has always deleted a pass mid-frame
|
|
41
41
|
* that the open pass never referenced, and that case was never the bug.
|
|
42
42
|
*/
|
|
@@ -47,7 +47,14 @@ export declare class WebGPUHal extends GpuHalBase<RegionPassBuffer> implements G
|
|
|
47
47
|
private appliedViewport;
|
|
48
48
|
private warnedSwapChainLoss;
|
|
49
49
|
private swapChainUnrecoverable;
|
|
50
|
+
private reportedSurfaceFailure;
|
|
50
51
|
private constructor();
|
|
52
|
+
private createRing;
|
|
53
|
+
private bindUntexturedPasses;
|
|
54
|
+
private growRing;
|
|
55
|
+
private bindGroupLayoutOf;
|
|
56
|
+
private createBindGroup;
|
|
57
|
+
private bindingResource;
|
|
51
58
|
protected limits(): {
|
|
52
59
|
maxBufferBytes: number;
|
|
53
60
|
maxTextureDimensionPx: number;
|
|
@@ -66,8 +73,9 @@ export declare class WebGPUHal extends GpuHalBase<RegionPassBuffer> implements G
|
|
|
66
73
|
* configured context behind with nothing to release it.
|
|
67
74
|
*/
|
|
68
75
|
private configureContext;
|
|
69
|
-
static create(canvas: HTMLCanvasElement, descriptors: PipelineDescriptor[],
|
|
76
|
+
static create(canvas: HTMLCanvasElement, descriptors: PipelineDescriptor[], sampleCount: SampleCount): Promise<WebGPUHal | null>;
|
|
70
77
|
resize(width: number, height: number): import("./types.ts").CanvasScale;
|
|
78
|
+
releaseRenderTargets(): void;
|
|
71
79
|
private recreateMsaaTexture;
|
|
72
80
|
/**
|
|
73
81
|
* Bind group matching the pipeline layout of `passId`.
|
|
@@ -80,24 +88,23 @@ export declare class WebGPUHal extends GpuHalBase<RegionPassBuffer> implements G
|
|
|
80
88
|
* (and a dropped draw) the moment one side samples a texture.
|
|
81
89
|
*
|
|
82
90
|
* Nothing in a bind group varies per region either: it references the
|
|
83
|
-
* HAL-wide uniform ring buffer plus the pass's own texture/sampler.
|
|
84
|
-
*
|
|
85
|
-
*
|
|
86
|
-
* Returns undefined when a pass needs a texture that hasn't arrived yet;
|
|
87
|
-
* drawPass skips those.
|
|
91
|
+
* HAL-wide uniform ring buffer plus the pass's own texture/sampler. Returns
|
|
92
|
+
* undefined when a pass needs a texture that hasn't arrived yet; drawPass
|
|
93
|
+
* skips those.
|
|
88
94
|
*/
|
|
89
95
|
private getBindGroup;
|
|
96
|
+
private bindTexture;
|
|
90
97
|
/**
|
|
91
98
|
* The one place a GPU resource this HAL owns is released — see
|
|
92
99
|
* {@link pendingDestroy} for why the frame decides when.
|
|
93
100
|
*
|
|
94
101
|
* Every buffer release routes here through the `RegionRegistry` destroy hook,
|
|
95
|
-
* so `uploadBuffer`, `deleteBuffer`, `deleteRegion
|
|
102
|
+
* so `uploadBuffer`, `deleteBuffer`, `deleteRegion` and
|
|
96
103
|
* `dispose` are all covered without any of them knowing a frame is open.
|
|
97
104
|
*/
|
|
98
105
|
private destroyWhenIdle;
|
|
99
106
|
private drainPendingDestroy;
|
|
100
|
-
protected createTexture(passId: string, binding: TextureBinding, data:
|
|
107
|
+
protected createTexture(passId: string, binding: TextureBinding, data: TextureSource, width: number, height: number): void;
|
|
101
108
|
writeUniforms(data: ArrayBuffer): void;
|
|
102
109
|
/**
|
|
103
110
|
* The canvas texture to draw this frame into, or null when the swap chain is
|
|
@@ -120,8 +127,17 @@ export declare class WebGPUHal extends GpuHalBase<RegionPassBuffer> implements G
|
|
|
120
127
|
* Retry is what builds a fresh HAL.
|
|
121
128
|
*/
|
|
122
129
|
private acquireTextureView;
|
|
130
|
+
/**
|
|
131
|
+
* Once per HAL, not once per frame: the refusal holds for every frame at this
|
|
132
|
+
* canvas size, and dotplot and synteny keep their canvas mounted through a
|
|
133
|
+
* `renderError`, so a per-frame report there never stops.
|
|
134
|
+
*
|
|
135
|
+
* Not terminal — a refusal tracks the canvas dimensions, so a resize can clear
|
|
136
|
+
* it. `swapChainUnrecoverable` stays for the case it was written for.
|
|
137
|
+
*/
|
|
138
|
+
private reportSurfaceFailure;
|
|
123
139
|
beginFrame(clearR: number, clearG: number, clearB: number, clearA?: number): void;
|
|
124
|
-
drawPass(passId: string, regionKey: number, bufferPassId?: string): void;
|
|
140
|
+
drawPass(passId: string, regionKey: number, bufferPassId?: string, verticesPerInstance?: number): void;
|
|
125
141
|
/**
|
|
126
142
|
* Close the frame's state whether the submit landed or threw.
|
|
127
143
|
*
|