Closed Bug 780361 Opened 12 years ago Closed 5 years ago

[HiDPI] WebGL is not in high resolution on Retina display

Categories

(Core :: Graphics: CanvasWebGL, enhancement)

17 Branch
x86
macOS
enhancement
Not set
normal

Tracking

()

RESOLVED INVALID

People

(Reporter: fxcoudert, Assigned: jgilbert)

References

(Blocks 1 open bug)

Details

Attachments

(1 file)

User Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.8; rv:17.0) Gecko/17.0 Firefox/17.0
Build ID: 20120803090747

Steps to reproduce:

Using the HiDPI-enabled build on bug 674373's comment 138 (https://bugzilla.mozilla.org/show_bug.cgi?id=674373#c138), WebGL content is displayed at low resolution, instead of the expected high resolution.

For example, go to this test page: https://cvs.khronos.org/svn/repos/registry/trunk/public/webgl/sdk/demos/google/particles/index.html
On the attached screen capture, compare patched FF's low-res WebGL on the left, to Chrome beta's high-res WebGL on the right.
Depends on: 674373
Component: Untriaged → Canvas: WebGL
Product: Firefox → Core
This is an open issue in the WebGL spec: whether the canvas size means device pixels or CSS pixels, no?
(In reply to Boris Zbarsky (:bz) [In and out Aug 1 - 10, out Aug 11-20] from comment #1)
> This is an open issue in the WebGL spec: whether the canvas size means
> device pixels or CSS pixels, no?

Correspondance between units is a separate issue if I understand correctly… in any case, there is no reason to perform drawing in low resolution.
There are reasons to make the backing store in device pixels match the canvas dimensions (whether those are CSS pixles or not).  See the public_webgl mailing list threads on the topic...
The WebGL spec, section 2.2,
http://www.khronos.org/registry/webgl/specs/latest/
says that the WebGL drawing buffer creation should attempt to use the canvas size as the drawing buffer size, but it that fails for whatever reason, it is OK to fall back to a smaller size. The effective drawing buffer size can always be queried as the drawingBuffer{Width,Height} properties.

I haven't followed recent mailing list discussion, but that is the current state of the spec.

I would, however, make the claim that using the low resolution, not the "retina" resolution, _is_ what you typically want for the WebGL drawing buffer, as WebGL anti-aliasing is enabled by default, making the low resolution generally look acceptable (it isn't that low) and the high resolution can quickly overwhelm the GPU with nontrivial WebGL fragment shaders.
Did you mean to paste a different link? Or was this a philosophical statement about recursivity and reflexivity?
Summary: WebGL is not in high resolution on Retina display → [HiDPI] WebGL is not in high resolution on Retina display
OK, so, thinking further about it --- it seems that all what we want to do here is, in WebGLContext::SetDimensions, multiply the width and height parameters by AppUnitsPerDevPixel() so that e.g. if the ratio is 2, and the page requests a 400x300 canvas, it gets a 800x600 drawing buffer.

Correct?

I was scared of doing that because of the overhead that this incurs on the fragment shaders (4x the amount of work), but that overhead is the same as in every other aspect of gfx, so I assume that the device manufacturer takes the responsibility to properly adjust the GPU fragment shader performance to the high number of pixels.

So how do I get the device-to-css-pixel ratio? I've seen AppUnitsPerDevPixel() but it lives in nsPresContext and I'm not sure if I can access that easily from content/canvas/ code?

There are other issues to sort out as well such as, as Gregg points out on this thread, what should texImage2D when passed a canvas element, but we can figure that later once we have a first-pass patch. There is a conformance test,
https://www.khronos.org/registry/webgl/sdk/tests/conformance/canvas/drawingbuffer-hd-dpi-test.html
> and I'm not sure if I can access that easily from content/canvas/ code?

You can in some cases, but not all.  Specifically not when you don't have a prescontext.

roc, is it reasonable to expose some sort of static accessor for this sort of thing?

Note that this ratio can technically be different for different parts of a page, really (consider a multimonitor system with both hi-dpi and normal-dpi monitors, and a window spanning monitors....).  So you don't want the "real" app unit to dev pixel ratio; you want something that sorta fakes it.
(In reply to Boris Zbarsky (:bz) from comment #9)
> roc, is it reasonable to expose some sort of static accessor for this sort
> of thing?

No, I don't think we should do that. In the multimonitor case you mention, we obviously can't change WebGL objects on the fly when the window moves from one monitor to another, but we should at least be able to use the page's current resolution when setting up the WebGL canvas.

We have code in nsContentUtils::WidgetForDocument that works hard to find the presentation associated with a document. We should factor out the part that finds an nsIPresShell and expose that as nsContentUtils::GetPresShellForDocument. Then get AppUnitsPerDevPixel from that presshell's nsPresContext --- and store it somewhere, probably WebGLContext, to make sure that everything stays consistent after that even if AppUnitsPerDevPixel changes.
Note that this would affect the backing store for WebGL contexts in full-zoomed pages. I think that's a good thing.
Has the WebGL group actually agreed that adjusting the WebGL buffer size automatically is the right thing to do? I don't see such agreement on the list. I see some people saying that that's unacceptable.
I believe the current plan was to follow the Canvas spec, which says that width and height are in CSS pixels, not device pixels, and that these values may differ.

In practice, this would mean a drawingBufferWidth of twice the canvas width on 'high-dpi' screens. Yes, this can break content.

Confirming, since it's clear this is an issue, even if we're still talking about how to address it. Marking as 'enhancement' since we're within spec here.
Severity: normal → enhancement
Status: UNCONFIRMED → NEW
Ever confirmed: true
Doing it on full-zoomed pages may be a little aggressive... it means that we'll either have to dispatch a context lost event (if the page has handlers registered, I guess?) or deal with different-looking webgl rendering based on whether the user opened a page and then zoomed, or reloaded while it was already zoomed (or loaded with a saved zoom value), right?
Yes. And if we handle HiDPI as suggested then we'll get different-looking WebGL rendering when you open a page on monitor A and move it to monitor B, or just open it on monitor B, when A and B have very different DPI.

But I think this is all reasonably OK.
Assignee: nobody → jgilbert
Status: NEW → RESOLVED
Closed: 5 years ago
Resolution: --- → WORKSFORME
Resolution: WORKSFORME → INCOMPLETE

Looks like the WG decided that gl.drawingbufferWidth should always be canvas.width. (see the comment in the test in Comment 8)

Resolution: INCOMPLETE → INVALID
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: