Skip to content

Commit f18e0b5

Browse files
committed
fixed build error
1 parent 5b162eb commit f18e0b5

File tree

2 files changed

+304
-2
lines changed

2 files changed

+304
-2
lines changed
Lines changed: 302 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,302 @@
1+
Title: WebGL2 Cross Platform Issues
2+
Description: Things to be aware of when trying to make your WebGL app work everywhere.
3+
TOC: Cross Platform Issues
4+
5+
I probably comes as no shock that not all WebGL programs work on all devices or
6+
browser.
7+
8+
Here's a list of most of the issues you might run into off the top of my head
9+
10+
## Performance
11+
12+
A top end GPU probably runs 100x faster than a low-end GPU. The only way around
13+
that that I know of is to either aim low, or else give the user options like
14+
most Desktop PC apps do where they can choose performance or fidelity.
15+
16+
## Memory
17+
18+
Similarly a top end GPU might have 12 to 24 gig of ram where as a low end GPU
19+
probably has less than 1gig. (I'm old so it's amazing to me low end = 1gig since
20+
I started programming on machines with 16k to 64k of memory 😜)
21+
22+
## Device Limits
23+
24+
WebGL has various minimum supported features but your local device might support
25+
> than that minimum which means it will fail on other devices that support less.
26+
27+
Examples include:
28+
29+
* The max texture size allowed
30+
31+
2048 or 4096 seems to be reasonable limits. At least as of 2020 it looks like
32+
[99% of devices support 4096 but only 50% support > 4096](https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE).
33+
34+
Note: the max texture size is the maximum dimension the GPU can process. It
35+
doesn't mean that GPU has enough memory for that dimension squared (for a 2D
36+
texture) or cubed (for a 3D texture). For example some GPUs have a max size of
37+
16384. But a 3D texture 16384 on each side would require 16 terabytes of
38+
memory!!!
39+
40+
* The maximum number of vertex attributes in a single program
41+
42+
In WebGL1 the minimum supported is 8. In WebGL2 it's 16. If you're using more than that
43+
then your code will fail on a machine with only the minimum
44+
45+
* The maximum number of uniform vectors
46+
47+
These are specified separately for vertex shaders and fragment shaders.
48+
49+
In WebGL1 it's 128 for vertex shaders and 16 for fragment shaders
50+
In WebGL2 it's 256 for vertex shaders and 224 for fragment shaders
51+
52+
Note that uniforms can be "packed" so the number above is how many `vec4`s
53+
can be used. Theoretically you could have 4x the number of `float` uniforms.
54+
but there is an algorithm that fits them in. You can imagine the space as
55+
an array with 4 columns, one row for each of the maximum uniform vectors above.
56+
57+
```
58+
+-+-+-+-+
59+
| | | | | <- one vec4
60+
| | | | | |
61+
| | | | | |
62+
| | | | | V
63+
| | | | | max uniform vectors rows
64+
| | | | |
65+
| | | | |
66+
| | | | |
67+
...
68+
69+
```
70+
71+
First `vec4`s are allocated with a `mat4` being 4 `vec4`s. Then `vec3`s are
72+
fit in the space left. Then `vec2`s followed by `float`s. So imagine we had 1
73+
`mat4`, 2 `vec3`s, 2 `vec2`s and 3 `float`s
74+
75+
```
76+
+-+-+-+-+
77+
|m|m|m|m| <- the mat4 takes 4 rows
78+
|m|m|m|m|
79+
|m|m|m|m|
80+
|m|m|m|m|
81+
|3|3|3| | <- the 2 vec3s take 2 rows
82+
|3|3|3| |
83+
|2|2|2|2| <- the 2 vec2s can squeeze into 1 row
84+
|f|f|f| | <- the 3 floats fit in one row
85+
...
86+
87+
```
88+
89+
Further, an array of uniforms is always vertical so for example if the maximum
90+
allowed uniform vectors is 16 then you can not have a 17 element `float` array
91+
and in fact if you had a single `vec4` that would take an entire row so there
92+
are only 15 rows left meaning the largest array you can have would be 15
93+
elements.
94+
95+
My advice though is don't count on perfect packing. Although the spec says the
96+
algorithm above is required to pass there are too many combinations to test
97+
that all drivers pass. Just be aware if you're getting close the limit.
98+
99+
note: varyings and attributes can not be packed.
100+
101+
* The maximum varying vectors.
102+
103+
WebGL1 the minimum is 8. WebGL2 it's 16.
104+
105+
If you use more than your code will not work on a machine with only the minimum.
106+
107+
* The maximum texture units
108+
109+
There are 3 values here.
110+
111+
1. How many texture units there are
112+
2. How many texture units a vertex shader can reference
113+
3. How many texture units a fragment shader can reference
114+
115+
<table class="tabular-data">
116+
<thead>
117+
<tr><th></th><th>WebGL1</th><th>WebGL2</th></tr>
118+
</thead>
119+
<tbody>
120+
<tr><td>min texture units that exist</td><td>8</td><td>32</td></tr>
121+
<tr><td>min texture units a vertex shader can reference</td><th style="color: red;">0!</td><td>16</td></tr>
122+
<tr><td>min texture units a fragment shader can reference</td><td>8</td><td>16</td></tr>
123+
</tbody>
124+
</table>
125+
126+
It's important to note the **0** for a vertex shader in WebGL1. Note that that's probably not the end of the world.
127+
Apparently [~97% of all devices support at least 4](https://web3dsurvey.com/webgl/parameters/MAX_VERTEX_TEXTURE_IMAGE_UNITS).
128+
Still, you might want to check so you can either tell the user that your app is not going to work for them or
129+
you can fallback to some other shaders.
130+
131+
There are other limits as well. To look them up you call `gl.getParameter` with
132+
the following values.
133+
134+
<div class="webgl_center">
135+
<table class="tabular-data">
136+
<tbody>
137+
<tr><td>MAX_TEXTURE_SIZE </td><td>max size of a texture</td></tr>
138+
<tr><td>MAX_VERTEX_ATTRIBS </td><td>num attribs you can have</td></tr>
139+
<tr><td>MAX_VERTEX_UNIFORM_VECTORS </td><td>num vec4 uniforms a vertex shader can have</td></tr>
140+
<tr><td>MAX_VARYING_VECTORS </td><td>num varyings you have</td></tr>
141+
<tr><td>MAX_COMBINED_TEXTURE_IMAGE_UNITS</td><td>num texture units that exist</td></tr>
142+
<tr><td>MAX_VERTEX_TEXTURE_IMAGE_UNITS </td><td>num texture units a vertex shader can reference</td></tr>
143+
<tr><td>MAX_TEXTURE_IMAGE_UNITS </td><td>num texture units a fragment shader can reference</td></tr>
144+
<tr><td>MAX_FRAGMENT_UNIFORM_VECTORS </td><td>num vec4 uniforms a fragment shader can have</td></tr>
145+
<tr><td>MAX_CUBE_MAP_TEXTURE_SIZE </td><td>max size of a cubemap</td></tr>
146+
<tr><td>MAX_RENDERBUFFER_SIZE </td><td>max size of a renderbuffer</td></tr>
147+
<tr><td>MAX_VIEWPORT_DIMS </td><td>max size of the viewport</td></tr>
148+
</tbody>
149+
</table>
150+
</div>
151+
152+
That is not the entire list. For example the max point size and max line thickness
153+
but you should basically assume the max line thickness is 1.0 and that POINTS
154+
are only useful for simple demos where you don't care about
155+
[the clipping issues](#points-lines-viewport-scissor-behavior).
156+
157+
WebGL2 adds several more. A few common ones are
158+
159+
<div class="webgl_center">
160+
<table class="tabular-data">
161+
<tbody>
162+
<tr><td>MAX_3D_TEXTURE_SIZE </td><td>max size of a 3D texture</td></tr>
163+
<tr><td>MAX_DRAW_BUFFERS </td><td>num color attachments you can have</td></tr>
164+
<tr><td>MAX_ARRAY_TEXTURE_LAYERS </td><td>max layers in a 2D texture array</td></tr>
165+
<tr><td>MAX_TRANSFORM_FEEDBACK_SEPARATE_ATTRIBS </td><td>num varyings you can output to separate buffers when using transform feedback</td></tr>
166+
<tr><td>MAX_TRANSFORM_FEEDBACK_INTERLEAVED_COMPONENTS</td><td>num varyings you can output when sending them all to a single buffer</td></tr>
167+
<tr><td>MAX_COMBINED_UNIFORM_BLOCKS </td><td>num uniform blocks you can use overall</td></tr>
168+
<tr><td>MAX_VERTEX_UNIFORM_BLOCKS </td><td>num uniform blocks a vertex shader can use</td></tr>
169+
<tr><td>MAX_FRAGMENT_UNIFORM_BLOCKS </td><td>num uniform blocks a fragment shader can use</td></tr>
170+
</tbody>
171+
</table>
172+
</div>
173+
174+
## Depth Buffer resolution
175+
176+
A few really old mobile devices use 16bit depth buffers. Otherwise, AFAICT 99%
177+
of devices use a 24bit depth buffer so you probably don't have to worry about
178+
this.
179+
180+
## readPixels format/type combos
181+
182+
Only certain format/type combos are guaranteed to work. Other combos are
183+
optional. This is covered in [this article](webgl-readpixels.html).
184+
185+
## framebuffer attachment combos
186+
187+
Framebuffers can have 1 or more attachments of textures and renderbuffers.
188+
189+
In WebGL1 only 3 combinations of attachments are guaranteed to work.
190+
191+
1. a single format = `RGBA`, type = `UNSIGNED_BYTE` texture as `COLOR_ATTACHMENT0`
192+
2. a format = `RGBA`, type = `UNSIGNED_BYTE` texture as `COLOR_ATTACHMENT0` and a
193+
format = `DEPTH_COMPONENT` renderbuffer attached as `DEPTH_ATTACHMENT`
194+
3. a format = `RGBA`, type = `UNSIGNED_BYTE` texture as `COLOR_ATTACHMENT0` and a
195+
format = `DEPTH_STENCIL` renderbuffer attached as `DEPTH_STENCIL_ATTACHMENT`
196+
197+
All other combinations are up to the implementation which you check by calling
198+
`gl.checkFramebufferStatus` and seeing if it returned `FRAMEBUFFER_COMPLETE`.
199+
200+
WebGL2 guarantees to be able to write to many more formats but still has the
201+
limit in that **any combination can fail!** Your best bet might be if all the
202+
color attachments are the same format if you attach more than 1.
203+
204+
## Extensions
205+
206+
Many features of WebGL1 and WebGL2 are optional. The entire point of having an
207+
API called `getExtension` is that it can fail if the extension does not exist
208+
and so you should be checking for that failure and not blindly assuming it will
209+
succeed.
210+
211+
Probably the most common missing extension on WebGL1 and WebGL2 is
212+
`OES_texture_float_linear` which is the ability to filter a floating point
213+
texture, meaning the ability to support setting `TEXTURE_MIN_FILTER` and
214+
`TEXTURE_MAX_FILTER` to anything except `NEAREST`. Many mobile devices do not
215+
support this.
216+
217+
In WebGL1 another often missing extension is `WEBGL_draw_buffers` which is the
218+
ability to attach more than 1 color attachment to a framebuffer is still at
219+
around 70% for desktop and almost none for smartphones (that seems wrong).
220+
Basically any device that can run WebGL2 should also support
221+
`WEBGL_draw_buffers` in WebGL1 but still, it's apparently still an issue. If you
222+
are needing to render to multiple textures at once it's likely your page needs a
223+
high end GPU period. Still, you should check if the user device supports it and
224+
if not provide a friendly explanation.
225+
226+
For WebGL1 the following 3 extensions seem almost universally supported so while
227+
you might want to warn the user your page is not going to work if they are
228+
missing it's likely that user has an extremely old device that wasn't going to
229+
run your page well anyway.
230+
231+
They are, `ANGLE_instance_arrays` (the ability to use [instanced drawing](webgl-instanced-drawing.html)),
232+
`OES_vertex_array_object` (the ability to store all the attribute state in an object so you can swap all
233+
that state with a single function call. See [this](webgl-attributes.html)), and `OES_element_index_uint`
234+
(the ability to use `UNSIGNED_INT` 32 bit indices with [`drawElements`](webgl-indexed-vertices.html)).
235+
236+
## attribute locations
237+
238+
A semi common bug is not looking up attribute locations. For example you have a vertex shader like
239+
240+
```glsl
241+
attribute vec4 position;
242+
attribute vec2 texcoord;
243+
244+
uniform mat4 matrix;
245+
246+
varying vec2 v_texcoord;
247+
248+
void main() {
249+
gl_Position = matrix * position;
250+
v_texcoord = texcoord;
251+
}
252+
```
253+
254+
Your code assumes that `position` will be attribute 0 and `texcoord` will be
255+
attribute 1 but that is not guaranteed. So it runs for you but fails for someone
256+
else. Often this can be a bug in that you didn't do this intentionally but
257+
through an error in the code things work when the locations are one way but not
258+
another.
259+
260+
There are 3 solutions.
261+
262+
1. Always look up the locations.
263+
2. Assign locations by calling `gl.bindAttribLocation` before calling `gl.linkProgram`
264+
3. WebGL2 only, set the locations in the shader as in
265+
266+
```glsl
267+
#version 300 es
268+
layout(location = 0) vec4 position;
269+
latout(location = 1) vec2 texcoord;
270+
...
271+
```
272+
273+
Solution 2 seems the most [D.R.Y.](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) where as solution 3
274+
seems the most [W.E.T.](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself#DRY_vs_WET_solutions) unless
275+
you're generating your textures at runtime.
276+
277+
## GLSL undefined behavior
278+
279+
Several GLSL functions have undefined behavior. For example `pow(x, y)` is
280+
undefined if `x < 0`. There is a longer list at [the bottom of the article on
281+
spot lighting](webgl-3d-lighting-spot.html).
282+
283+
## Shader precision issues
284+
285+
In 2020 the biggest issue here is if you use `mediump` or `lowp` in your shaders
286+
then on desktop the GPU will really use `highp` but on mobile they'll actually be
287+
`mediump` and or `lowp` and so you won't notice any issues when developing on desktop.
288+
289+
See [this article for more details](webgl-precision-issues.html).
290+
291+
## Points, Lines, Viewport, Scissor behavior
292+
293+
`POINTS` and `LINES` in WebGL can have a max size of 1 and in fact for `LINES`
294+
that is now the most common limit. Further whether points are clipped when their
295+
center is outside the viewport is implementation defined. See the bottom of
296+
[this article](webgl-drawing-without-data.html#pointissues).
297+
298+
Similarly, whether or not the viewport clips vertices only or also pixels is
299+
undefined. The scissor always clips pixels so turn on the scissor test and set
300+
the scissor size if you set the viewport smaller than the thing you're drawing
301+
to and you're drawing LINES or POINTS.
302+

webgl/lessons/zh_cn/webgl-tips.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
Title: WebGL2 小贴士
22
Description: 使用 WebGL 时可能遇到的一些小问题
3-
TOC: 画布截屏
3+
TOC: #
44

55
本文收集了一些你在使用 WebGL 时可能遇到的、看起来太小而不值得单独写一篇文章的问题。
66

77
---
88

99
<a id="screenshot" data-toc="Taking a screenshot"></a>
1010

11-
# 对 Canvas 截图
11+
# 画布截屏
1212

1313
在浏览器中,实际上有两种函数可以对画布进行截图。
1414
一种旧方法是:

0 commit comments

Comments
 (0)