@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.
Files changed (352) hide show
  1. package/esm/RenderCanvas.d.ts +2 -2
  2. package/esm/RenderLifecycleMixin.d.ts +52 -20
  3. package/esm/RenderLifecycleMixin.js +89 -23
  4. package/esm/canvas2dUtils.d.ts +90 -23
  5. package/esm/canvas2dUtils.js +119 -36
  6. package/esm/colorRampLut.d.ts +5 -5
  7. package/esm/colorRampLut.js +6 -6
  8. package/esm/computePipeline.d.ts +14 -0
  9. package/esm/computePipeline.js +62 -0
  10. package/esm/contractReports.d.ts +54 -0
  11. package/esm/contractReports.js +112 -0
  12. package/esm/coverageBand.d.ts +13 -8
  13. package/esm/coverageBand.js +15 -5
  14. package/esm/coverageBandBuffers.d.ts +2 -9
  15. package/esm/coverageBandBuffers.js +1 -13
  16. package/esm/createRenderingBackend.d.ts +14 -18
  17. package/esm/createRenderingBackend.js +4 -2
  18. package/esm/displayPhase.d.ts +83 -104
  19. package/esm/displayPhase.js +42 -82
  20. package/esm/encodeMemo.d.ts +14 -0
  21. package/esm/encodeMemo.js +48 -0
  22. package/esm/gpuContextLostError.d.ts +30 -0
  23. package/esm/gpuContextLostError.js +40 -0
  24. package/esm/gpuDevice.d.ts +29 -10
  25. package/esm/gpuDevice.js +35 -16
  26. package/esm/graphicsCapabilities.d.ts +27 -19
  27. package/esm/graphicsCapabilities.js +40 -18
  28. package/esm/hal/createHal.d.ts +4 -5
  29. package/esm/hal/createHal.js +14 -4
  30. package/esm/hal/deviceGpuCache.d.ts +25 -30
  31. package/esm/hal/deviceGpuCache.js +88 -97
  32. package/esm/hal/gpuHalBase.d.ts +5 -4
  33. package/esm/hal/gpuHalBase.js +25 -14
  34. package/esm/hal/index.d.ts +2 -2
  35. package/esm/hal/index.js +1 -1
  36. package/esm/hal/mockHal.d.ts +15 -10
  37. package/esm/hal/mockHal.js +31 -18
  38. package/esm/hal/oomReporter.d.ts +7 -0
  39. package/esm/hal/oomReporter.js +10 -0
  40. package/esm/hal/passIds.d.ts +8 -7
  41. package/esm/hal/passIds.js +11 -10
  42. package/esm/hal/regionRegistry.d.ts +0 -1
  43. package/esm/hal/regionRegistry.js +3 -15
  44. package/esm/hal/types.d.ts +55 -18
  45. package/esm/hal/webgl2Hal.d.ts +23 -6
  46. package/esm/hal/webgl2Hal.js +161 -155
  47. package/esm/hal/webgpuHal.d.ts +29 -13
  48. package/esm/hal/webgpuHal.js +221 -153
  49. package/esm/installUpload.d.ts +16 -3
  50. package/esm/installUpload.js +13 -41
  51. package/esm/instanceCache.d.ts +10 -7
  52. package/esm/instanceCache.js +14 -15
  53. package/esm/instancePass.d.ts +2 -1
  54. package/esm/mapUploadSync.d.ts +2 -10
  55. package/esm/mapUploadSync.js +2 -3
  56. package/esm/marks/barMark.d.ts +30 -0
  57. package/esm/marks/barMark.js +149 -0
  58. package/esm/marks/colorFill.d.ts +17 -0
  59. package/esm/marks/colorFill.js +26 -0
  60. package/esm/marks/drawAgainstHit.d.ts +113 -0
  61. package/esm/marks/drawAgainstHit.js +407 -0
  62. package/esm/marks/ellipseDistance.d.ts +10 -0
  63. package/esm/marks/ellipseDistance.js +136 -0
  64. package/esm/marks/glyphPaint.d.ts +36 -0
  65. package/esm/marks/glyphPaint.js +77 -0
  66. package/esm/marks/index.d.ts +33 -0
  67. package/esm/marks/index.js +20 -0
  68. package/esm/marks/lineMark.d.ts +37 -0
  69. package/esm/marks/lineMark.js +416 -0
  70. package/esm/marks/linkMark.d.ts +76 -0
  71. package/esm/marks/linkMark.js +585 -0
  72. package/esm/marks/markBackend.d.ts +118 -0
  73. package/esm/marks/markBackend.js +196 -0
  74. package/esm/marks/markHit.d.ts +32 -0
  75. package/esm/marks/markHit.js +61 -0
  76. package/esm/marks/markInk.d.ts +18 -0
  77. package/esm/marks/markInk.js +71 -0
  78. package/esm/marks/markPaint.d.ts +14 -0
  79. package/esm/marks/markPaint.js +32 -0
  80. package/esm/marks/markPlan.d.ts +25 -0
  81. package/esm/marks/markPlan.js +20 -0
  82. package/esm/marks/markRamp.d.ts +72 -0
  83. package/esm/marks/markRamp.js +197 -0
  84. package/esm/marks/nearestMarkHit.d.ts +55 -0
  85. package/esm/marks/nearestMarkHit.js +158 -0
  86. package/esm/marks/pathRecorder.d.ts +14 -0
  87. package/esm/marks/pathRecorder.js +80 -0
  88. package/esm/marks/pointMark.d.ts +42 -0
  89. package/esm/marks/pointMark.js +125 -0
  90. package/esm/marks/rowLane.d.ts +39 -0
  91. package/esm/marks/rowLane.js +41 -0
  92. package/esm/marks/rowSpanIndex.d.ts +29 -0
  93. package/esm/marks/rowSpanIndex.js +141 -0
  94. package/esm/marks/rowTable.d.ts +41 -0
  95. package/esm/marks/rowTable.js +75 -0
  96. package/esm/marks/ruleMark.d.ts +21 -0
  97. package/esm/marks/ruleMark.js +91 -0
  98. package/esm/marks/spanMark.d.ts +42 -0
  99. package/esm/marks/spanMark.js +81 -0
  100. package/esm/marks/types.d.ts +261 -0
  101. package/esm/marks/types.js +175 -0
  102. package/esm/marks/valueScale.d.ts +23 -0
  103. package/esm/marks/valueScale.js +11 -0
  104. package/esm/namedReactions.d.ts +3 -4
  105. package/esm/namedReactions.js +3 -4
  106. package/esm/perRegionRenderingBackend.d.ts +21 -3
  107. package/esm/perRegionRenderingBackend.js +37 -3
  108. package/esm/regionDataMap.d.ts +2 -2
  109. package/esm/regionDataMap.js +25 -23
  110. package/esm/renderBlock.d.ts +14 -0
  111. package/esm/renderBlock.js +25 -0
  112. package/esm/renderingBackendBase.d.ts +20 -14
  113. package/esm/renderingBackendBase.js +12 -7
  114. package/esm/scoreScale.d.ts +27 -0
  115. package/esm/scoreScale.js +88 -0
  116. package/esm/shaders/barMark.generated.d.ts +3 -0
  117. package/esm/shaders/barMark.generated.js +7 -0
  118. package/esm/shaders/barMark.glsl.generated.d.ts +2 -0
  119. package/esm/shaders/barMark.glsl.generated.js +4 -0
  120. package/esm/shaders/barMark.iface.generated.d.ts +90 -0
  121. package/esm/shaders/barMark.iface.generated.js +205 -0
  122. package/esm/shaders/barMark.wgsl.generated.d.ts +1 -0
  123. package/esm/shaders/barMark.wgsl.generated.js +3 -0
  124. package/esm/shaders/capsule.js.generated.d.ts +1 -0
  125. package/esm/shaders/capsule.js.generated.js +11 -0
  126. package/esm/shaders/clipStrip.generated.d.ts +2 -0
  127. package/esm/shaders/clipStrip.generated.js +4 -0
  128. package/esm/shaders/clipStrip.js.generated.d.ts +1 -0
  129. package/esm/shaders/clipStrip.js.generated.js +21 -0
  130. package/esm/shaders/colorRampLut.js.generated.d.ts +1 -0
  131. package/esm/shaders/colorRampLut.js.generated.js +17 -0
  132. package/esm/shaders/coverageBar.generated.d.ts +2 -3
  133. package/esm/shaders/coverageBar.generated.js +4 -3
  134. package/esm/shaders/coverageBar.glsl.generated.d.ts +2 -0
  135. package/esm/shaders/coverageBar.glsl.generated.js +4 -0
  136. package/esm/shaders/coverageBar.iface.generated.js +1 -1
  137. package/esm/shaders/coverageBar.wgsl.generated.d.ts +1 -0
  138. package/esm/shaders/coverageBar.wgsl.generated.js +3 -0
  139. package/esm/shaders/coverageClip.generated.d.ts +3 -0
  140. package/esm/shaders/coverageClip.generated.js +7 -0
  141. package/esm/shaders/coverageClip.glsl.generated.d.ts +2 -0
  142. package/esm/shaders/coverageClip.glsl.generated.js +4 -0
  143. package/esm/shaders/coverageClip.iface.generated.d.ts +85 -0
  144. package/esm/shaders/coverageClip.iface.generated.js +114 -0
  145. package/esm/shaders/coverageClip.wgsl.generated.d.ts +1 -0
  146. package/esm/shaders/coverageClip.wgsl.generated.js +3 -0
  147. package/esm/shaders/coverageIndicator.generated.d.ts +2 -3
  148. package/esm/shaders/coverageIndicator.generated.js +4 -3
  149. package/esm/shaders/coverageIndicator.glsl.generated.d.ts +2 -0
  150. package/esm/shaders/coverageIndicator.glsl.generated.js +4 -0
  151. package/esm/shaders/coverageIndicator.iface.generated.js +1 -1
  152. package/esm/shaders/coverageIndicator.wgsl.generated.d.ts +1 -0
  153. package/esm/shaders/coverageIndicator.wgsl.generated.js +3 -0
  154. package/esm/shaders/coverageInterbase.generated.d.ts +2 -3
  155. package/esm/shaders/coverageInterbase.generated.js +4 -3
  156. package/esm/shaders/coverageInterbase.glsl.generated.d.ts +2 -0
  157. package/esm/shaders/coverageInterbase.glsl.generated.js +4 -0
  158. package/esm/shaders/coverageInterbase.iface.generated.js +1 -1
  159. package/esm/shaders/coverageInterbase.wgsl.generated.d.ts +1 -0
  160. package/esm/shaders/coverageInterbase.wgsl.generated.js +3 -0
  161. package/esm/shaders/coverageMod.generated.d.ts +2 -3
  162. package/esm/shaders/coverageMod.generated.js +4 -3
  163. package/esm/shaders/coverageMod.glsl.generated.d.ts +2 -0
  164. package/esm/shaders/coverageMod.glsl.generated.js +4 -0
  165. package/esm/shaders/coverageMod.iface.generated.js +1 -1
  166. package/esm/shaders/coverageMod.wgsl.generated.d.ts +1 -0
  167. package/esm/shaders/coverageMod.wgsl.generated.js +3 -0
  168. package/esm/shaders/coverageSnp.generated.d.ts +2 -3
  169. package/esm/shaders/coverageSnp.generated.js +4 -3
  170. package/esm/shaders/coverageSnp.glsl.generated.d.ts +2 -0
  171. package/esm/shaders/coverageSnp.glsl.generated.js +4 -0
  172. package/esm/shaders/coverageSnp.iface.generated.js +1 -1
  173. package/esm/shaders/coverageSnp.wgsl.generated.d.ts +1 -0
  174. package/esm/shaders/coverageSnp.wgsl.generated.js +3 -0
  175. package/esm/shaders/curveDistance.js.generated.d.ts +5 -0
  176. package/esm/shaders/curveDistance.js.generated.js +87 -0
  177. package/esm/shaders/hpmath.js.generated.d.ts +2 -1
  178. package/esm/shaders/hpmath.js.generated.js +5 -2
  179. package/esm/shaders/lineCenterMark.generated.d.ts +3 -0
  180. package/esm/shaders/lineCenterMark.generated.js +7 -0
  181. package/esm/shaders/lineCenterMark.glsl.generated.d.ts +2 -0
  182. package/esm/shaders/lineCenterMark.glsl.generated.js +4 -0
  183. package/esm/shaders/lineCenterMark.iface.generated.d.ts +104 -0
  184. package/esm/shaders/lineCenterMark.iface.generated.js +237 -0
  185. package/esm/shaders/lineCenterMark.wgsl.generated.d.ts +1 -0
  186. package/esm/shaders/lineCenterMark.wgsl.generated.js +3 -0
  187. package/esm/shaders/lineCommon.generated.d.ts +2 -0
  188. package/esm/shaders/lineCommon.generated.js +4 -0
  189. package/esm/shaders/lineStepMark.generated.d.ts +3 -0
  190. package/esm/shaders/lineStepMark.generated.js +7 -0
  191. package/esm/shaders/lineStepMark.glsl.generated.d.ts +2 -0
  192. package/esm/shaders/lineStepMark.glsl.generated.js +4 -0
  193. package/esm/shaders/lineStepMark.iface.generated.d.ts +98 -0
  194. package/esm/shaders/lineStepMark.iface.generated.js +225 -0
  195. package/esm/shaders/lineStepMark.wgsl.generated.d.ts +1 -0
  196. package/esm/shaders/lineStepMark.wgsl.generated.js +3 -0
  197. package/esm/shaders/linkMark.consts.generated.d.ts +14 -0
  198. package/esm/shaders/linkMark.consts.generated.js +16 -0
  199. package/esm/shaders/linkMark.generated.d.ts +4 -0
  200. package/esm/shaders/linkMark.generated.js +8 -0
  201. package/esm/shaders/linkMark.glsl.generated.d.ts +2 -0
  202. package/esm/shaders/linkMark.glsl.generated.js +4 -0
  203. package/esm/shaders/linkMark.iface.generated.d.ts +142 -0
  204. package/esm/shaders/linkMark.iface.generated.js +1829 -0
  205. package/esm/shaders/linkMark.js.generated.d.ts +7 -0
  206. package/esm/shaders/linkMark.js.generated.js +159 -0
  207. package/esm/shaders/linkMark.wgsl.generated.d.ts +1 -0
  208. package/esm/shaders/linkMark.wgsl.generated.js +3 -0
  209. package/esm/shaders/markColor.generated.d.ts +9 -0
  210. package/esm/shaders/markColor.generated.js +11 -0
  211. package/esm/shaders/pointGlyph.js.generated.d.ts +2 -0
  212. package/esm/shaders/pointGlyph.js.generated.js +15 -0
  213. package/esm/shaders/pointMark.consts.generated.d.ts +7 -0
  214. package/esm/shaders/pointMark.consts.generated.js +9 -0
  215. package/esm/shaders/pointMark.generated.d.ts +4 -0
  216. package/esm/shaders/pointMark.generated.js +8 -0
  217. package/esm/shaders/pointMark.glsl.generated.d.ts +2 -0
  218. package/esm/shaders/pointMark.glsl.generated.js +4 -0
  219. package/esm/shaders/pointMark.iface.generated.d.ts +98 -0
  220. package/esm/shaders/pointMark.iface.generated.js +219 -0
  221. package/esm/shaders/pointMark.js.generated.d.ts +3 -0
  222. package/esm/shaders/pointMark.js.generated.js +93 -0
  223. package/esm/shaders/pointMark.wgsl.generated.d.ts +1 -0
  224. package/esm/shaders/pointMark.wgsl.generated.js +3 -0
  225. package/esm/shaders/rowRect.generated.d.ts +0 -1
  226. package/esm/shaders/rowRect.generated.js +0 -1
  227. package/esm/shaders/rowTable.generated.d.ts +1 -0
  228. package/esm/shaders/rowTable.generated.js +3 -0
  229. package/esm/shaders/rowTable.js.generated.d.ts +5 -0
  230. package/esm/shaders/rowTable.js.generated.js +29 -0
  231. package/esm/shaders/scoreScale.generated.d.ts +2 -0
  232. package/esm/shaders/scoreScale.generated.js +4 -0
  233. package/esm/shaders/scoreScale.js.generated.d.ts +1 -0
  234. package/esm/shaders/scoreScale.js.generated.js +50 -23
  235. package/esm/shaders/spanMark.generated.d.ts +3 -0
  236. package/esm/shaders/spanMark.generated.js +7 -0
  237. package/esm/shaders/spanMark.glsl.generated.d.ts +2 -0
  238. package/esm/shaders/spanMark.glsl.generated.js +4 -0
  239. package/esm/shaders/spanMark.iface.generated.d.ts +81 -0
  240. package/esm/shaders/spanMark.iface.generated.js +215 -0
  241. package/esm/shaders/spanMark.wgsl.generated.d.ts +1 -0
  242. package/esm/shaders/spanMark.wgsl.generated.js +3 -0
  243. package/esm/sharedBackendKey.d.ts +18 -0
  244. package/esm/{keyedRenderingBackend.js → sharedBackendKey.js} +5 -0
  245. package/esm/slangPass.d.ts +18 -11
  246. package/esm/slangPass.js +12 -4
  247. package/esm/useGraphicsCapabilities.d.ts +1 -1
  248. package/esm/useGraphicsCapabilities.js +1 -1
  249. package/esm/useRenderingBackend.d.ts +13 -13
  250. package/esm/useRenderingBackend.js +58 -20
  251. package/esm/webgpuUtils.d.ts +3 -11
  252. package/esm/webgpuUtils.js +12 -33
  253. package/package.json +32 -7
  254. package/src/shaders/antialias.slang +46 -0
  255. package/src/shaders/arcHull.test.ts +267 -0
  256. package/src/shaders/barMark.generated.ts +11 -0
  257. package/src/shaders/barMark.glsl.generated.ts +6 -0
  258. package/src/shaders/barMark.iface.generated.ts +285 -0
  259. package/src/shaders/barMark.slang +167 -0
  260. package/src/shaders/barMark.wgsl.generated.ts +4 -0
  261. package/src/shaders/capsule.js.generated.ts +14 -0
  262. package/src/shaders/capsule.slang +12 -4
  263. package/src/shaders/clipStrip.generated.ts +6 -0
  264. package/src/shaders/clipStrip.js.generated.ts +22 -0
  265. package/src/shaders/clipStrip.slang +34 -0
  266. package/src/shaders/clipStrip.test.ts +39 -0
  267. package/src/shaders/colorPack.slang +5 -1
  268. package/src/shaders/colorRampLut.js.generated.ts +22 -0
  269. package/src/shaders/colorRampLut.slang +15 -1
  270. package/src/shaders/coverageBand.slang +64 -32
  271. package/src/shaders/coverageBar.generated.ts +6 -5
  272. package/src/shaders/coverageBar.glsl.generated.ts +6 -0
  273. package/src/shaders/coverageBar.iface.generated.ts +1 -1
  274. package/src/shaders/coverageBar.slang +10 -10
  275. package/src/shaders/coverageBar.wgsl.generated.ts +4 -0
  276. package/src/shaders/coverageClip.generated.ts +11 -0
  277. package/src/shaders/coverageClip.glsl.generated.ts +6 -0
  278. package/src/shaders/coverageClip.iface.generated.ts +172 -0
  279. package/src/shaders/coverageClip.slang +38 -0
  280. package/src/shaders/coverageClip.wgsl.generated.ts +4 -0
  281. package/src/shaders/coverageIndicator.generated.ts +6 -5
  282. package/src/shaders/coverageIndicator.glsl.generated.ts +6 -0
  283. package/src/shaders/coverageIndicator.iface.generated.ts +1 -1
  284. package/src/shaders/coverageIndicator.wgsl.generated.ts +4 -0
  285. package/src/shaders/coverageInterbase.generated.ts +6 -5
  286. package/src/shaders/coverageInterbase.glsl.generated.ts +6 -0
  287. package/src/shaders/coverageInterbase.iface.generated.ts +1 -1
  288. package/src/shaders/coverageInterbase.wgsl.generated.ts +4 -0
  289. package/src/shaders/coverageMod.generated.ts +6 -5
  290. package/src/shaders/coverageMod.glsl.generated.ts +6 -0
  291. package/src/shaders/coverageMod.iface.generated.ts +1 -1
  292. package/src/shaders/coverageMod.wgsl.generated.ts +4 -0
  293. package/src/shaders/coverageSnp.generated.ts +6 -5
  294. package/src/shaders/coverageSnp.glsl.generated.ts +6 -0
  295. package/src/shaders/coverageSnp.iface.generated.ts +1 -1
  296. package/src/shaders/coverageSnp.wgsl.generated.ts +4 -0
  297. package/src/shaders/curveDistance.js.generated.ts +91 -0
  298. package/src/shaders/curveDistance.slang +265 -0
  299. package/src/shaders/hpClampFloor.test.ts +87 -0
  300. package/src/shaders/hpmath.js.generated.ts +6 -2
  301. package/src/shaders/hpmath.slang +100 -48
  302. package/src/shaders/insetValueScale.test.ts +67 -0
  303. package/src/shaders/lineCenterMark.generated.ts +11 -0
  304. package/src/shaders/lineCenterMark.glsl.generated.ts +6 -0
  305. package/src/shaders/lineCenterMark.iface.generated.ts +328 -0
  306. package/src/shaders/lineCenterMark.slang +127 -0
  307. package/src/shaders/lineCenterMark.wgsl.generated.ts +4 -0
  308. package/src/shaders/lineCommon.generated.ts +6 -0
  309. package/src/shaders/lineCommon.slang +102 -0
  310. package/src/shaders/lineStepMark.generated.ts +11 -0
  311. package/src/shaders/lineStepMark.glsl.generated.ts +6 -0
  312. package/src/shaders/lineStepMark.iface.generated.ts +311 -0
  313. package/src/shaders/lineStepMark.slang +125 -0
  314. package/src/shaders/lineStepMark.wgsl.generated.ts +4 -0
  315. package/src/shaders/linkMark.consts.generated.ts +30 -0
  316. package/src/shaders/linkMark.generated.ts +12 -0
  317. package/src/shaders/linkMark.glsl.generated.ts +6 -0
  318. package/src/shaders/linkMark.iface.generated.ts +1954 -0
  319. package/src/shaders/linkMark.js.generated.ts +167 -0
  320. package/src/shaders/linkMark.slang +439 -0
  321. package/src/shaders/linkMark.wgsl.generated.ts +4 -0
  322. package/src/shaders/markColor.generated.ts +20 -0
  323. package/src/shaders/markColor.slang +128 -0
  324. package/src/shaders/pointGlyph.js.generated.ts +20 -0
  325. package/src/shaders/pointGlyph.slang +23 -7
  326. package/src/shaders/pointGlyphPad.test.ts +242 -0
  327. package/src/shaders/pointMark.consts.generated.ts +16 -0
  328. package/src/shaders/pointMark.generated.ts +12 -0
  329. package/src/shaders/pointMark.glsl.generated.ts +6 -0
  330. package/src/shaders/pointMark.iface.generated.ts +304 -0
  331. package/src/shaders/pointMark.js.generated.ts +99 -0
  332. package/src/shaders/pointMark.slang +227 -0
  333. package/src/shaders/pointMark.wgsl.generated.ts +4 -0
  334. package/src/shaders/rowRect.generated.ts +0 -2
  335. package/src/shaders/rowRect.slang +39 -58
  336. package/src/shaders/rowTable.generated.ts +4 -0
  337. package/src/shaders/rowTable.js.generated.ts +37 -0
  338. package/src/shaders/rowTable.slang +98 -0
  339. package/src/shaders/scoreScale.generated.ts +6 -0
  340. package/src/shaders/scoreScale.js.generated.ts +48 -23
  341. package/src/shaders/scoreScale.slang +49 -55
  342. package/src/shaders/sdEllipse.test.ts +211 -0
  343. package/src/shaders/spanMark.generated.ts +11 -0
  344. package/src/shaders/spanMark.glsl.generated.ts +6 -0
  345. package/src/shaders/spanMark.iface.generated.ts +289 -0
  346. package/src/shaders/spanMark.slang +77 -0
  347. package/src/shaders/spanMark.wgsl.generated.ts +4 -0
  348. package/src/shaders/valueScale.slang +26 -0
  349. package/src/shaders/wideCircleLeg.test.ts +85 -0
  350. package/esm/globalRenderingBackend.d.ts +0 -90
  351. package/esm/globalRenderingBackend.js +0 -53
  352. package/esm/keyedRenderingBackend.d.ts +0 -41
