The horse bolted long ago; there's little sense in trying to prevent future web platform features from enabling fingerprinting, because the existing surface that enables it is way too big to do anything meaningful about it.
Here are a couple of more constructive things to do:
- Campaign to make fingerprinting illegal in as many jurisdictions as possible. This addresses the big "legitimate" companies.
- Use some combination of allow-listing, deny-listing, and "grey-listing" to lock down what untrusted websites can do with your browser. I'm sure I've seen extensions and Pi-hole type products for this. You could even stop your browser from sending anything to untrusted sites except simple GET requests to pages that show up on Google. (I.e. make it harder for them to smuggle information back to the server.)
- Support projects like the Internet Archive that enable viewing large parts of the web without ever making a request to the original server.
I’m sympathetic to the privacy concerns but this isn’t a solution worth considering.
If the data can't be exfiltrated, who cares if they can fingerprint?
Letting JS communicate with servers without the user's explicit consent was the original sin of web dev, that ruined everything. Turned it from a user-controlled experience to one giant spyware service.
Also, WebGPU seems to conceptually support software rendering ("fallback adapter"), where fixed time rendering would seem to be possible even without getting cooperation from HW drivers. Being slower than WebGL might still be an acceptable tradeoff at least if the alternative WebGL API avenue of fingerprinting could be plugged.
You can time any computation. So they all have that side effect.
Also, from Javascript you can execute tons of C++ code (e.g. via DOM manipulation). There's no way all of that native code can be guaranteed to run with consistent timing across platforms.
Computations that call into native APIs can be put in the "has observable side effects" category (but in more fine grained treatment, some could have more specific handling).
function computation() { ... }
before = performance.now();
computation();
t = performance.now() - before;
(Obviously there will be noise, and you need to average a bunch of runs to get reliable results.)