Reduced performance after GPU switch
Categories
(Core :: Graphics: Layers, defect, P3)
Tracking
()
Tracking | Status | |
---|---|---|
firefox-esr68 | --- | unaffected |
firefox70 | --- | wontfix |
firefox71 | --- | wontfix |
firefox72 | --- | fixed |
People
(Reporter: mstange, Assigned: mstange)
References
(Regression)
Details
(Keywords: perf, regression)
Attachments
(2 files, 1 obsolete file)
On macOS systems with two GPUs (integrated and discrete), scrolling performance in Firefox on macOS is reduced when the current GPU is different from the GPU that was in use when the Firefox window was opened.
Steps to reproduce:
- Install gfxCardStatus from https://gfx.io/
- Start Firefox with one window, while the integrated GPU is in use.
- Go to https://www.mozilla.org/en-US/.
- Switch to the discrete GPU using gfxCardStatus.
- Open another window of the same size and go to https://www.mozilla.org/en-US/.
- Compare scrolling smoothness in the two windows, for example using Quartz Debug's FrameMeter overlay window.
- Switch back to the integrated GPU and compare scrolling smoothness again.
Expected results:
Scrolling should be equally smooth in both windows and as smooth as possible.
Actual results:
Opened on integrated GPU | Opened on discrete GPU | |
---|---|---|
Scrolled on integrated GPU | 55fps | 20fps |
Scrolled on discrete GPU | 40fps-55fps | 60fps |
Assignee | ||
Comment 1•5 years ago
|
||
Chrome recreates GLContexts when switching GPUs: https://codereview.chromium.org/231863002
Assignee | ||
Comment 2•5 years ago
•
|
||
Recreating the GLContext would mean that we'd also need to recompile shaders on GPU switch, which is, in some ways, the opposite of what bug 1494763 wants to achieve. Maybe we could keep around two GLContexts, one for each GPU, and reuse them.
Switching GPUs changes a window's CGDirectDisplayID
([[[[window screen] deviceDescription] objectForKey:@"NSScreenNumber"] unsignedIntValue]
).
I think the following might be a nice solution:
- Create one GLContext per
CGDirectDisplayID
. For compositing into a window, use the GLContext for that window's screen. - When a
CGDirectDisplayID
becomes unused, because no window is on a screen with that ID any more, keep around the GLContext if that display ID is for the internal display (CGDisplayIsBuiltin
), otherwise throw the GLContext away.
Assignee | ||
Comment 3•5 years ago
|
||
Assignee | ||
Updated•5 years ago
|
Assignee | ||
Comment 4•5 years ago
|
||
This is a regression from the Core Animation work. In the past, the OpenGL context from the compositor would follow the GPU switch. Today, all Firefox windows keep using the GPU that was driving the internal display when that Firefox window was opened.
Updated•5 years ago
|
Assignee | ||
Comment 5•5 years ago
|
||
I've done some research on this. Useful resources:
- Technical Note TN2229: Supporting Multiple GPUs on Mac OS X
- Understanding Multi-GPU and Multi-Display Setups
- Device Selection and Fallback for Graphics Rendering in Metal
- The "Metal System Trace" tool in Instruments displays GPU usage broken down by GPU, even for OpenGL work.
GLContextCGL::ForceGpuSwitchIfNeeded()
in Chrome
One thing that was not clear to me in the past was the fact that, on a dual-GPU Macbook Pro, both GPUs can be used at all times. Only one of the GPUs drives the internal display at any given time, but you are free to use the other GPU for your own rendering. If you do so, getting your context onto the screen will incur a slow copy. You can pick the GPU during pixel format creation, or after creation using CGLSetVirtualScreen
.
For example, if you include NSOpenGLPFAAllowOfflineRenderers
, using NSOpenGLPFAScreenMask, 1 << 0
in the NSOpenGLPixelFormatAttribute list will pick the integrated GPU on my machine, whereas NSOpenGLPFAScreenMask, 1 << 6
will pick the discrete GPU, without forcing a GPU switch for the internal display, and regardless of which GPU currently drives the internal display.
Metal makes GPU selection a lot clearer: there's one MTLDevice for each GPU, and you can pick any. (You'll usually use the "default" device (which is the discrete GPU) or you get the device that currently drives a given screen.)
When an NSOpenGLContext is associated with an NSView, calling -[NSOpenGLContext update]
migrates the context to the GPU that drives the screen that the window is on. This is how we were handling GPU switches before we switched to Core Animation.
For NSOpenGLContexts which are not associated with NSViews, -[NSOpenGLContext update]
does not seem to have any useful effect.
Assignee | ||
Comment 6•5 years ago
•
|
||
Here's a small program that can be used to play with these things.
Only internal display, when using integrated GPU:
mstange@Markuss-MacBook-Pro enumerate-display-masks % ./test
Active display CGDirectDisplayIDs:
- display mask: 00000000000000000000000000000001, display ID: 01111011110101111111001111111001
Available display masks for pixel format:
- display mask: 00000000000000000000000000111111, display ID: 01111011110101111111001111111001, renderer: kCGLRendererIntelHD5000ID
- display mask: 00000000000000000000011111000000, display ID: 01111011110101111111001111111001, renderer: kCGLRendererATIRadeonX4000ID (Radeon HD 7xxx)
- display mask: 00000000000000000000000000000000, display ID: 00000000000000000000000000000000, renderer: kCGLRendererGenericFloatID (Apple Software Renderer)
Only internal display, when using discrete GPU:
mstange@Markuss-MacBook-Pro enumerate-display-masks % ./test
Active display CGDirectDisplayIDs:
- display mask: 00000000000000000000000001000000, display ID: 00000100001010000000110000000110
Available display masks for pixel format:
- display mask: 00000000000000000000000000111111, display ID: 00000100001010000000110000000110, renderer: kCGLRendererIntelHD5000ID
- display mask: 00000000000000000000011111000000, display ID: 00000100001010000000110000000110, renderer: kCGLRendererATIRadeonX4000ID (Radeon HD 7xxx)
- display mask: 00000000000000000000000000000000, display ID: 00000000000000000000000000000000, renderer: kCGLRendererGenericFloatID (Apple Software Renderer)
With connected external display, using discrete GPU:
mstange@Markuss-MacBook-Pro enumerate-display-masks % ./test
Active display CGDirectDisplayIDs:
- display mask: 00000000000000000000000001000000, display ID: 00000100001010000000110000000110
- display mask: 00000000000000000000001000000000, display ID: 00011011010101100010011001010101
Available display masks for pixel format:
- display mask: 00000000000000000000000000111111, display ID: 00000100001010000000110000000110, renderer: kCGLRendererIntelHD5000ID
- display mask: 00000000000000000000011111000000, display ID: 00000100001010000000110000000110, renderer: kCGLRendererATIRadeonX4000ID (Radeon HD 7xxx)
- display mask: 00000000000000000000000000000000, display ID: 00000000000000000000000000000000, renderer: kCGLRendererGenericFloatID (Apple Software Renderer)
Assignee | ||
Comment 7•5 years ago
|
||
I've filed bug 1597547 on WebGL.
Assignee | ||
Comment 8•5 years ago
|
||
Updated•5 years ago
|
Comment 10•5 years ago
|
||
bugherder |
Comment 11•5 years ago
|
||
There's only one beta build left before Fx71 goes to RC and this seems like something which could use more baking time than the schedule allows for at this point in the cycle. Marking this as wontfix for 71 but feel free to nominate for uplift if you feel strongly otherwise about that assessment.
Assignee | ||
Comment 12•5 years ago
|
||
I agree, this is a risky change that needs some time to bake.
Updated•3 years ago
|
Description
•