{"action":"created","issue":{"url":"https://api.github.com/repos/KhronosGroup/WebGL/issues/2460","repository_url":"https://api.github.com/repos/KhronosGroup/WebGL","labels_url":"https://api.github.com/repos/KhronosGroup/WebGL/issues/2460/labels{/name}","comments_url":"https://api.github.com/repos/KhronosGroup/WebGL/issues/2460/comments","events_url":"https://api.github.com/repos/KhronosGroup/WebGL/issues/2460/events","html_url":"https://github.com/KhronosGroup/WebGL/issues/2460","id":243680908,"node_id":"MDU6SXNzdWUyNDM2ODA5MDg=","number":2460,"title":"CSS pixel size -> WebGL canvas size example is subtly wrong?","user":{"login":"juj","id":225351,"node_id":"MDQ6VXNlcjIyNTM1MQ==","avatar_url":"https://avatars2.githubusercontent.com/u/225351?v=4","gravatar_id":"","url":"https://api.github.com/users/juj","html_url":"https://github.com/juj","followers_url":"https://api.github.com/users/juj/followers","following_url":"https://api.github.com/users/juj/following{/other_user}","gists_url":"https://api.github.com/users/juj/gists{/gist_id}","starred_url":"https://api.github.com/users/juj/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/juj/subscriptions","organizations_url":"https://api.github.com/users/juj/orgs","repos_url":"https://api.github.com/users/juj/repos","events_url":"https://api.github.com/users/juj/events{/privacy}","received_events_url":"https://api.github.com/users/juj/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":15,"created_at":"2017-07-18T11:13:09Z","updated_at":"2018-08-22T22:52:48Z","closed_at":null,"author_association":"NONE","body":"Consider the example of choosing a WebGL backbuffer size based on the CSS pixel size of the canvas `window.devicePixelRatio` to match 1:1 with high DPI/physical screen pixels at\r\n\r\nhttps://www.khronos.org/webgl/wiki/HandlingHighDPI\r\n\r\nThe example reads\r\n\r\n```javascript\r\n<style>\r\n #theCanvas {\r\n    width: 50%;\r\n    height: 50%;\r\n}\r\n<style>\r\n<canvas id=\"theCanvas\"></canvas>\r\n<script>\r\nwindow.onload = main();\r\n\r\nfunction main() {\r\n  var canvas = document.getElementById(\"theCanvas\");\r\n  var devicePixelRatio = window.devicePixelRatio || 1;\r\n\r\n  // set the size of the drawingBuffer based on the size it's displayed.\r\n  canvas.width = canvas.clientWidth * devicePixelRatio;\r\n  canvas.height = canvas.clientHeight * devicePixelRatio;\r\n\r\n  var gl = canvas.getContext(\"webgl\");\r\n  ...\r\n}\r\n</script>\r\n```\r\n\r\nHere `window.devicePixelRatio` can be an arbitrary number like `1.353239x` (it is affected by page zoom level) and the CSS pixel size (`canvas.clientWidth/Height`) can also be arbitrary float numbers like `732.4315135px` as they come from `width: 50%, height: 50%` sizes, but `canvas.width/.height` need to be integers, so there's a double->int conversion that takes place.\r\n\r\nIn this example the physical size of the canvas is set to truncate/round down the computed CSS pixel size to integer units at\r\n\r\n```javascript\r\n  canvas.width = canvas.clientWidth * devicePixelRatio;\r\n  canvas.height = canvas.clientHeight * devicePixelRatio;\r\n```\r\n\r\nhowever to my understanding there is no guarantee that rounding down is the correct action to perform, nor that rounding to nearest, or rounding up would be the correct action to perform either, in order to get a WebGL rendering output that matches up 1:1 with the pixel size on screen.\r\n\r\nIn practice this kind of \"I don't know whether I should round down, round up or round to nearest\" problem can result in off-by-one pixel scenarios for the WebGL render target in different browser implementations, and as result, either the whole WebGL canvas output becomes blurry, as its composited to widen/tallen/shrink by one pixel, or one column or row of the WebGL canvas is duplicated in the middle, or there will be a one-pixel black/white border on the canvas.\r\n\r\nTo my experience the only correct way to choose the backbuffer size of a WebGL canvas, given an (arbitrary) CSS pixel size, is to first compute the WebGL backbuffer size from the CSS pixel size, e.g. using the above formula, but then after having set the WebGL backbuffer size, propagate that integer size back to the CSS pixel size to ensure that the two match up. That is,\r\n\r\n```javascript\r\n\r\n  // set the size of the drawingBuffer based on the size it's displayed.\r\n  canvas.width = canvas.clientWidth * devicePixelRatio;\r\n  canvas.height = canvas.clientHeight * devicePixelRatio;\r\n\r\n  // propagate the integer size back to CSS pixels to ensure they align up 1:1.\r\n  canvas.style.width = (canvas.width / devicePixelRatio) + 'px';\r\n  canvas.style.height = (canvas.height / devicePixelRatio) + 'px';\r\n```\r\n\r\nA result of this issue is that to avoid compositing artifacts, it's not possible to use automatic CSS directives such as `width: 50%` to size a canvas, while expecting a 1:1 match with physical screen size.\r\n\r\nIs there anything better to ensure 1:1 match for a canvas size without glitches, or if not, perhaps the example should be updated to instruct developers with this gotcha?"},"comment":{"url":"https://api.github.com/repos/KhronosGroup/WebGL/issues/comments/415211410","html_url":"https://github.com/KhronosGroup/WebGL/issues/2460#issuecomment-415211410","issue_url":"https://api.github.com/repos/KhronosGroup/WebGL/issues/2460","id":415211410,"node_id":"MDEyOklzc3VlQ29tbWVudDQxNTIxMTQxMA==","user":{"login":"kenrussell","id":1149904,"node_id":"MDQ6VXNlcjExNDk5MDQ=","avatar_url":"https://avatars1.githubusercontent.com/u/1149904?v=4","gravatar_id":"","url":"https://api.github.com/users/kenrussell","html_url":"https://github.com/kenrussell","followers_url":"https://api.github.com/users/kenrussell/followers","following_url":"https://api.github.com/users/kenrussell/following{/other_user}","gists_url":"https://api.github.com/users/kenrussell/gists{/gist_id}","starred_url":"https://api.github.com/users/kenrussell/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/kenrussell/subscriptions","organizations_url":"https://api.github.com/users/kenrussell/orgs","repos_url":"https://api.github.com/users/kenrussell/repos","events_url":"https://api.github.com/users/kenrussell/events{/privacy}","received_events_url":"https://api.github.com/users/kenrussell/received_events","type":"User","site_admin":false},"created_at":"2018-08-22T22:52:48Z","updated_at":"2018-08-22T22:52:48Z","author_association":"CONTRIBUTOR","body":"Sorry, progress on this stalled. I've just emailed blink-dev@ to ask what the current thinking is on this topic.\r\n"}}
{"actor":{"display_login":"kenrussell"}}