openlayers / openlayers

OpenLayers
https://openlayers.org
BSD 2-Clause "Simplified" License
11.39k stars 3.03k forks source link

COG -> GeoTIFF() + normalize:false -> TileLayer is broken on many newer Android phones #15581

Open potion-cellar opened 8 months ago

potion-cellar commented 8 months ago

Describe the bug

When using a TileLayer with a GeoTIFF source that has sources with normalize: false, the TileLayer fails to draw properly on devices which do not support the OES_texture_float GL extension and in a browser that does not manage to provide the extension anyways for WebGL1.0 contexts.

WebGL: INVALID_ENUM: texImage2D: invalid type

Context and Severity

I am now aware that the maintainers of openlayers have been considering and working towards implementing WebGL2 (with a WebGL1 fallback?) and I want to call attention to the below number if it helps influence the decision on if or when this should be implemented:

OES_texture_float support has dropped from ~95% support on Android devices to ~88%, per https://web3dsurvey.com/webgl/extensions/OES_texture_float.

Filtering by Android 14 on this list reveals a troubling collection of popular devices: https://opengles.gpuinfo.org/listreports.php?extension=GL_OES_texture_float&option=not

I've fleshed out the list here: https://github.com/openlayers/openlayers/issues/15581#issuecomment-1961837090

This number seems pretty reasonable to us as we have hundreds of Android users and we are getting increasing reports of unusable maps, likely a couple dozen users now. All from people with new Pixels and in a variety of browsers including Chrome.

For more color, as of right now this has become a significant, high priority production problem for us as people have upgraded their phones in the past year. We're trying to get some sort of workaround deployed, which may end up having to be an openlayers fork with WebGL2 support.

Of course, I understand that this is a fairly niche feature of the library and this growing production-level problem does not impact probably 99% of the openlayers userbase.

Anyways, the culprit is that newer Exynos chipsets that use Mali GPUs -- these chipsets are used in many flagship and major phone lines, particularly the Pixel, but also some flavors of Samsung Galaxy.

In the code, since normalize: false creates a Float32Array, webgl/TileTexture.js tries to call texImage2D with a FLOAT texel type that is invalid in WebGL1 contexts with no OES_texture_float extension.

Reproduction Steps

  1. Find a device that does not provide the GL_OES_texture_float GL extension.
  2. Make sure your browser does not provide a workaround for this missing extension (for instance, on Pixel 6, Chrome will still show OES_texture_float as an available extension for a WebGL1 context, but WebView will not)
  3. Visit https://openlayers.org/en/latest/examples/cog-style.html or any other example that uses a GeoTIFF with normalize: false. Note the incorrect rendering (solid black, white, green, etc.)
  4. Visit a GeoTIFF example that doesn't use normalize: false and note correct rendering.

Expected Behavior

I should be able to use normalize: false in the sources property of a GeoTIFF source and have my TileLayer style drawn properly across all devices.

At the very least, I should be made aware in the documentation and/or examples that the use of normalize: false is not supported on some significant subset of modern devices, and that normalize: true has better support.

Workarounds?

We're trying to implement some sort of workaround right now. If you have any insights, we'd really appreciate it.

We use singleband Float32 COGs and render contoured gradients using palette. Much of our data is fairly logarithmic so despite our best efforts to use normalize: true we've encountered datasets where the data near the minima becomes unacceptably coarse when normalized.

Here are our only ideas:

Maybe we're missing something easy here or have been incorrectly trying to use normalize: true. We're happy to provide a few example COGs or even a CodePen if it helps.

mike-000 commented 8 months ago

See #13367 #13529 #14366 #14377 #15136

potion-cellar commented 8 months ago

Ah cool, didn't know a webgl2 port has been in the works for awhile. If more work is needed on a PR I'd be happy to jump in.

potion-cellar commented 8 months ago

As I've slowly wrapped my ahead around the issue and the context for everything I've rewritten the issue to be more straightforward hopefully. I also brought in some additional statistics in case it helps the openlayers maintainers make decisions about future WebGL2 implementation.

In the past few years OES_texture_float support has dropped from ~95% support on Android devices (at least from an archive.org version of webglstats.com in 2021) to ~88%, per the latest web3d survey data: https://web3dsurvey.com/webgl/extensions/OES_texture_float

According to gpuinfo.org, the following devices running Android 13 or 14 have limited (broken in some browsers) or no (broken in all browsers) OES_texture_float support:

Given the above list, this has not been as problematic in North America and Europe until the newer Pixel versions started gaining market share. For us, we have enough users on Pixel 7 & 8 where it is now a high priority production problem, albeit due to our usage of a niche openlayers feature.