@@ -0,0 +1,261 @@
1
+ import type { BlockClipResult } from '../blockClipUtils.ts';
2
+ import type { ClipContext2D } from '../canvas2dUtils.ts';
3
+ import type { GpuHal } from '../hal/index.ts';
4
+ import type { InstancePass } from '../instancePass.ts';
5
+ import type { RenderBlock } from '../renderBlock.ts';
6
+ import type { FrameDimensions } from '../renderingBackendBase.ts';
7
+ /**
8
+ * The 2D-context subset a shape's painter needs, which both a canvas and
9
+ * `@jbrowse/core`'s `SvgCanvas` satisfy: one painter is the fallback and the
10
+ * SVG export.
11
+ */
12
+ export interface MarkContext2D extends ClipContext2D {
13
+ fillStyle: string | CanvasGradient | CanvasPattern;
14
+ strokeStyle: string | CanvasGradient | CanvasPattern;
15
+ lineWidth: number;
16
+ lineCap?: CanvasLineCap;
17
+ lineJoin?: CanvasLineJoin;
18
+ fillRect(x: number, y: number, w: number, h: number): void;
19
+ strokeRect(x: number, y: number, w: number, h: number): void;
20
+ translate(x: number, y: number): void;
21
+ scale(x: number, y: number): void;
22
+ rotate(angle: number): void;
23
+ moveTo(x: number, y: number): void;
24
+ lineTo(x: number, y: number): void;
25
+ bezierCurveTo(cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number): void;
26
+ arc(x: number, y: number, radius: number, startAngle: number, endAngle: number, counterclockwise?: boolean): void;
27
+ ellipse(x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number): void;
28
+ setLineDash(segments: number[]): void;
29
+ closePath(): void;
30
+ fill(): void;
31
+ stroke(): void;
32
+ drawImage?(image: CanvasImageSource, sx: number, sy: number, sw: number, sh: number, dx: number, dy: number, dw: number, dh: number): void;
33
+ }
34
+ /**
35
+ * A canvas a mark's pass samples in place of a colour ramp. Hand a fresh object
36
+ * per repaint: the backend uploads on identity.
37
+ */
38
+ export interface MarkImage {
39
+ image: HTMLCanvasElement | OffscreenCanvas;
40
+ width: number;
41
+ height: number;
42
+ }
43
+ /**
44
+ * RGBA8 texels with their dimensions: a table a pass samples, such as a row
45
+ * table. Hand a fresh object per change: the backend uploads on identity.
46
+ */
47
+ export interface MarkTexels {
48
+ bytes: Uint8Array;
49
+ width: number;
50
+ height: number;
51
+ }
52
+ /** What a mark's pass binds: a 256-entry RGBA ramp, a canvas, or texels. */
53
+ export type MarkTexture = Uint8Array | MarkImage | MarkTexels;
54
+ /**
55
+ * A pass's textures by the sampler that reads each: `colorRamp`, `rowTable`,
56
+ * a ring's `strip`. A sampler left out, or answered undefined, keeps what it
57
+ * holds.
58
+ */
59
+ export type MarkTextures = Readonly<Record<string, MarkTexture | undefined>>;
60
+ export type MarkFrame = FrameDimensions;
61
+ export type MarkValueScaleType = 'linear' | 'log' | 'symlog';
62
+ /**
63
+ * The colour scale a ramp channel's raw `colorValue`s resolve through each
64
+ * frame, with the 256-entry RGBA LUT the pass's sampler binds: straight, its
65
+ * middle stop at the middle, and `mid`, where a diverging ramp puts that stop,
66
+ * read through a uniform.
67
+ */
68
+ export interface MarkRamp {
69
+ domain: [number, number];
70
+ scale: 'linear' | 'log';
71
+ lut: Uint8Array;
72
+ /** The value the ramp's middle stop sits at; the domain's middle when absent. */
73
+ mid?: number;
74
+ }
75
+ /**
76
+ * A threshold a value channel's raw `colorValue`s resolve through each frame:
77
+ * the ascending cut points, at most `MAX_COLOR_CUTS` of them, and one packed
78
+ * ABGR per interval between them, `cuts.length + 1` in all. The cuts and
79
+ * colours ride uniforms, so an edit moves them and uploads no instance bytes.
80
+ */
81
+ export interface MarkThreshold {
82
+ cuts: readonly number[];
83
+ colors: Uint32Array;
84
+ }
85
+ /** The scale a quantitative colour channel resolves through: a ramp or a threshold. */
86
+ export type MarkColorScale = MarkRamp | MarkThreshold;
87
+ /** A horizontal strip of the canvas, in CSS px down from its top edge. */
88
+ export interface MarkBand {
89
+ top: number;
90
+ height: number;
91
+ }
92
+ /** Where a shape's ink sits nearest a cursor, and how far that is. */
93
+ export interface MarkHit {
94
+ index: number;
95
+ x: number;
96
+ y: number;
97
+ distSq: number;
98
+ }
99
+ /** An axis-aligned box of the canvas, in CSS px. */
100
+ export interface InkRect {
101
+ left: number;
102
+ top: number;
103
+ width: number;
104
+ height: number;
105
+ /**
106
+ * The ink as a stroked path, for a shape whose box is mostly empty space (a
107
+ * link's curve): a highlight strokes it, clipped to the box.
108
+ */
109
+ stroke?: InkStroke;
110
+ }
111
+ /**
112
+ * An SVG path `d` in canvas px, the width the shape strokes it at, and where
113
+ * the canvas origin sits in the frame the box is in, which `shiftInk` moves
114
+ * with the box.
115
+ */
116
+ export interface InkStroke {
117
+ d: string;
118
+ widthPx: number;
119
+ originX: number;
120
+ originY: number;
121
+ }
122
+ /**
123
+ * A shape: one `.slang` pass, a uniform writer and a Canvas2D painter over the
124
+ * same channel arrays, and the geometry its hit test reads. `TParams` reaches
125
+ * the GPU as uniforms and the painter as arguments, so both backends draw the
126
+ * same values.
127
+ */
128
+ export interface MarkShape<TChannels, TParams> {
129
+ readonly id: string;
130
+ readonly pass: InstancePass<TChannels>;
131
+ /**
132
+ * Draws over the whole canvas from every loaded region's payload, after the
133
+ * blocks and unclipped to any block's column, each region's instances placed
134
+ * through a canvas-wide block of its own: a link, whose curve crosses regions
135
+ * holding neither foot.
136
+ */
137
+ readonly spansView?: boolean;
138
+ writeUniforms(scratch: ArrayBuffer, clip: BlockClipResult, block: RenderBlock, frame: MarkFrame, params: TParams): void;
139
+ paintBlock(ctx: MarkContext2D, channels: TChannels, block: RenderBlock, frame: MarkFrame, params: TParams): void;
140
+ /**
141
+ * Whether the block carries any ink under these params. Both backends and the
142
+ * hit test skip a block it declines.
143
+ */
144
+ paintsBlock?(block: RenderBlock, frame: MarkFrame, params: TParams): boolean;
145
+ /**
146
+ * Slots the GPU addresses per instance this frame, where the pass's
147
+ * registered count is a worst case over canvas widths. The canvas chevron
148
+ * pass shades a slot per chevron a line could put on screen, which is the
149
+ * canvas width over the chevron pitch — a tenth of its registered budget at a
150
+ * laptop width, and every surplus slot is a vertex invocation that runs the
151
+ * whole placement before culling itself.
152
+ */
153
+ verticesPerInstance?(frame: MarkFrame, params: TParams): number;
154
+ /**
155
+ * The textures the pass samples that the params the painter and the hit
156
+ * test read decide (`span`'s row table), so the two backends cannot be
157
+ * handed different tables. A display's own `textures` lens wins for a
158
+ * sampler it answers.
159
+ */
160
+ textures?(params: TParams): MarkTextures;
161
+ /**
162
+ * The rect `paintBlock` fills for instance `i`, undefined where it paints
163
+ * nothing. `defineMark` derives `hitNearest` from it where none is declared,
164
+ * and a highlight guide draws it. Painter-only overdraw, `span`'s seam, is
165
+ * not ink.
166
+ */
167
+ ink?(channels: TChannels, block: RenderBlock, frame: MarkFrame, params: TParams, i: number): InkRect | undefined;
168
+ /**
169
+ * The nearest drawn ink to `(xPx, yPx)` among `candidates`, or undefined if
170
+ * nothing beats `maxDistSq`. Distance 0 is on the ink, edges included. Only a
171
+ * strictly nearer candidate replaces the best, so candidates handed back to
172
+ * front answer a tie with the mark on top.
173
+ */
174
+ hitNearest?(channels: TChannels, block: RenderBlock, frame: MarkFrame, params: TParams, xPx: number, yPx: number, candidates: Iterable<number>, maxDistSq: number): MarkHit | undefined;
175
+ /**
176
+ * The values an instance can hold and still put ink within `radiusPx` of
177
+ * canvas y `yPx`, which a display's index over (bp, value) is searched with.
178
+ * A shape with no value axis leaves it off.
179
+ */
180
+ valueWindow?(yPx: number, radiusPx: number, frame: MarkFrame, params: TParams): [number, number];
181
+ }
182
+ /**
183
+ * The uniform writer and `params` lens whose struct is in the HAL's slot, so a
184
+ * later mark of the same block over both draws without writing it again. Hand
185
+ * every mark of a block one fresh object: a stale one draws against the
186
+ * previous block's clip.
187
+ */
188
+ export interface StagedUniforms {
189
+ writer: unknown;
190
+ params: unknown;
191
+ }
192
+ /**
193
+ * Puts a texture behind one of a pass's samplers once per identity: a repeat
194
+ * of the bound one costs nothing, and undefined leaves what is bound or binds
195
+ * an inert table where nothing is, since a textured pass missing a texture
196
+ * draws nothing on either GPU HAL.
197
+ */
198
+ export interface TextureBinder {
199
+ bind(passId: string, sampler: string, texture: MarkTexture | undefined): void;
200
+ }
201
+ /** What `hal.drawPass` takes for one mark of a frame plan. */
202
+ export interface PlannedPass {
203
+ readonly id: string;
204
+ readonly bufferOf: string | undefined;
205
+ }
206
+ /**
207
+ * A shape bound to a display's region payload and render state, its generics
208
+ * erased so one list holds several shapes.
209
+ */
210
+ export interface Mark<TRegion, TState extends MarkFrame> {
211
+ readonly pass: InstancePass<TRegion>;
212
+ /** The shape's {@link MarkShape.spansView}. */
213
+ readonly spansView?: boolean;
214
+ /** The pass whose uploaded instance buffer this mark draws from. */
215
+ readonly bufferOf?: string;
216
+ /** What the pass's samplers read this frame; undefined binds an inert table. */
217
+ readonly textures?: (state: TState, region: TRegion) => MarkTextures | undefined;
218
+ /**
219
+ * Whether the mark draws at all under `state`. `planMarks` asks once per
220
+ * frame and every other consumer per block, before any lens.
221
+ */
222
+ readonly enabled?: (state: TState) => boolean;
223
+ /** The pass a frame plan draws; undefined with a `band` or `paintsBlock`. */
224
+ readonly planned?: PlannedPass;
225
+ drawRegion(hal: GpuHal, scratch: ArrayBuffer, block: RenderBlock, clip: BlockClipResult, region: TRegion, state: TState, regionKey: number, staged?: StagedUniforms, textures?: TextureBinder): void;
226
+ paintBlock(ctx: MarkContext2D, region: TRegion, block: RenderBlock, state: TState): void;
227
+ hitNearest?(region: TRegion, block: RenderBlock, state: TState, xPx: number, yPx: number, candidates: Iterable<number>, maxDistSq: number): MarkHit | undefined;
228
+ /** The box instance `i` painted under the mark's gates, clipped to a band. */
229
+ ink?(region: TRegion, block: RenderBlock, state: TState, i: number): InkRect | undefined;
230
+ /** The shape's `valueWindow` under the mark's gates, if they open. */
231
+ valueWindow?(region: TRegion, block: RenderBlock, state: TState, yPx: number, radiusPx: number): [number, number] | undefined;
232
+ }
233
+ /**
234
+ * The shape under another pass id. A pass id keys the instance buffer and
235
+ * texture, so two marks of one shape in one display need two ids; pipelines
236
+ * are keyed by content, so the clone compiles nothing.
237
+ */
238
+ export declare function withPassId<C, P>(shape: MarkShape<C, P>, id: string): MarkShape<C, P>;
239
+ /**
240
+ * Binds a shape to a display's payload and render state through two picks run
241
+ * once per block per frame: `channels` names the region's arrays for the
242
+ * shape's lanes, and answers undefined for a region the mark has nothing in,
243
+ * which then packs, draws and paints nothing; `params` names what reaches the
244
+ * uniforms.
245
+ *
246
+ * `bufferOf` draws off another mark's uploaded buffer of the same instance
247
+ * struct. `textures` binds per pass per frame, each sampler re-uploading when
248
+ * its texture's identity moves, so ramps that differ by region re-upload per
249
+ * region. `band` clips the
250
+ * mark to a strip without offsetting it. `enabled` turns the mark off for a
251
+ * whole frame, for every consumer.
252
+ */
253
+ export declare function defineMark<TRegion, TState extends MarkFrame, TChannels, TParams>(spec: {
254
+ shape: MarkShape<TChannels, TParams>;
255
+ channels: (region: TRegion) => TChannels | undefined;
256
+ params: (state: TState, region: TRegion, block: RenderBlock) => TParams;
257
+ bufferOf?: Mark<TRegion, TState>;
258
+ band?: (state: TState) => MarkBand;
259
+ textures?: (state: TState, region: TRegion) => MarkTextures | undefined;
260
+ enabled?: (state: TState) => boolean;
261
+ }): Mark<TRegion, TState>;
@@ -0,0 +1,175 @@
1
+ import { devicePxBand, withClip } from '../canvas2dUtils.js';
2
+ import { shapeHitNearest } from './markHit.js';
3
+ /**
4
+ * The shape under another pass id. A pass id keys the instance buffer and
5
+ * texture, so two marks of one shape in one display need two ids; pipelines
6
+ * are keyed by content, so the clone compiles nothing.
7
+ */
8
+ export function withPassId(shape, id) {
9
+ return { ...shape, id, pass: { ...shape.pass, id } };
10
+ }
11
+ /**
12
+ * Binds a shape to a display's payload and render state through two picks run
13
+ * once per block per frame: `channels` names the region's arrays for the
14
+ * shape's lanes, and answers undefined for a region the mark has nothing in,
15
+ * which then packs, draws and paints nothing; `params` names what reaches the
16
+ * uniforms.
17
+ *
18
+ * `bufferOf` draws off another mark's uploaded buffer of the same instance
19
+ * struct. `textures` binds per pass per frame, each sampler re-uploading when
20
+ * its texture's identity moves, so ramps that differ by region re-upload per
21
+ * region. `band` clips the
22
+ * mark to a strip without offsetting it. `enabled` turns the mark off for a
23
+ * whole frame, for every consumer.
24
+ */
25
+ export function defineMark(spec) {
26
+ const { shape, channels, params, band, textures: ownTextures, enabled } = spec;
27
+ const hitNearest = shapeHitNearest(shape);
28
+ const shapeInk = shape.ink?.bind(shape);
29
+ const shapeValueWindow = shape.valueWindow?.bind(shape);
30
+ const shapeTextures = shape.textures?.bind(shape);
31
+ const samplers = shape.pass.textures?.map(t => t.name) ?? [];
32
+ const lender = spec.bufferOf?.pass;
33
+ if (lender &&
34
+ (lender.instanceStride !== shape.pass.instanceStride ||
35
+ JSON.stringify(lender.vertexAttributes) !==
36
+ JSON.stringify(shape.pass.vertexAttributes))) {
37
+ throw new Error(`mark ${shape.id} draws off ${lender.id}'s buffer but declares a different instance struct`);
38
+ }
39
+ const bufferOf = lender?.id;
40
+ const planned = band || shape.paintsBlock ? undefined : { id: shape.pass.id, bufferOf };
41
+ // `channels` gates `params`: a union payload's params lens may only read its
42
+ // own kind of region.
43
+ function resolve(region, block, state) {
44
+ if (enabled && !enabled(state)) {
45
+ return undefined;
46
+ }
47
+ const strip = band?.(state);
48
+ if (strip && !bandIsOpen(strip)) {
49
+ return undefined;
50
+ }
51
+ const c = channels(region);
52
+ if (c === undefined) {
53
+ return undefined;
54
+ }
55
+ const p = params(state, region, block);
56
+ if (shape.paintsBlock && !shape.paintsBlock(block, state, p)) {
57
+ return undefined;
58
+ }
59
+ return { channels: c, params: p, strip };
60
+ }
61
+ return {
62
+ pass: {
63
+ ...shape.pass,
64
+ pack: region => {
65
+ const c = channels(region);
66
+ return c === undefined ? NOTHING : shape.pass.pack(c);
67
+ },
68
+ },
69
+ bufferOf,
70
+ spansView: shape.spansView,
71
+ textures: ownTextures,
72
+ enabled,
73
+ planned,
74
+ // `resolve`'s gates inline: its picks leaving as a record or through
75
+ // closure state measured 0.80-0.86x of these locals on
76
+ // markUniformDedupe.bench.ts.
77
+ drawRegion(hal, scratch, block, clip, region, state, regionKey, staged, textures) {
78
+ if (enabled && !enabled(state)) {
79
+ return;
80
+ }
81
+ const strip = band?.(state);
82
+ if (strip && !bandIsOpen(strip)) {
83
+ return;
84
+ }
85
+ if (channels(region) === undefined) {
86
+ return;
87
+ }
88
+ const p = params(state, region, block);
89
+ if (shape.paintsBlock && !shape.paintsBlock(block, state, p)) {
90
+ return;
91
+ }
92
+ if (textures && samplers.length > 0) {
93
+ const own = ownTextures?.(state, region);
94
+ const fromParams = shapeTextures?.(p);
95
+ for (const sampler of samplers) {
96
+ textures.bind(shape.pass.id, sampler, own?.[sampler] ?? fromParams?.[sampler]);
97
+ }
98
+ }
99
+ const scissor = strip && devicePxBand(strip.top, strip.height, clip.scaleY, clip.pxH);
100
+ if (scissor?.height === 0) {
101
+ return;
102
+ }
103
+ if (scissor) {
104
+ hal.setScissor(clip.pxX, scissor.top, clip.pxW, scissor.height);
105
+ }
106
+ if (staged?.writer !== shape.writeUniforms || staged.params !== params) {
107
+ shape.writeUniforms(scratch, clip, block, state, p);
108
+ hal.writeUniforms(scratch);
109
+ if (staged) {
110
+ staged.writer = shape.writeUniforms;
111
+ staged.params = params;
112
+ }
113
+ }
114
+ hal.drawPass(shape.pass.id, regionKey, bufferOf, shape.verticesPerInstance?.(state, p));
115
+ if (scissor) {
116
+ hal.setScissor(clip.pxX, 0, clip.pxW, clip.pxH);
117
+ }
118
+ },
119
+ paintBlock(ctx, region, block, state) {
120
+ const open = resolve(region, block, state);
121
+ if (!open) {
122
+ return;
123
+ }
124
+ const { strip } = open;
125
+ if (strip) {
126
+ withClip(ctx, 0, strip.top, state.canvasWidth, strip.height, () => {
127
+ shape.paintBlock(ctx, open.channels, block, state, open.params);
128
+ });
129
+ }
130
+ else {
131
+ shape.paintBlock(ctx, open.channels, block, state, open.params);
132
+ }
133
+ },
134
+ hitNearest: hitNearest
135
+ ? (region, block, state, xPx, yPx, candidates, maxDistSq) => {
136
+ const open = resolve(region, block, state);
137
+ if (!open || bandExcludes(open.strip, yPx)) {
138
+ return undefined;
139
+ }
140
+ const hit = hitNearest(open.channels, block, state, open.params, xPx, yPx, candidates, maxDistSq);
141
+ // Rejecting a nearest hit the band clipped away, rather than asking
142
+ // again, can mask a farther candidate inside the strip.
143
+ return hit && !bandExcludes(open.strip, hit.y) ? hit : undefined;
144
+ }
145
+ : undefined,
146
+ ink: shapeInk
147
+ ? (region, block, state, i) => {
148
+ const open = resolve(region, block, state);
149
+ if (!open) {
150
+ return undefined;
151
+ }
152
+ const r = shapeInk(open.channels, block, state, open.params, i);
153
+ return r && open.strip ? clipToBand(r, open.strip) : r;
154
+ }
155
+ : undefined,
156
+ valueWindow: shapeValueWindow
157
+ ? (region, block, state, yPx, radiusPx) => {
158
+ const open = resolve(region, block, state);
159
+ return open && shapeValueWindow(yPx, radiusPx, state, open.params);
160
+ }
161
+ : undefined,
162
+ };
163
+ }
164
+ function bandIsOpen(strip) {
165
+ return strip.height > 0 && Number.isFinite(strip.top + strip.height);
166
+ }
167
+ function clipToBand(r, strip) {
168
+ const top = Math.max(r.top, strip.top);
169
+ const bottom = Math.min(r.top + r.height, strip.top + strip.height);
170
+ return bottom > top ? { ...r, top, height: bottom - top } : undefined;
171
+ }
172
+ const NOTHING = new ArrayBuffer(0);
173
+ function bandExcludes(strip, yPx) {
174
+ return (strip !== undefined && (yPx < strip.top || yPx > strip.top + strip.height));
175
+ }
@@ -0,0 +1,23 @@
1
+ import type { MarkValueScaleType } from './types.ts';
2
+ /** The y scale a valued shape places its instances through. */
3
+ export interface MarkValueScale {
4
+ /** `[min, max]` the values are read through. */
5
+ domain: [number, number];
6
+ /** How that domain is read; linear when absent. */
7
+ scaleType?: MarkValueScaleType;
8
+ /**
9
+ * symlog's linear-region width, already resolved from `domain` the way the
10
+ * axis resolves it (`resolveSymlogConstant`); d3's 1 when absent.
11
+ */
12
+ symlogConstant?: number;
13
+ /** Whether the domain's minimum sits at the band's top rather than its bottom. */
14
+ reverse?: boolean;
15
+ }
16
+ /**
17
+ * The two uniforms `valueScale.slang` reads a scale by, which the painter, the
18
+ * ink box and the hit test read too.
19
+ */
20
+ export declare function valueScaleUniforms({ scaleType, symlogConstant, }: MarkValueScale): {
21
+ valueScaleType: import("../scoreScale.ts").ScaleTypeCode;
22
+ valueSymlogConstant: number;
23
+ };
@@ -0,0 +1,11 @@
1
+ import { scaleTypeCode } from '../scoreScale.js';
2
+ /**
3
+ * The two uniforms `valueScale.slang` reads a scale by, which the painter, the
4
+ * ink box and the hit test read too.
5
+ */
6
+ export function valueScaleUniforms({ scaleType, symlogConstant = 1, }) {
7
+ return {
8
+ valueScaleType: scaleTypeCode(scaleType),
9
+ valueSymlogConstant: symlogConstant,
10
+ };
11
+ }
@@ -12,10 +12,9 @@ export declare function recordNamedReaction(self: object, name: string, disposer
12
12
  *
13
13
  * The two halves belong together: `reactionDependencies` can only see a
14
14
  * reaction that was recorded, so an installer that calls `autorun` and
15
- * `addDisposer` directly silently opts its dependency set out of the tests that
16
- * are supposed to pin it — and nothing fails, which is the same shape of
17
- * quiet-hole the mechanism exists to close. Every installer goes through here
18
- * so there is no second spelling to forget.
15
+ * `addDisposer` directly leaves its dependency set out of the tests that are
16
+ * supposed to pin it, and those tests still pass. Every installer goes through
17
+ * here so there is no second spelling to forget.
19
18
  */
20
19
  export declare function namedAutorun(self: IAnyStateTreeNode, body: () => void, options: IAutorunOptions & {
21
20
  name: string;
@@ -23,10 +23,9 @@ export function recordNamedReaction(self, name, disposer) {
23
23
  *
24
24
  * The two halves belong together: `reactionDependencies` can only see a
25
25
  * reaction that was recorded, so an installer that calls `autorun` and
26
- * `addDisposer` directly silently opts its dependency set out of the tests that
27
- * are supposed to pin it — and nothing fails, which is the same shape of
28
- * quiet-hole the mechanism exists to close. Every installer goes through here
29
- * so there is no second spelling to forget.
26
+ * `addDisposer` directly leaves its dependency set out of the tests that are
27
+ * supposed to pin it, and those tests still pass. Every installer goes through
28
+ * here so there is no second spelling to forget.
30
29
  */
31
30
  export function namedAutorun(self, body, options) {
32
31
  const disposer = autorun(body, options);
@@ -1,9 +1,12 @@
1
1
  import { Canvas2DRenderingBackendBase, GpuRenderingBackendBase } from './renderingBackendBase.ts';
2
2
  import type { BlockClipResult } from './blockClipUtils.ts';
3
+ import type { CanvasScale } from './canvas2dUtils.ts';
3
4
  import type { InstancePass } from './instancePass.ts';
4
5
  import type { RenderBlock } from './renderBlock.ts';
5
6
  import type { FrameDimensions, RenderingBackend } from './renderingBackendBase.ts';
6
7
  export type { FrameDimensions } from './renderingBackendBase.ts';
8
+ /** Straight RGBA, each channel 0-1 — what `beginFrame` takes. */
9
+ export type ClearColor = readonly [number, number, number, number];
7
10
  /**
8
11
  * Shared contract for per-region streamed GPU backends.
9
12
  *
@@ -12,9 +15,8 @@ export type { FrameDimensions } from './renderingBackendBase.ts';
12
15
  * against a data map passed back through `renderBlocks` each frame.
13
16
  *
14
17
  * `UploadData` is what the upload-side autorun pushes per region;
15
- * `RenderData` is what the render-side reads. They default to the same
16
- * type — MAF is the lone case where they diverge (upload payload also
17
- * carries a pre-encoded GPU buffer that the render side doesn't need).
18
+ * `RenderData` is what the render-side reads. They default to the same type,
19
+ * and every per-region display keeps the default today.
18
20
  *
19
21
  * Renderers are stateless: they keep no per-region cache. Canvas2D backends
20
22
  * stub `upload` / `release` as no-ops since they read everything from the
@@ -58,6 +60,15 @@ export declare abstract class Canvas2DPerRegionRenderingBackend<UploadData, Rend
58
60
  upload(): void;
59
61
  release(): void;
60
62
  renderBlocks(blocks: Block[], regions: ReadonlyMap<number, RenderData>, state: RenderState): boolean;
63
+ /**
64
+ * What the frame is painted onto before the blocks are drawn — the Canvas2D
65
+ * half of the GPU base's `beginFrame` clear. Undefined, the default, leaves
66
+ * `prepareCanvas`'s `clearRect` as the whole of it, which is transparent.
67
+ * Synteny is the one display that overrides: its indel wedges pre-blend
68
+ * against a KNOWN ground and only agree with the base ribbon beside them over
69
+ * a destination that really is that colour.
70
+ */
71
+ protected clearColor(_state: RenderState): ClearColor | undefined;
61
72
  /**
62
73
  * Paint the visible blocks into `this.ctx` (already DPR-prepared). Delegates
63
74
  * to the plugin's pure `drawXxxBlocks(ctx, regions, blocks, state)` function.
@@ -103,6 +114,11 @@ export declare abstract class GpuPerRegionRenderingBackend<UploadData, RenderSta
103
114
  */
104
115
  upload(displayedRegionIndex: number, data: UploadData): void;
105
116
  renderBlocks(blocks: Block[], regions: ReadonlyMap<number, RenderData>, state: RenderState): boolean;
117
+ /**
118
+ * Draw what spans the whole canvas after the blocks, with the scissor and
119
+ * viewport cleared, and answer whether anything drew.
120
+ */
121
+ protected drawOverBlocks(_regions: ReadonlyMap<number, RenderData>, _state: RenderState, _scale: CanvasScale): boolean;
106
122
  /**
107
123
  * Write uniforms and issue draw passes for one block whose scissor/viewport
108
124
  * are already set to its clipped span. `clip` carries the HP-split bp range
@@ -111,4 +127,6 @@ export declare abstract class GpuPerRegionRenderingBackend<UploadData, RenderSta
111
127
  * those whose draw state is fully in the uploaded buffer).
112
128
  */
113
129
  protected abstract drawRegion(block: Block, clip: BlockClipResult, region: RenderData, state: RenderState): void;
130
+ /** @see Canvas2DPerRegionRenderingBackend.clearColor */
131
+ protected clearColor(_state: RenderState): ClearColor;
114
132
  }
@@ -2,6 +2,7 @@ import { clipBlock } from './blockClipUtils.js';
2
2
  import { prepareCanvas } from './canvas2dUtils.js';
3
3
  import { uploadPass } from './instancePass.js';
4
4
  import { Canvas2DRenderingBackendBase, GpuRenderingBackendBase, } from './renderingBackendBase.js';
5
+ const TRANSPARENT = [0, 0, 0, 0];
5
6
  /**
6
7
  * Canvas2D-side base for `PerRegionRenderingBackend` implementations. Inherits
7
8
  * the `canvas` + 2D context (and no-op `dispose`) from
@@ -21,9 +22,26 @@ export class Canvas2DPerRegionRenderingBackend extends Canvas2DRenderingBackendB
21
22
  release() { }
22
23
  renderBlocks(blocks, regions, state) {
23
24
  prepareCanvas(this.canvas, this.ctx, state.canvasWidth, state.canvasHeight);
25
+ const clear = this.clearColor(state);
26
+ if (clear) {
27
+ const [r, g, b, a] = clear;
28
+ this.ctx.fillStyle = `rgba(${Math.round(r * 255)},${Math.round(g * 255)},${Math.round(b * 255)},${a})`;
29
+ this.ctx.fillRect(0, 0, state.canvasWidth, state.canvasHeight);
30
+ }
24
31
  this.draw(blocks, regions, state);
25
32
  return blocks.some(block => regions.has(block.displayedRegionIndex));
26
33
  }
34
+ /**
35
+ * What the frame is painted onto before the blocks are drawn — the Canvas2D
36
+ * half of the GPU base's `beginFrame` clear. Undefined, the default, leaves
37
+ * `prepareCanvas`'s `clearRect` as the whole of it, which is transparent.
38
+ * Synteny is the one display that overrides: its indel wedges pre-blend
39
+ * against a KNOWN ground and only agree with the base ribbon beside them over
40
+ * a destination that really is that colour.
41
+ */
42
+ clearColor(_state) {
43
+ return undefined;
44
+ }
27
45
  }
28
46
  /**
29
47
  * GPU-side base for `PerRegionRenderingBackend` implementations. Inherits the
@@ -70,9 +88,10 @@ export class GpuPerRegionRenderingBackend extends GpuRenderingBackendBase {
70
88
  // window, so a track dragged past the clamp draws at reduced resolution
71
89
  // instead of asking for a viewport its target cannot hold.
72
90
  const scale = this.hal.resize(canvasWidth, canvasHeight);
73
- // Always pair beginFrame/endFrame so the canvas clears to transparent even
74
- // when every block is skipped (e.g. all regions pruned by a density gate).
75
- this.hal.beginFrame(0, 0, 0, 0);
91
+ // Always pair beginFrame/endFrame so the canvas clears even when every
92
+ // block is skipped (e.g. all regions pruned by a density gate).
93
+ const [clearR, clearG, clearB, clearA] = this.clearColor(state);
94
+ this.hal.beginFrame(clearR, clearG, clearB, clearA);
76
95
  for (const block of blocks) {
77
96
  const region = regions.get(block.displayedRegionIndex);
78
97
  if (region !== undefined) {
@@ -87,7 +106,22 @@ export class GpuPerRegionRenderingBackend extends GpuRenderingBackendBase {
87
106
  }
88
107
  this.hal.clearScissor();
89
108
  this.hal.clearViewport();
109
+ if (this.drawOverBlocks(regions, state, scale)) {
110
+ painted = true;
111
+ this.hal.clearViewport();
112
+ }
90
113
  this.hal.endFrame();
91
114
  return painted;
92
115
  }
116
+ /**
117
+ * Draw what spans the whole canvas after the blocks, with the scissor and
118
+ * viewport cleared, and answer whether anything drew.
119
+ */
120
+ drawOverBlocks(_regions, _state, _scale) {
121
+ return false;
122
+ }
123
+ /** @see Canvas2DPerRegionRenderingBackend.clearColor */
124
+ clearColor(_state) {
125
+ return TRANSPARENT;
126
+ }
93
127
  }
@@ -17,8 +17,8 @@ export declare function isCheckedAtTheStore(map: ReadonlyMap<unknown, unknown>):
17
17
  * observable object graph — the stored value is not the object the worker
18
18
  * produced. A multi-wiggle region is one atom per field per source, so a
19
19
  * thousand-sample track pays ~18k on every pan; MAF pays the whole set again
20
- * for every cached region on every row reorder, since `placeFetchedRows`
21
- * re-places them all.
20
+ * for every cached region on every row reorder, since a reorder re-places
21
+ * them all.
22
22
  * - **Read.** Each field access goes through `getObservablePropValue_`. Hot
23
23
  * loops that hoist their typed arrays are fine, but the ones that don't were
24
24
  * paying it per iteration.