Skip to content

Commit 5f51569

Browse files
cmdcolinclaude
andcommitted
Extract shared WebGL utilities to @jbrowse/core/gpu/webglUtils
Consolidate duplicated createShader, createProgram, splitPositionWithFrac, and cacheUniforms functions from 6 separate copies across wiggle, hic, variants, alignments, canvas, sequence, dotplot, and synteny plugins into a single shared module in packages/core. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 7a2767a commit 5f51569

File tree

23 files changed

+129
-356
lines changed

23 files changed

+129
-356
lines changed

packages/core/package.json

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"./data_adapters/dataAdapterCache": "./src/data_adapters/dataAdapterCache.ts",
3737
"./gpu/getGpuDevice": "./src/gpu/getGpuDevice.ts",
3838
"./gpu/initGpuContext": "./src/gpu/initGpuContext.ts",
39+
"./gpu/webglUtils": "./src/gpu/webglUtils.ts",
3940
"./pluggableElementTypes": "./src/pluggableElementTypes/index.ts",
4041
"./pluggableElementTypes/AdapterType": "./src/pluggableElementTypes/AdapterType.ts",
4142
"./pluggableElementTypes/ConnectionType": "./src/pluggableElementTypes/ConnectionType.ts",
@@ -165,7 +166,7 @@
165166
"@mui/material": "^7.3.9",
166167
"@mui/system": "^7.3.9",
167168
"@mui/types": "^7.4.12",
168-
"@mui/x-data-grid": "^8.27.5",
169+
"@mui/x-data-grid": "^8.28.0",
169170
"@types/file-saver-es": "^2.0.3",
170171
"canvas-sequencer-ts": "^3.1.3",
171172
"copy-to-clipboard": "^3.3.3",
@@ -254,6 +255,10 @@
254255
"types": "./esm/gpu/initGpuContext.d.ts",
255256
"import": "./esm/gpu/initGpuContext.js"
256257
},
258+
"./gpu/webglUtils": {
259+
"types": "./esm/gpu/webglUtils.d.ts",
260+
"import": "./esm/gpu/webglUtils.js"
261+
},
257262
"./pluggableElementTypes": {
258263
"types": "./esm/pluggableElementTypes/index.d.ts",
259264
"import": "./esm/pluggableElementTypes/index.js"
@@ -693,6 +698,9 @@
693698
"gpu/initGpuContext": [
694699
"esm/gpu/initGpuContext.d.ts"
695700
],
701+
"gpu/webglUtils": [
702+
"esm/gpu/webglUtils.d.ts"
703+
],
696704
"pluggableElementTypes": [
697705
"esm/pluggableElementTypes/index.d.ts"
698706
],
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
export function splitPositionWithFrac(value: number): [number, number] {
2+
const intValue = Math.floor(value)
3+
const frac = value - intValue
4+
const loInt = intValue & 0xfff
5+
const hi = intValue - loInt
6+
const lo = loInt + frac
7+
return [hi, lo]
8+
}
9+
10+
export function createShader(
11+
gl: WebGL2RenderingContext,
12+
type: number,
13+
source: string,
14+
) {
15+
const shader = gl.createShader(type)!
16+
gl.shaderSource(shader, source)
17+
gl.compileShader(shader)
18+
if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS)) {
19+
const info = gl.getShaderInfoLog(shader)
20+
gl.deleteShader(shader)
21+
throw new Error(`Shader compile error: ${info}`)
22+
}
23+
return shader
24+
}
25+
26+
export function createProgram(
27+
gl: WebGL2RenderingContext,
28+
vsSource: string,
29+
fsSource: string,
30+
) {
31+
const vs = createShader(gl, gl.VERTEX_SHADER, vsSource)
32+
const fs = createShader(gl, gl.FRAGMENT_SHADER, fsSource)
33+
const program = gl.createProgram()
34+
gl.attachShader(program, vs)
35+
gl.attachShader(program, fs)
36+
gl.linkProgram(program)
37+
gl.detachShader(program, vs)
38+
gl.detachShader(program, fs)
39+
gl.deleteShader(vs)
40+
gl.deleteShader(fs)
41+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
42+
const info = gl.getProgramInfoLog(program)
43+
gl.deleteProgram(program)
44+
throw new Error(`Program link error: ${info}`)
45+
}
46+
return program
47+
}
48+
49+
export function cacheUniforms(
50+
gl: WebGL2RenderingContext,
51+
program: WebGLProgram,
52+
names: string[],
53+
) {
54+
const cache: Record<string, WebGLUniformLocation | null> = {}
55+
for (const name of names) {
56+
cache[name] = gl.getUniformLocation(program, name)
57+
}
58+
return cache
59+
}

plugins/alignments/src/LinearAlignmentsDisplay/components/ArcsRenderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import {
1010
splitPositionWithFrac,
1111
} from './shaders/index.ts'
1212

13-
import type { RenderState } from './rendererTypes.ts'
1413
import type { WebGLRenderer } from './WebGLRenderer.ts'
14+
import type { RenderState } from './rendererTypes.ts'
1515

