Re: [csswg-drafts] [resize-observer] device-pixel-border-box size (#3554)

> An example of (a) being hard is that the inputs to layout may change _after_ the call to getDeviceRects(), but before javascript yields to rendering:
> 
> canvas.getDeviceRects();
> ...
> divContainingCanvas.style.width = '200px';

In this example, the problem is not that the `.getDeviceRects()` API exists, but the second line: developer changes the size after querying the device pixel size. (what would developer expect to happen anyways?) With same rationale(?), one could claim that having e.g. a synchronous `String.length` API is bad since developer can change the string afterwards, leading to `String.length` to return the wrong value. The only way to fix this would be to move to purely functional programming.

Having a resize event observer is fine and great, being able to get events from when a size changes is much nicer than polling, I don't argue against that, but I don't see why that would prevent having a `.getDeviceRects()` API?

> @juj @jdashg a polling API introduces all sorts of problems like forcing a layout, as @chrishtr has shown, which can easily cause major performance and correctness issues in applications.

I see forcing a layout being the correct thing to do, and not a problem. In 99% of applications with this canvas use case by the time the WebGL context is being initialized the DOM has already been set up and the DOM content is static. Relayouting would not do anything in such case, and even if it has to relayout right there on the spot, I don't see it correctness issues. If the API is forced to be async, it will be the async nature that will cause performance and correctness issues. If I have code e.g. like
```js
var canvas = new Canvas();
canvas.style.width = '100%';
canvas.style.height = '100%';
document.body.appendChild(canvas);
var deviceSize = canvas.getDeviceRects();
canvas.width = deviceSize.width;
canvas.height = deviceSize.height;
var ctx = canvas.getContext('webgl');
requestAnimationFrame(...);
```
there does not really exist a more performant, correct, unambiguous nor self-documenting way to initialize the rendering backbuffer size and the GL context than the above code. It has a good guarantee that no badly sized temp GPU backbuffer resources will be allocated. Having a separate resize observer event to allow reacting to when user resizes the page or similar is then great as well (is the existing 'resize' event not already usable for that purpose?)

If we need to have an async event to get the proper size, we will end up with tons of code out there that first initialize the canvas with a framebuffer with size 1920x1079 or 1921x1080 or something random off-by-one like that, then render one or more(?) frames with wrong size, then get the event, then fix up the framebuffer to proper 1920x1080 size. That will have worse performance than the code example above. Or we place an implicit requirement to codebases that initializing a GL context on a canvas is practically an async operation if you don't want temp memory pressure or silly temp init work, which will lead to more complicated init sequences and correctness bugs from developers.

Also e.g. transitioning to fullscreen would become an asynchronous operation, where one would `.requestFullscreen()` (as response to user input) either have to pause rendering until the resize event is received, or render with incorrect backbuffer size for unspecified number of frames, leading to possibly glitched visuals.

I don't think allocating these kind of temp framebuffers on the GPU would be exactly free memory-wise either, and GPU memory intensive applications might run into GPU OOMs because they allocated temporary off-by-one framebuffers on the GPU.

-- 
GitHub Notification of comment by juj
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/3554#issuecomment-504364913 using your GitHub account

Received on Friday, 21 June 2019 09:45:50 UTC