glre 0.23.0 → 0.24.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "glre",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "author": "tseijp",
5
5
  "license": "MIT",
6
6
  "private": false,
package/src/index.ts CHANGED
@@ -29,9 +29,7 @@ export const isWebGPUSupported = () => {
29
29
  return 'gpu' in navigator
30
30
  }
31
31
 
32
- let iTime = performance.now(),
33
- iPrevTime = 0,
34
- iDeltaTime = 0
32
+ let iTime = performance.now()
35
33
 
36
34
  export const createGL = (props?: Partial<GL>) => {
37
35
  const gl = event<Partial<GL>>({
@@ -50,8 +48,9 @@ export const createGL = (props?: Partial<GL>) => {
50
48
  gl.frame = createFrame()
51
49
 
52
50
  gl.attribute = durable((k, v, i) => gl.queue(() => gl._attribute?.(k, v, i)))
53
- gl.uniform = durable((k, v, i) => gl.queue(() => gl._uniform?.(k, v, i)))
54
51
  gl.texture = durable((k, v) => gl.queue(() => gl._texture?.(k, v)))
52
+ gl.uniform = durable((k, v, i) => gl.queue(() => gl._uniform?.(k, v, i)))
53
+ gl.uniform({ iResolution: gl.size, iMouse: [0, 0], iTime: 0 }) // default uniform
55
54
 
56
55
  gl('mount', async () => {
57
56
  if (!isWebGPUSupported()) gl.isWebGL = true
@@ -61,6 +60,7 @@ export const createGL = (props?: Partial<GL>) => {
61
60
  gl.resize()
62
61
  gl.frame(() => {
63
62
  gl.loop()
63
+ gl.queue.flush()
64
64
  gl.render()
65
65
  return gl.isLoop
66
66
  })
@@ -77,14 +77,6 @@ export const createGL = (props?: Partial<GL>) => {
77
77
  gl.el.removeEventListener('mousemove', gl.mousemove)
78
78
  })
79
79
 
80
- gl('loop', () => {
81
- iPrevTime = iTime
82
- iTime = performance.now() / 1000
83
- iDeltaTime = iTime - iPrevTime
84
- gl.uniform({ iPrevTime, iTime, iDeltaTime })
85
- // if (gl.fragmentNode) updateUniforms({ time: iTime }) // @TODO FIX
86
- })
87
-
88
80
  gl('resize', () => {
89
81
  const w = gl.width || window.innerWidth
90
82
  const h = gl.height || window.innerHeight
@@ -101,6 +93,11 @@ export const createGL = (props?: Partial<GL>) => {
101
93
  gl.uniform('iMouse', gl.mouse)
102
94
  })
103
95
 
96
+ gl('loop', () => {
97
+ iTime = performance.now() / 1000
98
+ gl.uniform('iTime', iTime)
99
+ })
100
+
104
101
  return gl(props)
105
102
  }
106
103
 
package/src/node/index.ts CHANGED
@@ -43,8 +43,8 @@ export const If = (condition: X, callback: () => void): ConditionalNode => {
43
43
  }
44
44
 
45
45
  // 組み込み変数
46
- export const gl_FragCoord = node('vec4', undefined)
47
- export const gl_Position = node('vec4', undefined)
46
+ export const fragCoord = node('vec4', undefined)
47
+ export const position = node('vec4', undefined)
48
48
  export const iTime = uniform(0.0)
49
49
  export const iResolution = uniform([1920, 1080])
50
50
  export const iMouse = uniform([0, 0])
package/src/types.ts CHANGED
@@ -6,6 +6,7 @@ export type GPUContext = any // GPUCanvasContext https://developer.mozilla.org/e
6
6
  export type GPUDevice = any //
7
7
  export type GPUBuffer = any //
8
8
  export type GPUPipeline = any //
9
+ export type GPUBindGroup = any
9
10
  export type Uniform = number | number[]
10
11
  export type Attribute = number[]
11
12
  export type Attributes = Record<string, Attribute>
@@ -1,18 +1,5 @@
1
1
  import { GPUContext, GPUDevice, GPUPipeline } from '../types'
2
2
 
3
- export const initWebGPUDevice = async (el: HTMLCanvasElement) => {
4
- const gpu = (navigator as any).gpu
5
- if (!gpu) return null
6
- const adapter = await gpu.requestAdapter()
7
- if (!adapter) return null
8
- const device = await adapter.requestDevice()
9
- const context = el.getContext('webgpu') as GPUContext
10
- if (!context) return null
11
- const format = gpu.getPreferredCanvasFormat()
12
- context.configure({ device, format })
13
- return { device, context, format }
14
- }
15
-
16
3
  const defaultVertexWGSL = `
17
4
  @vertex
18
5
  fn main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
@@ -23,13 +10,21 @@ fn main(@builtin(vertex_index) vertex_index: u32) -> @builtin(position) vec4f {
23
10
  `
24
11
 
25
12
  const defaultFragmentWGSL = `
13
+ struct Uniforms {
14
+ iResolution: vec2f,
15
+ iMouse: vec2f,
16
+ iTime: f32,
17
+ }
18
+
19
+ @group(0) @binding(0) var<uniform> u: Uniforms;
20
+
26
21
  @fragment
27
22
  fn main(@builtin(position) position: vec4f) -> @location(0) vec4f {
28
- return vec4f(position.xy / vec2f(1280, 800), 0.0, 1.0);
23
+ return vec4f(position.xy / iResolution, 0.0, 1.0);
29
24
  }
30
25
  `
31
26
 
32
- export const createRenderPipeline = (
27
+ export const createPipeline = (
33
28
  device: GPUDevice,
34
29
  format: string,
35
30
  vs = defaultVertexWGSL,
@@ -64,65 +59,66 @@ export const createDescriptor = (c: GPUContext) => {
64
59
  ],
65
60
  }
66
61
  }
67
- export const alignTo256 = (size: number) => Math.ceil(size / 256) * 256
68
-
69
- export const createUniformBuffer = (device: GPUDevice, size: number) => {
70
- return device.createBuffer({ size: alignTo256(size), usage: 0x40 | 0x4 }) as Buffer
71
- }
72
-
73
- export const createVertexBuffer = (device: GPUDevice, value: number[]) => {
74
- const array = new Float32Array(value)
75
- const buffer = device.createBuffer({ size: array.byteLength, usage: 0x20 | 0x4 })
76
- device.queue.writeBuffer(buffer, 0, array)
77
- return buffer as Buffer
78
- }
79
-
80
- export const createBindGroup = (device: GPUDevice, pipeline: GPUPipeline, entries: any[]) => {
81
- const layout = pipeline.getBindGroupLayout(0)
82
- return device.createBindGroup({ layout, entries })
83
- }
84
-
85
- export const updateBindGroup = (
86
- device: GPUDevice,
87
- pipeline: GPUPipeline,
88
- uniformBuffer: Buffer,
89
- textures: any = {},
90
- sampler: any = null
91
- ) => {
92
- const entries = [{ binding: 0, resource: { buffer: uniformBuffer } }]
93
- let binding = 1
94
- Object.values(textures).forEach((texture: any) => {
95
- entries.push({ binding: binding++, resource: texture.createView() })
96
- })
97
- if (sampler && Object.keys(textures).length > 0) entries.push({ binding: binding++, resource: sampler })
98
- return createBindGroup(device, pipeline, entries)
99
- }
100
-
101
- export const createUniform = (device: GPUDevice, buffer: any, data: Float32Array, offset = 0) => {
102
- device.queue.writeBuffer(buffer, offset, data)
103
- }
104
-
105
- export const createDeviceTexture = (device: GPUDevice, image: HTMLImageElement) => {
106
- const texture = device.createTexture({
107
- size: { width: image.width, height: image.height },
108
- format: 'rgba8unorm',
109
- usage: 0x4 | 0x2,
110
- })
111
- device.queue.copyExternalImageToTexture(
112
- { source: image },
113
- { texture },
114
- { width: image.width, height: image.height }
115
- )
116
- return texture
117
- }
118
-
119
- export const createSampler = (device: GPUDevice) => {
120
- return device.createSampler({
121
- magFilter: 'linear',
122
- minFilter: 'linear',
123
- addressModeU: 'clamp-to-edge',
124
- addressModeV: 'clamp-to-edge',
125
- })
126
- }
127
62
 
128
- export const getDefaultVertices = () => new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])
63
+ // export const alignTo256 = (size: number) => Math.ceil(size / 256) * 256
64
+ //
65
+ // export const createUniformBuffer = (device: GPUDevice, size: number) => {
66
+ // return device.createBuffer({ size: alignTo256(size), usage: 0x40 | 0x4 }) as Buffer
67
+ // }
68
+ //
69
+ // export const createVertexBuffer = (device: GPUDevice, value: number[]) => {
70
+ // const array = new Float32Array(value)
71
+ // const buffer = device.createBuffer({ size: array.byteLength, usage: 0x20 | 0x4 })
72
+ // device.queue.writeBuffer(buffer, 0, array)
73
+ // return buffer as Buffer
74
+ // }
75
+ //
76
+ // export const createBindGroup = (device: GPUDevice, pipeline: GPUPipeline, entries: any[]) => {
77
+ // const layout = pipeline.getBindGroupLayout(0)
78
+ // return device.createBindGroup({ layout, entries })
79
+ // }
80
+ //
81
+ // export const updateBindGroup = (
82
+ // device: GPUDevice,
83
+ // pipeline: GPUPipeline,
84
+ // uniformBuffer: Buffer,
85
+ // textures: any = {},
86
+ // sampler: any = null
87
+ // ) => {
88
+ // const entries = [{ binding: 0, resource: { buffer: uniformBuffer } }]
89
+ // let binding = 1
90
+ // Object.values(textures).forEach((texture: any) => {
91
+ // entries.push({ binding: binding++, resource: texture.createView() })
92
+ // })
93
+ // if (sampler && Object.keys(textures).length > 0) entries.push({ binding: binding++, resource: sampler })
94
+ // return createBindGroup(device, pipeline, entries)
95
+ // }
96
+ //
97
+ // export const createUniform = (device: GPUDevice, buffer: any, data: Float32Array, offset = 0) => {
98
+ // device.queue.writeBuffer(buffer, offset, data)
99
+ // }
100
+ //
101
+ // export const createDeviceTexture = (device: GPUDevice, image: HTMLImageElement) => {
102
+ // const texture = device.createTexture({
103
+ // size: { width: image.width, height: image.height },
104
+ // format: 'rgba8unorm',
105
+ // usage: 0x4 | 0x2,
106
+ // })
107
+ // device.queue.copyExternalImageToTexture(
108
+ // { source: image },
109
+ // { texture },
110
+ // { width: image.width, height: image.height }
111
+ // )
112
+ // return texture
113
+ // }
114
+ //
115
+ // export const createSampler = (device: GPUDevice) => {
116
+ // return device.createSampler({
117
+ // magFilter: 'linear',
118
+ // minFilter: 'linear',
119
+ // addressModeU: 'clamp-to-edge',
120
+ // addressModeV: 'clamp-to-edge',
121
+ // })
122
+ // }
123
+ //
124
+ // export const getDefaultVertices = () => new Float32Array([-1, -1, 1, -1, -1, 1, -1, 1, 1, -1, 1, 1])
package/src/webgl.ts CHANGED
@@ -41,7 +41,6 @@ export const webgl = async (gl: GL) => {
41
41
 
42
42
  gl('render', () => {
43
43
  c.useProgram(pg)
44
- gl.queue.flush()
45
44
  c.clear(c.COLOR_BUFFER_BIT)
46
45
  c.viewport(0, 0, ...gl.size)
47
46
  c.drawArrays(c.TRIANGLES, 0, 3)
package/src/webgpu.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { wgsl } from './code/wgsl'
2
2
  import { is } from './utils/helpers'
3
3
  import {
4
- createRenderPipeline,
4
+ createPipeline,
5
5
  createDescriptor,
6
6
  // createUniformBuffer,
7
7
  // updateBindGroup,
@@ -11,7 +11,8 @@ import {
11
11
  // createSampler,
12
12
  } from './utils/pipeline'
13
13
  import type { X } from './node'
14
- import type { GL, GPUPipeline } from './types'
14
+ import type { GL, GPUBindGroup, GPUPipeline } from './types'
15
+ import { nested } from 'reev'
15
16
 
16
17
  const quadVertexCount = 3
17
18
 
@@ -27,18 +28,44 @@ export const webgpu = async (gl: GL) => {
27
28
  const format = gpu.getPreferredCanvasFormat()
28
29
  c.configure({ device, format, alphaMode: 'opaque' })
29
30
 
31
+ // Uniform buffer setup
32
+ // WebGPU 16-byte alignment requirement: iTime(4) + padding(12) + iMouse(8) + iPrevTime(4) + iDeltaTime(4) + iResolution(8) = 40 bytes, rounded to 48
33
+
34
+ const buffer = device.createBuffer({
35
+ size: 64, // @ts-ignore
36
+ usage: GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST,
37
+ })
38
+
30
39
  gl('clean', () => {})
31
40
 
41
+ const activeUnit = nested((_, size) => (_activeUnit += size))
42
+ let _activeUnit = 0
32
43
  let pipeline: GPUPipeline
44
+ let bindGroup: GPUBindGroup
45
+ let uniformData = new Float32Array(0)
33
46
 
34
47
  gl('render', () => {
35
- if (!pipeline) pipeline = createRenderPipeline(device, format, vs, fs, [])
48
+ if (!pipeline) {
49
+ pipeline = createPipeline(device, format, vs, fs, [])
50
+ bindGroup = device.createBindGroup({
51
+ layout: pipeline.getBindGroupLayout(0),
52
+ entries: [
53
+ {
54
+ binding: 0,
55
+ resource: { buffer },
56
+ },
57
+ ],
58
+ })
59
+ }
60
+
36
61
  const encoder = device.createCommandEncoder()
37
62
  const pass = encoder.beginRenderPass(createDescriptor(c))
38
63
  pass.setPipeline(pipeline)
64
+ pass.setBindGroup(0, bindGroup)
39
65
  pass.draw(quadVertexCount, 1, 0, 0)
40
66
  pass.end()
41
67
  device.queue.submit([encoder.finish()])
68
+ return true
42
69
  })
43
70
 
44
71
  gl('_attribute', (key = '', value: number[]) => {
@@ -46,17 +73,22 @@ export const webgpu = async (gl: GL) => {
46
73
  // vertexBuffers(key, value)
47
74
  })
48
75
 
49
- gl('_uniform', (key: string, value = 0) => {
50
- // @TODO FIX
51
- // if (!device || !uniformBuffer) return
52
- // uniforms[key] = value
53
- // const uniformData = new Float32Array(Object.values(uniforms))
54
- // createUniform(device, uniformBuffer, uniformData)
76
+ gl('_uniform', (key: string, value: number | number[]) => {
77
+ if (is.num(value)) value = [value]
78
+ const size = value.length
79
+ const unit = activeUnit(key, size)
80
+ if (unit === _activeUnit) {
81
+ const array = new Float32Array(_activeUnit)
82
+ if (uniformData) array.set(uniformData)
83
+ uniformData = array
84
+ }
85
+ for (let i = 0; i < size; i++) uniformData[unit - size + i] = value[i]
86
+ device.queue.writeBuffer(buffer, 0, uniformData)
55
87
  })
56
88
 
57
89
  // const _loadFun = (image: HTMLImageElement, gl: GL) => {
58
90
  // const texture = createDeviceTexture(device, image)
59
- // // bindGroup = updateBindGroup(device, pipeline, uniformBuffer, textures, sampler)
91
+ // // bindGroup = updateBindGroup(device, pipeline, buffer, textures, sampler)
60
92
  // }
61
93
 
62
94
  gl('_texture', (alt: string, src: string) => {