Posts Tagged ‘high-DPI display’

WebGL on a high-DPI display

Dealing with WebGL on a high-DPI display isn’t too difficult, but it does require an understanding of device pixels vs CSS pixels. Elements on a page automatically upscale on a high-DPI display, as dimensions are typically defined with CSS, and therefore defined in units of CSS pixels. The <canvas> element is no exception. However, upscaling a DOM element doesn’t mean that the content within the element will be upscaled or rendered nicely – this is why non-vector content can appear blurry on higher resolutions. With WebGL content, not only will it appear blurry, but the viewport will likely be clipped as well, due to the viewport being incorrectly calculated using CSS pixel dimensions.

With WebGL everything is assumed to be in units of device pixels and there is no automatic conversion from CSS pixels to device pixels. To specify the device pixel dimensions of the <canvas>, we need to set the width and height attributes of the element:

CSS Pixels vs Device Pixels on canvas

I like to compute and set the attributes automatically using window.devicePixelRatio.
In glfx I do the following (passing in _canvasWidthCSSPx, _canvasHeightCSSPx):

// Get devicePixelRatio
glfx.devicePixelRatio = window.devicePixelRatio || 1;

// Set the width,height attributes of the canvas element (in device pixels)
var _canvasWidthDevicePx = _canvasWidthCSSPx * glfx.devicePixelRatio;
var _canvasHeightDevicePx = _canvasHeightCSSPx * glfx.devicePixelRatio;    
_canvas.setAttribute(
"width", _canvasWidthDevicePx);
_canvas.setAttribute(
"height", _canvasHeightDevicePx);

// Set viewport width,height based on dimensions of canvas element        
glfx.gl.viewportWidth = _canvasWidthDevicePx;
glfx.gl.viewportHeight = _canvasHeightDevicePx;        

Reference: HandlingHighDPI

Entering the world of high-DPI displays

With a Retina iPad and my recent purchase of a Yoga 2 laptop with a “Quad HD” display (3200×1800) I’ve been dragged into the world of high-DPI (more precisely PPI) displays. For years, DPI was “standard” at either 96dpi (Windows) or 72dpi (Mac OS), with a logical/software pixel being equivalent to a hardware pixel on the display device. A higher resolution monitor meant the content on your display got a bit smaller but you gained a couple more thousand pixels to work with, but the recent and massive increases in pixel densities seems to be the end of the 1:1 mapping between software and hardware pixel references. Below are a few notes on my experiences dealing with high-DPI displays and content so far.

  • Windows 8.1 support is terrible. Both application support and operating system support for high-DPI displays is abysmal. See the post Living a High-DPI desktop lifestyle can be painful by Scott Hanselman which reflects many of the issues I’ve encountered with my Yoga 2 as well. There’s a large list of issues: for non-DPI aware applications Windows scale text but not icons and layout, applications lie about being DPI-aware and are rendered too small, and some applications simply crash (TourtiseSVN’s diff… no clue why, too many pixels?!). It’s easy to wag a finger at application developers, but legacy support is clearly something the operating system needs to handle. In addition, despite Windows 8.1 touting automatic, per-monitor, DPI detection, it’s all based off of the DPI of a “primary monitor” and content on the other monitors is scaled to match. So dragging a window for an application from the Yoga 2 display across to a HD/96dpi monitor results in the window being scaled down (and visibly blurry). Worse, all applications undergo the same treatment – so if you’re thinking you can just use non-DPI aware applications on an external display until support comes around, guess again.
    ArsTechnica did a piece mentioning this issue in particular, and Windows 8.1’s high-DPI support is general.
  • Web support is only half-way there. The best thing done to support high-DPI displays was defining the CSS2 reference pixel to be independent of hardware pixels. Beyond that you have media queries and higher resolution background images, but there’s still no good way to specify alternate foreground images, though the <picture> element may gain support soon. In general, outside of CSS things gets messy, as is the case with a high-DPI <canvas>.
    One problem with the web that I don’t see a proposed solution for is handling low-resolution image assets for which you can’t get a higher resolution version. This is a problem I face with this blog. There’s a lot of images (old screenshots, low-resolution photos, etc.) for which I can’t get a 2x, 4x, etc., higher resolution version and there’s no way to prevent upscaling the images or specify how the upscaling is done. The typical 2x-bilinear-filtered upscaling, done by most browsers, is not always desirable. In addition, as display vendors pack more pixels in, what happens when the “high-resolution” version needed is 4x or 8x?
  • SVG/Vector-based images aren’t always the answer. There’s a lot of benefits to vector-based formats, but they’re not the holy grail many think they are. For vector-based images, rendering costs grow as you add details with polygons and paths. It’s why video games still rely heavily on texture mapping, even as graphics hardware has progressed to handle rendering millions of polygons per frame – the additional geometry and computation for fine details is enormous.