You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+99-56Lines changed: 99 additions & 56 deletions
Original file line number
Diff line number
Diff line change
@@ -3,7 +3,9 @@
3
3
Virtualizes a single WebGL context into multiple contexts
4
4
5
5
[A demo of some WebGL apps running with only 1 shared WebGL context](https://greggman.github.io/virtual-webgl/example/example.html)
6
-
and using `alpha: false`, `premultipliedAlpha: false`, `preserveDrawingBuffer: true` and some other things. [A similar demo for WebGL2](https://greggman.github.io/virtual-webgl/example/example2.html).
6
+
and using `alpha: false`, `premultipliedAlpha: false`, `preserveDrawingBuffer: true`
7
+
and some other things. [A similar demo for WebGL2](https://greggman.github.io/virtual-webgl/example/example2.html).
8
+
And, [one for a mix of WebGL1 and WebGL2](https://greggman.github.io/virtual-webgl/example/example1and2.html).
7
9
8
10
[A demo of creating and disposing of webgl contexts](https://greggman.github.io/virtual-webgl/example/dispose.html).
9
11
WebGL implementations often delete the oldest context when too many are created. Using virtual-webgl you can
@@ -20,9 +22,10 @@ Compare to [the original without post processing](https://greggman.github.io/vir
20
22
21
23
Browsers usually limit WebGL to 8 to 16 contexts max. This is one idea to overcome that limit.
22
24
23
-
I don't actually recommend this at all. If you're in control of your code then there are
24
-
much better solutions [like this for raw webgl](http://twgljs.org/examples/itemlist.html)
25
-
and [this for three.js](https://threejs.org/examples/webgl_multiple_elements.html) (both if which I wrote BTW 😛)
25
+
If you're in control of your code then there are arguably better solutions
26
+
[like this for raw webgl](http://twgljs.org/examples/itemlist.html)
27
+
and [this for three.js](https://threejs.org/examples/webgl_multiple_elements.html)
28
+
(both if which I wrote BTW 😛)
26
29
27
30
I mostly wrote this for a fun short technical challenge. I have no plans to actually use it
28
31
or maintain it. If you find a problem feel free to file an issue but I can't promise I
@@ -45,6 +48,11 @@ you can do things like
45
48
With normal WebGL contexts you can't use resources from one context in another
46
49
context but with virtual contexts you can.
47
50
51
+
This is actually probably the best use-case. You can write 2 different libraries
52
+
independently of each other using WebGL and have them share resources and they
53
+
won't have to worry about stepping on each other's WebGL state. An example might
54
+
be, you have a video conferencing library and you want to add an effects library.
55
+
48
56
### Use the output of one WebGL app inside another
49
57
50
58
For example use a [mapbox-gl-js](https://www.mapbox.com/mapbox-gl-js/api/) map
@@ -73,49 +81,77 @@ or for WebGL2 use
73
81
74
82
## Writing your own compositor
75
83
76
-
A full solution would probably require some other method but ... If you look in
you'll see code that creates a custom compositor that draws a different result
93
+
than the default compositor.
94
+
95
+
The idea for the `createCompositor` function is that you probably need different
96
+
compositors for each canvas on the page so it's up to you how to do that. For
97
+
example you could check the `canvas` passed in and its ID or some `data`
98
+
attribute and do create different compositors for different canvases. If you
99
+
return nothing/undefined the default compositor will be created for that canvas.
100
+
101
+
As another example, if you wanted to draw a MapGL texture inside THREE.js then
102
+
you'd probably make the one compositor do nothing except record the texture
103
+
needed to use inside three.js. For three's canvas you'd use the default compositor.
104
+
[see this](https://greggman.github.io/virtual-webgl/mapbox-gl/index.html). I was not
105
+
sure how to use an external WebGL texture in THREE.js so the example uses twgl.
91
106
92
107
Note: If a compositor has a `dispose` method it will be called if `context.dispose` is called
93
108
to give your custom compositor a chance to clean up.
94
109
95
110
## Limits and Issues
96
111
97
-
* In WebGL2 you must end queries and transformFeedback before exiting
98
-
the current event. The good things is, AFAIK, pretty much all WebGL
99
-
apps already do this so it should't be a problem but not finishing
100
-
those is not technically against the spec.
112
+
* In WebGL2 you must end queries and transformFeedback before exiting the
113
+
current event. The good things is, AFAIK, pretty much all WebGL2 apps that use
114
+
queries and/or transformFeedback already do this so it should't be a problem.
115
+
But, not finishing those before exiting the event is not technically against
116
+
the spec.
117
+
118
+
* WebGL1 is emulated on WebGL2 in virtual-webgl2.js
119
+
120
+
When using virtual-webgl2.js WebGL2 functions are not available on virtual
121
+
WebGL1 contexts but WebGL2 constants can be passed to WebGL1 contexts.
122
+
123
+
In other words:
124
+
125
+
```js
126
+
webgl1Ctx.texImage3D(...); // error! no such function
127
+
webgl1Ctx.bindTexture(webgl1ctx.TEXTURE_3D, tex); // error! TEXTURE_3D is not defined
128
+
webgl1Ctx.bindTexture(webgl2ctx.TEXTURE_3D, tex); // ok
129
+
```
101
130
102
-
* You can't mix WebGL1 and WebGL2
131
+
This should arguably not a come up. A WebGL1 context would be using
132
+
WebGL1 constants. I only point this out to say virtual-webgl doesn't
133
+
force WebGL1 compliance.
103
134
104
-
WebGL1 and WebGL2 have a few incompatibilities meaning that emulating
105
-
WebGL1 on top of WebGL2 is more work. It might not be that much work.
106
-
I have not bothered to think about it. Off the top of my head you'd
107
-
have to emulate all the various WebGL1 only extensions like
108
-
OES_vertex_array_object, WEBGL_draw_buffers, different floating
109
-
point texture support, differences in how depth-stencil renderbuffers
110
-
work, and maybe a few other things.
135
+
* WebGL1 on WebGL2 support is limited
136
+
137
+
I took a quick stab at trying to emulate WebGL1 on WebGL2 so that
138
+
you could mix WebGL1 and WebGL2 in the same WebGL2 context.
139
+
That includes extensions like `OES_vertex_array_object`, `OES_texture_float`,
140
+
and `ANGLE_instanced_arrays`.
141
+
142
+
Unfortunately, when I got to `WEBGL_draw_buffers` I realized that
143
+
emulating that would require a full GLSL parser and re-writer to
144
+
change GLSL ES 1.0 to GLSL ES 3.0 and several complex transformations.
145
+
146
+
That's the long way of saying WebGL1 emulation on WebGL2 is incomplete.
111
147
112
148
* There are no checks for errors.
113
149
114
150
WebGL (and OpenGL) use a asynchronous command buffer error system
115
151
which means checking for errors really slows things down so
116
152
this Virtual WebGL also doesn't check for errors. Your code
117
153
should not be generating errors in the first place so if it is
118
-
fix your code.
154
+
fix your code!
119
155
120
156
Where this might come up? I forget the details of the spec but,
121
157
lets say you make an invalid program. When you call `gl.useProgram`
@@ -136,40 +172,47 @@ to give your custom compositor a chance to clean up.
136
172
137
173
## Perf
138
174
139
-
The WebGL2 wrapper is newer and saves state so it's pretty fast.
140
-
The WebGL1 wrapper is older and queries state so it's pretty slow.
175
+
The WebGL2 wrapper (virtual-webgl2.js) is newer and saves state so it's pretty fast.
176
+
The WebGL1 wrapper (virtual-webgl.js) is older and queries state so it's pretty slow.
141
177
142
178
Another perf issue is you can't render directly to different canvases so I have
143
-
to make each of the canvases use a `Canvas2DRenderingContext` and call `drawImage`.
144
-
That could be solved maybe with `OffscreenCanvas` and `ImageBitmapRenderingContext`
145
-
but those features haven't shipped without a flag as of 2018-06-05.
146
-
147
-
It could also be solved using the techniques used in [this sample](http://twgljs.org/examples/itemlist.html)
148
-
149
-
Basically put the canvas of the shared GL context full window size in the background and instead
150
-
of compositing by copying to a 2D canvas, composite by setting the viewport/scissor and render to
151
-
the shared GL context's canvas. The limitation of course is that the result won't appear in front
152
-
of other elements but usually that's ok.
153
-
154
-
That should be trivial to implement using a custom compositor. The first time you get a compositor
155
-
put the canvas of the shared context (the one that gets passed to `composite`) in the page and then
156
-
render the texture being composited using `gl.viewport` and `gl.scissor`
157
-
158
-
If your canvases are not all on screen you could try using [an augmented requestAnimationFrame](https://github.com/greggman/requestanimationframe-fix.js)
179
+
to make each of the canvases use a `Canvas2DRenderingContext` and call
180
+
`drawImage`. That could be solved maybe with `OffscreenCanvas` and
181
+
`ImageBitmapRenderingContext` but those features haven't shipped without a flag
182
+
as of 2018-06-05.
183
+
184
+
It could also be solved using the techniques used in
0 commit comments