seerge/g-helper · warning · Exception

Failed to get switchable graphics applications. Error code:

Error message

Failed to get switchable graphics applications. Error code: 

What it means

Thrown inside AmdGpuControl.KillGPUApps when the AMD Display Library call ADL2_SwitchableGraphics_Applications_Get returns a value other than ADL_SUCCESS (0). This is a P/Invoke into atiadlxx.dll (AmdAdl2.cs:534) that enumerates applications with GPU affinity; the iListType argument is hardcoded to 2. AMD ADL returns negative integer codes (e.g. ADL_ERR=-1, ADL_ERR_NOT_INIT=-2, ADL_ERR_INVALID_PARAM=-3, ADL_ERR_NOT_SUPPORTED=-8), which are appended to the message. Note the whole block is wrapped in try/catch that calls Logger.WriteLine, so the exception is caught and logged and KillGPUApps simply degrades to not killing any apps.

Source

Thrown at app/Gpu/AMD/AmdGpuControl.cs:374

        return performanceLevels;
    }

    public void KillGPUApps()
    {

        if (!IsValid) return;

        nint appInfoPtr = nint.Zero;
        int appCount = 0;

        try
        {
            // Get switchable graphics applications information
            var result = ADL2_SwitchableGraphics_Applications_Get(_adlContextHandle, 2, out appCount, out appInfoPtr);
            if (result != 0)
            {
                throw new Exception("Failed to get switchable graphics applications. Error code: " + result);
            }

            // Convert the application data pointers to an array of structs
            var appInfoArray = new ADLSGApplicationInfo[appCount];
            nint currentPtr = appInfoPtr;

            for (int i = 0; i < appCount; i++)
            {
                appInfoArray[i] = Marshal.PtrToStructure<ADLSGApplicationInfo>(currentPtr);
                currentPtr = nint.Add(currentPtr, Marshal.SizeOf<ADLSGApplicationInfo>());
            }

            var appNames = new List<string>();

            for (int i = 0; i < appCount; i++)
            {
                if (appInfoArray[i].iGPUAffinity == 1)
                {

View on GitHub (pinned to b9ba417f1b)

Solutions

  1. Update the AMD Adrenalin driver to a version that supports ADL2 switchable graphics on this hardware.
  2. Keep the existing 'if (!IsValid) return;' guard and also early-return when _iGPU is null (no integrated GPU means no switchable graphics).
  3. Stop throwing for a non-zero result: log the code and return, since KillGPUApps is already best-effort and wrapped in try/catch.
  4. Verify Adl2.Load() succeeded and _adlContextHandle is non-zero before calling (IsValid covers this but pair it with the _iGPU null check).
  5. Decode the returned code against known ADL constants (ADL_ERR, ADL_ERR_NOT_SUPPORTED) to log a precise reason.

Example fix

// before
var result = ADL2_SwitchableGraphics_Applications_Get(_adlContextHandle, 2, out appCount, out appInfoPtr);
if (result != 0)
    throw new Exception("Failed to get switchable graphics applications. Error code: " + result);
// after
var result = ADL2_SwitchableGraphics_Applications_Get(_adlContextHandle, 2, out appCount, out appInfoPtr);
if (result != Adl2.ADL_SUCCESS)
{
    Logger.WriteLine($"ADL2_SwitchableGraphics_Applications_Get failed (code {result}); skipping GPU app cleanup.");
    return;
}
Defensive patterns

Strategy: try-catch

Validate before calling

// The strongest pre-check available is the public IsValid property plus a switchable-GPU presence check.
if (!amdGpu.IsValid) return;             // ADL context not created (AmdGpuControl.cs:95)
if (amdGpu._iGPU is null)   return;       // no integrated GPU => no switchable graphics
// Note: _iGPU is private; expose a bool HasSwitchableGraphics property if you need this guard outside the class.

Try / catch

// KillGPUApps already does this — keep it, but stop throwing inside the try:
try
{
    var result = ADL2_SwitchableGraphics_Applications_Get(_adlContextHandle, 2, out appCount, out appInfoPtr);
    if (result != Adl2.ADL_SUCCESS)
    {
        Logger.WriteLine($"KillGPUApps: switchable-graphics query failed (ADL code {result}).");
        return;
    }
    // ... process appInfoArray ...
}
catch (Exception ex)
{
    Logger.WriteLine($"KillGPUApps: {ex.Message}");
}
finally
{
    if (appInfoPtr != nint.Zero) Marshal.FreeCoTaskMem(appInfoPtr);
}

Prevention

When it happens

Trigger: Calling KillGPUApps when ADL2_SwitchableGraphics_Applications_Get(_adlContextHandle, 2, out appCount, out appInfoPtr) returns non-zero. This happens when the ADL context handle is stale/uninitialized, atiadlxx.dll is the wrong version, the driver does not support switchable graphics or list type 2, no discrete+integrated GPU pairing exists, or the call is made after ADL2_Main_Control_Destroy. The guard 'if (!IsValid) return;' (line 363) only checks _isReady && _adlContextHandle != 0, so a valid-but-not-fully-functional context still reaches the throwing call.

Common situations: AMD Adrenalin driver is missing, outdated, or a version that dropped the switchable-graphics API; the system is a desktop with a single AMD GPU (no switchable graphics); atiadlxx.dll loaded but ADL2_Main_Control_Create partially failed; running on an Intel/NVIDIA-only machine where Adl2.Load succeeded by accident; the context was disposed while KillGPUApps ran. Because it is logged and swallowed, users usually only see it in the log file, not as a crash.

Related errors


AI-assisted analysis of seerge/g-helper@b9ba417f1b (2026-08-13). Data as JSON: /api/errors/183c57ffe3641798. Report an issue: GitHub.