Skip to content

Fix crashes and improve hybrid mode handling in EnvyControl#234

Open
vjaykrsna wants to merge 2 commits intobayasdev:mainfrom
vjaykrsna:main
Open

Fix crashes and improve hybrid mode handling in EnvyControl#234
vjaykrsna wants to merge 2 commits intobayasdev:mainfrom
vjaykrsna:main

Conversation

@vjaykrsna
Copy link
Copy Markdown

This pull request makes several improvements to the GPU detection and mode switching logic in envycontrol.py, focusing on more robust handling of cache creation, error handling, and mode detection. The changes ensure better reliability when switching GPU modes, especially in hybrid configurations.

Improvements to GPU mode switching and cache management:

  • Changed cache file creation logic in the adapter method so that the cache is only recreated when leaving hybrid mode, preventing unnecessary cache updates and handling cases where the GPU may not be visible due to old udev rules.

Error handling and robustness:

  • Added a return None statement in get_amd_igpu_name() if the xrandr command fails, ensuring the function exits gracefully on error.

Mode detection logic:

  • Updated get_current_mode() to consider the system to be in 'integrated' mode if any of the relevant files exist (using logical ORs), instead of requiring both BLACKLIST_PATH and one of the udev rules to exist, making the detection logic more accurate and flexible.

If xrandr exits with a non-zero code the except block logged a warning
but execution fell through to the pattern.findall() call, where
xrandr_output was never assigned, causing an immediate NameError crash.
Return None explicitly so callers receive the expected sentinel value.
Two related bugs caused envycontrol to crash with 'Could not find Nvidia
GPU' even when switching to a mode that doesn't need the GPU visible:

1. get_current_mode() required BOTH the blacklist file AND the udev
   removal rule to report 'integrated'.  If only the udev rule existed
   (e.g. after a partial or interrupted previous switch), the function
   returned 'hybrid', misleading the CachedConfig adapter.

   Fix: any single EnvyControl-specific integrated-mode file is now
   sufficient to report integrated mode, since all three paths
   (/etc/modprobe.d/blacklist-nvidia.conf,
    /etc/udev/rules.d/50-remove-nvidia.rules,
    /lib/udev/rules.d/50-remove-nvidia.rules)
   are written exclusively by envycontrol for that mode.

2. CachedConfig.adapter() called create_cache_file() whenever the
   current mode was detected as hybrid, including when the requested
   switch target was also hybrid.  create_cache_file() calls
   get_nvidia_gpu_pci_bus() which parses lspci output; if a stale udev
   removal rule was hiding the NVIDIA device the function called
   sys.exit(1), aborting before cleanup() ever ran.

   Fix: skip cache creation when the target switch is 'hybrid', since
   hybrid mode never consumes the cached PCI bus value.
Copilot AI review requested due to automatic review settings March 12, 2026 18:51
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR improves EnvyControl’s robustness around GPU mode detection and hybrid-mode transitions by adjusting when the Nvidia PCI BusID cache is written, hardening AMD iGPU name detection, and loosening integrated-mode detection to handle partially-present config artifacts.

Changes:

  • Return None from get_amd_igpu_name() when xrandr execution fails to avoid a crash path.
  • Adjust CachedConfig.adapter() cache creation conditions to avoid unnecessary cache recreation when switching to hybrid.
  • Update get_current_mode() to classify integrated when any integrated-mode marker file exists.
Comments suppressed due to low confidence (1)

envycontrol.py:658

  • use_cache is computed before create_cache_file() runs. If the cache file didn’t exist initially, this path will create it but still skip read_cache_file() and won’t rebind get_nvidia_gpu_pci_bus, so later calls during the same run may still hit live lspci and fail if the GPU becomes hidden. Consider recomputing use_cache after cache creation, or directly setting use_cache = True / rebinding after create_cache_file() succeeds.
        use_cache = os.path.exists(CACHE_FILE_PATH)

        # Only cache the GPU PCI bus when leaving hybrid mode.
        # Switching *to* hybrid never needs the cached value and the GPU
        # may not be visible via lspci if old udev removal rules are still
        # in place, which would make create_cache_file() exit early.
        if self.is_hybrid() and self.app_args.switch != 'hybrid':
            self.create_cache_file()

        if use_cache:
            self.read_cache_file()  # might not be in hybrid mode

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment thread envycontrol.py
# Switching *to* hybrid never needs the cached value and the GPU
# may not be visible via lspci if old udev removal rules are still
# in place, which would make create_cache_file() exit early.
if self.is_hybrid() and self.app_args.switch != 'hybrid':
Copy link

Copilot AI Mar 12, 2026

Choose a reason for hiding this comment

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

if self.is_hybrid() and self.app_args.switch != 'hybrid': will also run when --reset / --reset-sddm are used (since app_args.switch is None), causing an unnecessary cache (re)creation and potential failure on systems where the dGPU isn’t visible even though get_current_mode() reports hybrid. If the intent is “only when leaving hybrid mode”, it would be safer to gate on an explicit switch target (e.g., only when switch is 'integrated' or 'nvidia').

Suggested change
if self.is_hybrid() and self.app_args.switch != 'hybrid':
if self.is_hybrid() and self.app_args.switch in ('integrated', 'nvidia'):

Copilot uses AI. Check for mistakes.
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.

2 participants