1616
export interface RegionTableEntry {
1717
startBpOffset: number

plugins/alignments/src/LinearAlignmentsDisplay/components/Canvas2DAlignmentsRenderer.ts

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -259,10 +259,7 @@ export class Canvas2DAlignmentsRenderer implements AlignmentsBackend {
259259
this.ctx = ctx
260260
}
261261

262-
uploadFromTypedArraysForRegion(
263-
regionNumber: number,
264-
data: ReadUploadData,
265-
) {
262+
uploadFromTypedArraysForRegion(regionNumber: number, data: ReadUploadData) {
266263
let r = this.regions.get(regionNumber)
267264
if (!r) {
268265
r = emptyRegion(data.regionStart)
@@ -472,10 +469,7 @@ export class Canvas2DAlignmentsRenderer implements AlignmentsBackend {
472469
this.regions.clear()
473470
}
474471

475-
renderBlocks(
476-
blocks: RenderBlock[],
477-
state: RenderState,
478-
) {
472+
renderBlocks(blocks: RenderBlock[], state: RenderState) {
479473
const { canvasWidth, canvasHeight } = state
480474
const dpr = window.devicePixelRatio || 1
481475
const bufW = Math.round(canvasWidth * dpr)

plugins/alignments/src/LinearAlignmentsDisplay/components/ConnectingLineRenderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { splitPositionWithFrac } from './shaders/index.ts'
22

3-
import type { RenderState } from './rendererTypes.ts'
43
import type { WebGLRenderer } from './WebGLRenderer.ts'
4+
import type { RenderState } from './rendererTypes.ts'
55

66
export function renderConnectingLine(
77
renderer: WebGLRenderer,

plugins/alignments/src/LinearAlignmentsDisplay/components/CoverageRenderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
import type { RenderState } from './rendererTypes.ts'
21
import type { WebGLRenderer } from './WebGLRenderer.ts'
2+
import type { RenderState } from './rendererTypes.ts'
33
import type { ColorPalette } from './shaders/index.ts'
44

55
export function renderCoverage(

plugins/alignments/src/LinearAlignmentsDisplay/components/PileupRenderer.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import { getChainBounds, toClipRect } from './chainOverlayUtils.ts'
22
import { splitPositionWithFrac } from './shaders/index.ts'
33

4-
import type { RenderState } from './rendererTypes.ts'
54
import type { WebGLRenderer } from './WebGLRenderer.ts'
65
import type { ClipRect } from './chainOverlayUtils.ts'
6+
import type { RenderState } from './rendererTypes.ts'
77
import type { ColorPalette } from './shaders/index.ts'
88

99
function setCigarUniforms(

plugins/alignments/src/LinearAlignmentsDisplay/components/WebGLRenderer.ts

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,6 @@ import type {
8585
SashimiUploadData,
8686
} from './rendererTypes.ts'
8787

88-
8988
export interface GPUBuffers {
9089
// Reference point for all position offsets
9190
regionStart: number
@@ -1742,10 +1741,7 @@ export class WebGLRenderer implements AlignmentsBackend {
17421741
this.deactivateRegion(regionNumber)
17431742
}
17441743

1745-
uploadFromTypedArraysForRegion(
1746-
regionNumber: number,
1747-
data: ReadUploadData,
1748-
) {
1744+
uploadFromTypedArraysForRegion(regionNumber: number, data: ReadUploadData) {
17491745
this.withRegion(regionNumber, this.uploadFromTypedArrays, data)
17501746
}
17511747

@@ -1874,10 +1870,7 @@ export class WebGLRenderer implements AlignmentsBackend {
18741870
/**
18751871
* Render multiple blocks with scissor rects, each from a different refName's GPU buffers.
18761872
*/
1877-
renderBlocks(
1878-
blocks: RenderBlock[],
1879-
state: RenderState,
1880-
) {
1873+
renderBlocks(blocks: RenderBlock[], state: RenderState) {
18811874
const gl = this.gl
18821875
const canvas = this.canvas
18831876
const { canvasWidth, canvasHeight } = state

plugins/alignments/src/LinearAlignmentsDisplay/components/shaders/utils.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
export function splitPositionWithFrac(value: number): [number, number] {
2-
const intValue = Math.floor(value)
3-
const frac = value - intValue
4-
const loInt = intValue & 0xfff
5-
const hi = intValue - loInt
6-
const lo = loInt + frac
7-
return [hi, lo]
8-
}
1+
export { splitPositionWithFrac } from '@jbrowse/core/gpu/webglUtils'
92

103
export const HP_GLSL_FUNCTIONS = `
114
// SYNC(wgsl/common.ts): HP_LOW_MASK=0xFFF, hpSplitUint/hpToClipX/hpScaleLinear must match hp_split_uint/hp_to_clip_x/hp_scale_linear

plugins/canvas/src/LinearFeatureDisplay/components/FeatureComponent.tsx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -422,7 +422,7 @@ const FeatureComponent = observer(function FeatureComponent({ model }: Props) {
422422
// WebGL features in sync with the DOM label overlay (which is computed
423423
// during the same render via useMemo). useEffect would run after paint,
424424
// causing a frame where labels show new data but WebGL shows old data.
425-
425+
426426
useLayoutEffect(() => {
427427
const renderer = rendererRef.current
428428
if (!renderer || !rendererReady) {

0 commit comments

Comments
 (0)