[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Public WebGL] How to unambiguously set canvas pixel size to be pixel-perfect?



This problem seems as yet unresolved, and a good candidate to solve for the WebGL 2 specification.

An additional datapoint for consideration, for 398'000 pageviews from Wednesday the 25th of March 2015, I captured these DPRs in the wild:

 count | value
    75 | 0.50000
    82 | 0.70000
    86 | 2.00494
    98 | 1.33000
   125 | 1.42177
   127 | 1.35000
   128 | 1.75000
   138 | 0.66600
   175 | 2.50000
   183 | 1.30000
   188 | 1.09091
   215 | 0.80000
   247 | 0.89552
   247 | 1.34422
   378 | 0.85000
   436 | 1.20000
   438 | 1.15000
   625 | 4.00000
   698 | 0.95000
   796 | 1.33125
   855 | 1.05000
   909 | 0.75000
  1960 | 0.90000
  2510 | 1.10000
  5534 | 1.25000
  7393 | 3.00000
  8913 | 1.50000
 27176 | 2.00000
327576 | 1.00000

We have everything here, insane ratios (3 and beyond), ratios below 1 (seriously, does that even make sense?), fractional ratios (you like your pixels blurred irregularly do you?), periodic fractions (who could be bothered by even divisibility), irrational numbers (how do you even come up with that given that your screen has an integer number of pixels..., did you just fiddle with the ratio by hand?), you name it.

Regardless of all other concerns (CSS sizes, what have you). The first task is to make sure a WebGL application can render a viewport in the actual device resolution. There is no point in rendering incidentially/accidentially larger/smaller than the physical pixels on the device. There is very much a point to be able to precisely render at a desired super/sub resolution (which is only possible once you can accurately render at device resolution).

This problem is somewhat complicated by zooming. If things are reduced in size, this isn't a big problem because the underlying buffer can equally be reduced in size and things will work out fine. However if zooming enlarges the viewport, it's easily possible that just enlarging the underlying buffer by that ratio will lead to performance issues and/or exceeding the drawing buffer size limits.

Unfortunately the zoom-in case cannot be handled automatically (such as viewport curtailment) because post-processing algorithms on the presented result might do things with pixels that are off screen (like say a high horizontal spread anamorphic lens simulating bloom blur).

But viewport curtailment is still a practical device to have, and so it should be considered as an opt-in semantic for those wishing to regard it.

I propose the following simple API to take care of this problem:
  1. canvas.getDevicePixelSize() -> this returns width/height of the canvas in terms of real device pixels. Whatever DPR/zoom/CSS transform is applied to the content, it will return an integer width/height that is closest (ideally perfect) to the real screen coverage. It is primarily intended to adjust the canvas.width/canvas.height to this dimension.
  2. canvas.getVisibleRect() -> this returns a left/top width/height structure that specifies which part of the canvas needs to be rendered in terms of the DevicePixelSize in order to fill a rendering on screen. It is intended to be used in the gl.viewport setting.
I'm not sure this is sufficient/correct, as it leaves out how to handle the affine transform correctly, and doesn't handle the drawing buffer exceeding size limits case. I hope it's a starting point.