Skip to content

fix: add NSSupportsAutomaticGraphicsSwitching to Info.plist#1759

Open
AasishDairelSahayaGrinspan wants to merge 1 commit intoCapSoftware:mainfrom
AasishDairelSahayaGrinspan:fix/nssupports-automatic-graphic-switching
Open

fix: add NSSupportsAutomaticGraphicsSwitching to Info.plist#1759
AasishDairelSahayaGrinspan wants to merge 1 commit intoCapSoftware:mainfrom
AasishDairelSahayaGrinspan:fix/nssupports-automatic-graphic-switching

Conversation

@AasishDairelSahayaGrinspan
Copy link
Copy Markdown

@AasishDairelSahayaGrinspan AasishDairelSahayaGrinspan commented Apr 24, 2026

Addresses high CPU usage during recording (related to #586 and #1673). Without this key, macOS may default to the integrated GPU on dual-GPU MacBooks, preventing VTEncoder from engaging hardware acceleration properly. Setting to false prefers the discrete GPU for better encoding performance.

Greptile Summary

This PR adds NSSupportsAutomaticGraphicsSwitching = false to Info.plist, which prevents macOS from switching to the integrated GPU on Intel dual-GPU MacBooks, aiming to ensure VTEncoder can engage hardware acceleration during screen recording. The change is correct in intent — false does force the discrete GPU — but applies globally for the entire app lifetime rather than only during active recording sessions.

Confidence Score: 4/5

Safe to merge with minor concerns — only affects Intel dual-GPU MacBooks and has a known battery trade-off worth acknowledging.

Both findings are P2: one is a trivial indentation style issue, the other is a real but non-blocking power-consumption trade-off that the team should be aware of. The functional change is correct and the fix is targeted at a real reported issue.

apps/desktop/src-tauri/Info.plist — indentation style and always-on discrete GPU concern.

Important Files Changed

Filename Overview
apps/desktop/src-tauri/Info.plist Adds NSSupportsAutomaticGraphicsSwitching=false to force discrete GPU on Intel dual-GPU MacBooks; introduces indentation inconsistency (spaces vs. tabs) and forces discrete GPU for entire app lifetime rather than only during recording.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[App Launch] --> B{Dual-GPU Intel Mac?}
    B -- No / Apple Silicon --> C[Unified GPU - No Effect]
    B -- Yes --> D{NSSupportsAutomaticGraphicsSwitching}
    D -- true / absent --> E[macOS may select Integrated GPU]
    D -- false - this PR --> F[Discrete GPU forced ON]
    E --> G{During Recording}
    G -- Integrated GPU active --> H[VTEncoder may miss HW accel\nhigh CPU fallback]
    F --> I{During Recording}
    I --> J[VTEncoder uses HW accel\nlower CPU usage]
    F --> K{App Idle / Menu Bar}
    K --> L[Discrete GPU still ON\nincreased power draw]
Loading
Prompt To Fix All With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/Info.plist
Line: 32-33

Comment:
**Indentation inconsistency**

The new keys use 4 spaces for indentation while all existing keys in the file use tabs. This mixes whitespace styles within the same XML document.

```suggestion
	<key>NSSupportsAutomaticGraphicsSwitching</key>
	<false/>
```

How can I resolve this? If you propose a fix, please make it concise.

---

This is a comment left during a code review.
Path: apps/desktop/src-tauri/Info.plist
Line: 32-33

Comment:
**Discrete GPU forced for entire app lifetime, not just recording**

Setting `NSSupportsAutomaticGraphicsSwitching` to `false` prevents macOS from ever switching to the integrated GPU while Cap is running — including when it's idle in the menu bar between recordings. On Intel dual-GPU MacBooks this continuously activates the discrete GPU, which can noticeably increase power consumption and fan activity even when the app is not encoding. Consider whether this trade-off is intentional; a more targeted approach (e.g. invoking `CGLEnable(kCGLCEMPEngine)` or the Metal equivalent only during active recording) would avoid the always-on GPU cost.

How can I resolve this? If you propose a fix, please make it concise.

Reviews (1): Last reviewed commit: "fix: add NSSupportsAutomaticGraphicsSwit..." | Re-trigger Greptile

Greptile also left 2 inline comments on this PR.

Addresses high CPU usage during recording (related to CapSoftware#586 and CapSoftware#1673).
Without this key, macOS may default to the integrated GPU on dual-GPU
MacBooks, preventing VTEncoder from engaging hardware acceleration properly.
Setting to false prefers the discrete GPU for better encoding performance.
Comment on lines +32 to +33
<key>NSSupportsAutomaticGraphicsSwitching</key>
<false/>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Indentation inconsistency

The new keys use 4 spaces for indentation while all existing keys in the file use tabs. This mixes whitespace styles within the same XML document.

Suggested change
<key>NSSupportsAutomaticGraphicsSwitching</key>
<false/>
<key>NSSupportsAutomaticGraphicsSwitching</key>
<false/>
Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/Info.plist
Line: 32-33

Comment:
**Indentation inconsistency**

The new keys use 4 spaces for indentation while all existing keys in the file use tabs. This mixes whitespace styles within the same XML document.

```suggestion
	<key>NSSupportsAutomaticGraphicsSwitching</key>
	<false/>
```

How can I resolve this? If you propose a fix, please make it concise.

Comment on lines +32 to +33
<key>NSSupportsAutomaticGraphicsSwitching</key>
<false/>
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Discrete GPU forced for entire app lifetime, not just recording

Setting NSSupportsAutomaticGraphicsSwitching to false prevents macOS from ever switching to the integrated GPU while Cap is running — including when it's idle in the menu bar between recordings. On Intel dual-GPU MacBooks this continuously activates the discrete GPU, which can noticeably increase power consumption and fan activity even when the app is not encoding. Consider whether this trade-off is intentional; a more targeted approach (e.g. invoking CGLEnable(kCGLCEMPEngine) or the Metal equivalent only during active recording) would avoid the always-on GPU cost.

Prompt To Fix With AI
This is a comment left during a code review.
Path: apps/desktop/src-tauri/Info.plist
Line: 32-33

Comment:
**Discrete GPU forced for entire app lifetime, not just recording**

Setting `NSSupportsAutomaticGraphicsSwitching` to `false` prevents macOS from ever switching to the integrated GPU while Cap is running — including when it's idle in the menu bar between recordings. On Intel dual-GPU MacBooks this continuously activates the discrete GPU, which can noticeably increase power consumption and fan activity even when the app is not encoding. Consider whether this trade-off is intentional; a more targeted approach (e.g. invoking `CGLEnable(kCGLCEMPEngine)` or the Metal equivalent only during active recording) would avoid the always-on GPU cost.

How can I resolve this? If you propose a fix, please make it concise.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is that a valid fix??

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, CGLEnable(kCGLCEMPEngine) was a bad suggestion on my part — that enables OpenGL's multi-processor engine, it has nothing to do with GPU selection. I shouldn't have cited it.

The reality is there's no clean programmatic way to switch the discrete GPU on/off only during recording in a Tauri + VideoToolbox app. You could enumerate Metal devices via MTLCopyAllDevices() and explicitly pick a non-low-power device when creating your encoder, but VideoToolbox's VTCompressionSession manages its own GPU selection internally and doesn't expose a direct "use this GPU" override.

The NSSupportsAutomaticGraphicsSwitching = false plist key is the correct and standard approach. The always-on discrete GPU trade-off is real, but worth noting:

  • Only affects Intel dual-GPU MacBooks (2016–2019 era, increasingly rare)
  • On those machines, software-encoding fallback (the problem being fixed) burns more CPU/battery than keeping the discrete GPU active

The PR as-is is the right fix. My concern about "entire app lifetime" was valid to flag but the practical alternative doesn't really exist cleanly — so merging this is fine.

Tip: You can customize Greptile's behavior for this repo with .greptile/rules and .greptile/config.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NSSupportsAutomaticGraphicsSwitching = false changed this and the issue still exist , so how can i fix it ,any idea???

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the plist change didn't help, the issue is likely not GPU switching — it's something in the encoder pipeline itself. Looking at crates/enc-ffmpeg/src/video/h264.rs, I see a concrete problem in the recording path:

For export (is_export = true), you have:

options.set("allow_sw", "0");  // Forces hardware, fails hard if unavailable

For realtime recording, you don't set allow_sw at all — which means VideoToolbox's default (allow_sw = true) silently falls back to software encoding internally without any error. The code thinks it's using h264_videotoolbox (hardware), but VTB is actually encoding in software, causing high CPU.

Fix: Add allow_sw = "0" to the recording path so VTB either uses hardware or fails explicitly (triggering fallback to libx264 with a proper warning log):

// in crates/enc-ffmpeg/src/video/h264.rs, "h264_videotoolbox" match arm
"h264_videotoolbox" => {
    if is_export {
        options.set("realtime", "false");
        options.set("profile", "main");
        options.set("allow_sw", "0");
    } else {
        options.set("realtime", "true");
        options.set("prio_speed", "true");
        options.set("profile", "main");
        options.set("allow_sw", "0");  // add this
    }
}

Also worth checking: The debug logs. When recording starts, look for:

  • "Selected hardware H264 encoder" → good
  • "Using SOFTWARE H264 encoder" → means libx264 was selected instead of VTB
  • "Created SOFTWARE scaler for pixel format conversion (CPU-intensive)" → means the pixel format from screen capture doesn't match what VTB expects, causing a CPU-side format conversion even if the encoder itself is hardware

The software scaler case would cause high CPU regardless of the plist change.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if i give the log can you probe the issue??

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, share the logs and I can dig in. Most useful would be:

  1. Tauri/app logs from when a recording starts — look for lines mentioning h264_videotoolbox, allow_sw, scaler, or encoder
  2. FFmpeg/encoder init output — any codec selection messages
  3. Console.app output filtered to your app process during recording start

The key signals I'm looking for:

  • Which encoder was actually selected (hardware VTB vs libx264)
  • Whether a software scaler is being spun up for pixel format conversion
  • Any VTB error codes (e.g. -12902 = no hardware available, -12908 = format unsupported)

Paste them here and I'll trace the issue.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tell me the steps to genrate the log

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here's how to capture the logs:

1. Run the app in dev mode (gets you Rust/FFmpeg logs directly in terminal):

cd apps/desktop
pnpm tauri dev

This streams all println!, log::info!, eprintln! output to the terminal. Start a recording and watch for encoder selection messages.

2. If you need logs from a release build, use Console.app:

  • Open Console.app (Applications → Utilities)
  • In the search bar, type your app name (Cap) and filter by Process
  • Click Start before launching the app
  • Start a recording session
  • Stop and export the log (File → Export)

3. Capture VideoToolbox errors specifically:
In a terminal, run this before starting the app:

log stream --process Cap --level debug 2>&1 | tee cap_recording.log

Then start the app and trigger a recording. Press Ctrl+C when done. The log file will have everything.

4. What to look for and paste here:

  • Lines containing: h264_videotoolbox, allow_sw, scaler, libx264, encoder, VT, pixel format
  • Any lines with error codes like -12902, -12908
  • Anything around the moment recording starts

The pnpm tauri dev route is easiest — just start it, record for 10–15 seconds, stop, and paste the terminal output here.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant