~ubuntu-branches/ubuntu/trusty/ubuntu-drivers-common/trusty

« back to all changes in this revision

Viewing changes to share/hybrid/gpu-manager.c

  • Committer: Package Import Robot
  • Author(s): Alberto Milone
  • Date: 2014-03-19 14:49:04 UTC
  • Revision ID: package-import@ubuntu.com-20140319144904-j2teldl6ajqksyw4
Tags: 1:0.2.91
* debian/control:
  - Add build dependency on libdrm-dev.
* debian/rules:
  - Remove /etc/init/hybrid-gfx.conf.
  - Also remove the current upstart job from the architectures
    that don't ship gpu-manager.
* gpu-manager.c, tests/gpu-manager.py:
  - Replace laptop specific hack to detect the need to offload
    rendering to the discrete card with code that opens the
    available drm devices and checks the connected outputs.
    If any outputs are connected to the Intel card, then we
    choose offloading. This also helps when the monitor is
    still connected to Intel on desktop systems with Intel +
    NVIDIA systems.
  - Preliminary work to reduce code duplication in nvidia-prime.
* tests/ubuntu_drivers.py:
  - Do not abort if test_auto_install_system fails.

Show diffs side-by-side

added added

removed removed

Lines of Context:
38
38
 * authorization from the copyright holder(s) and author(s).
39
39
 *
40
40
 *
41
 
 * Build with `gcc -o gpu-manager gpu-manager.c $(pkg-config --cflags --libs pciaccess)`
 
41
 * Build with `gcc -o gpu-manager gpu-manager.c $(pkg-config --cflags --libs pciaccess libdrm)`
42
42
 */
43
43
 
44
44
#define _GNU_SOURCE
53
53
#include <dirent.h>
54
54
#include <getopt.h>
55
55
#include <time.h>
56
 
 
 
56
#include <fcntl.h>
 
57
#include "xf86drm.h"
 
58
#include "xf86drmMode.h"
57
59
 
58
60
#define PCI_CLASS_DISPLAY               0x03
59
61
#define PCI_CLASS_DISPLAY_OTHER         0x0380
64
66
     && (((c) & 0x00ffff00) != (PCI_CLASS_DISPLAY_OTHER << 8)) )
65
67
 
66
68
#define LAST_BOOT "/var/lib/ubuntu-drivers-common/last_gfx_boot"
 
69
#define OFFLOADING_CONF "/var/lib/ubuntu-drivers-common/requires_offloading"
67
70
#define XORG_CONF "/etc/X11/xorg.conf"
68
 
#define FORCE_LAPTOP "/etc/force-laptop"
69
71
#define KERN_PARAM "nogpumanager"
70
72
 
71
73
#define AMD 0x1002
832
834
    FILE *file;
833
835
    struct stat stbuf;
834
836
 
835
 
    /* If file doesn't exist */
836
 
    if (stat(amd_pcsdb_file, &stbuf) == -1) {
837
 
        fprintf(log_handle, "can't access %s\n", amd_pcsdb_file);
838
 
        return 0;
839
 
    }
840
 
    /* If file is empty */
841
 
    if ((stbuf.st_mode & S_IFMT) && ! stbuf.st_size) {
842
 
        fprintf(log_handle, "%s is empty\n", amd_pcsdb_file);
843
 
        return 0;
844
 
    }
845
 
 
 
837
    if (!exists_not_empty(amd_pcsdb_file))
 
838
        return 0;
846
839
 
847
840
    file = fopen(amd_pcsdb_file, "r");
848
841
 
1087
1080
    FILE *file;
1088
1081
    struct stat stbuf;
1089
1082
 
1090
 
    /* If file doesn't exist */
1091
 
    if (stat(xorg_conf_file, &stbuf) == -1) {
1092
 
        fprintf(log_handle, "can't access %s\n", xorg_conf_file);
1093
 
        return 0;
1094
 
    }
1095
 
    /* If file is empty */
1096
 
    if ((stbuf.st_mode & S_IFMT) && ! stbuf.st_size) {
1097
 
        fprintf(log_handle, "%s is empty\n", xorg_conf_file);
1098
 
        return 0;
1099
 
    }
1100
 
 
 
1083
    /* If file doesn't exist or is empty */
 
1084
    if (!exists_not_empty(xorg_conf_file))
 
1085
        return 0;
1101
1086
 
1102
1087
    file = fopen(xorg_conf_file, "r");
1103
1088
 
1606
1591
    if (dry_run && fake_dmesg_path) {
1607
1592
        struct stat stbuf;
1608
1593
 
1609
 
        /* If file doesn't exist */
1610
 
        if (stat(fake_dmesg_path, &stbuf) == -1) {
1611
 
            fprintf(log_handle, "can't access %s\n", fake_dmesg_path);
1612
 
            return 0;
1613
 
        }
1614
 
        /* If file is empty */
1615
 
        if ((stbuf.st_mode & S_IFMT) && ! stbuf.st_size) {
1616
 
            fprintf(log_handle, "%s is empty\n", fake_dmesg_path);
1617
 
            return 0;
1618
 
        }
 
1594
        /* If file doesn't exist or is empty */
 
1595
        if (!exists_not_empty(fake_dmesg_path))
 
1596
            return 0;
1619
1597
 
1620
1598
        sprintf(command, "grep %s %s",
1621
1599
                pattern, fake_dmesg_path);
1723
1701
}
1724
1702
 
1725
1703
 
1726
 
static int is_laptop (void) {
1727
 
    /* We only support laptops by default,
1728
 
     * you can override this check by creating
1729
 
     * the /etc/force-pxpress file
 
1704
/* Count the number of outputs connected to the card */
 
1705
int count_connected_outputs(int fd, drmModeResPtr res) {
 
1706
    int i;
 
1707
    int connected_outputs = 0;
 
1708
    drmModeConnectorPtr connector;
 
1709
 
 
1710
    for (i = 0; i < res->count_connectors; i++) {
 
1711
        connector = drmModeGetConnector(fd, res->connectors[i]);
 
1712
 
 
1713
        if (connector) {
 
1714
            switch (connector->connection) {
 
1715
            case DRM_MODE_CONNECTED:
 
1716
                fprintf(log_handle, "output %d:\n", connected_outputs);
 
1717
                connected_outputs += 1;
 
1718
 
 
1719
                switch (connector->connector_type) {
 
1720
                case DRM_MODE_CONNECTOR_Unknown:
 
1721
                    fprintf(log_handle, "\tunknown connector\n");
 
1722
                    break;
 
1723
                case DRM_MODE_CONNECTOR_VGA:
 
1724
                    fprintf(log_handle, "\tVGA connector\n");
 
1725
                    break;
 
1726
                case DRM_MODE_CONNECTOR_DVII:
 
1727
                    fprintf(log_handle, "\tDVII connector\n");
 
1728
                    break;
 
1729
                case DRM_MODE_CONNECTOR_DVID:
 
1730
                    fprintf(log_handle, "\tDVID connector\n");
 
1731
                    break;
 
1732
                case DRM_MODE_CONNECTOR_DVIA:
 
1733
                    fprintf(log_handle, "\tDVIA connector\n");
 
1734
                    break;
 
1735
                case DRM_MODE_CONNECTOR_Composite:
 
1736
                    fprintf(log_handle, "\tComposite connector\n");
 
1737
                    break;
 
1738
                case DRM_MODE_CONNECTOR_SVIDEO:
 
1739
                    fprintf(log_handle, "\tSVIDEO connector\n");
 
1740
                    break;
 
1741
                case DRM_MODE_CONNECTOR_LVDS:
 
1742
                    fprintf(log_handle, "\tLVDS connector\n");
 
1743
                    break;
 
1744
                case DRM_MODE_CONNECTOR_Component:
 
1745
                    fprintf(log_handle, "\tComponent connector\n");
 
1746
                    break;
 
1747
                case DRM_MODE_CONNECTOR_9PinDIN:
 
1748
                    fprintf(log_handle, "\t9PinDIN connector\n");
 
1749
                    break;
 
1750
                case DRM_MODE_CONNECTOR_DisplayPort:
 
1751
                    fprintf(log_handle, "\tDisplayPort connector\n");
 
1752
                    break;
 
1753
                case DRM_MODE_CONNECTOR_HDMIA:
 
1754
                    fprintf(log_handle, "\tHDMIA connector\n");
 
1755
                    break;
 
1756
                case DRM_MODE_CONNECTOR_HDMIB:
 
1757
                    fprintf(log_handle, "\tHDMIB connector\n");
 
1758
                    break;
 
1759
                case DRM_MODE_CONNECTOR_TV:
 
1760
                    fprintf(log_handle, "\tTV connector\n");
 
1761
                    break;
 
1762
                case DRM_MODE_CONNECTOR_eDP:
 
1763
                    fprintf(log_handle, "\teDP connector\n");
 
1764
                    break;
 
1765
#if 0
 
1766
                case DRM_MODE_CONNECTOR_VIRTUAL:
 
1767
                    fprintf(log_handle, "VIRTUAL connector\n");
 
1768
                    break;
 
1769
                case DRM_MODE_CONNECTOR_DSI:
 
1770
                    fprintf(log_handle, "DSI connector\n");
 
1771
                    break;
 
1772
#endif
 
1773
                default:
 
1774
                    break;
 
1775
                }
 
1776
 
 
1777
 
 
1778
                break;
 
1779
            case DRM_MODE_DISCONNECTED:
 
1780
                break;
 
1781
            default:
 
1782
                break;
 
1783
            }
 
1784
            drmModeFreeConnector(connector);
 
1785
        }
 
1786
    }
 
1787
    return connected_outputs;
 
1788
}
 
1789
 
 
1790
 
 
1791
/* See if the drm device created by a driver has any connected outputs. */
 
1792
static int has_driver_connected_outputs(const char *driver) {
 
1793
    char path[20];
 
1794
    int fd = 1;
 
1795
    drmModeResPtr res;
 
1796
    drmVersionPtr version;
 
1797
    int connected_outputs = 0;
 
1798
    int driver_match = 0;
 
1799
    int it;
 
1800
 
 
1801
    /* Keep looking until we find the device for the driver */
 
1802
    for (it = 0; fd != -1; it++) {
 
1803
        sprintf(path, "/dev/dri/card%d", it);
 
1804
        fd = open(path, O_RDWR);
 
1805
        if (fd) {
 
1806
            if ((version = drmGetVersion(fd))) {
 
1807
                /* Let's use strstr to catch the different backported
 
1808
                 * kernel modules
 
1809
                 */
 
1810
                if (driver && strstr(version->name, driver) != NULL) {
 
1811
                    fprintf(log_handle, "Found \"%s\", driven by \"%s\"\n",
 
1812
                           path, version->name);
 
1813
                    driver_match = 1;
 
1814
                    drmFreeVersion(version);
 
1815
                    break;
 
1816
                }
 
1817
                else {
 
1818
                    fprintf(log_handle, "Skipping \"%s\", driven by \"%s\"\n",
 
1819
                            path, version->name);
 
1820
                    drmFreeVersion(version);
 
1821
                    close(fd);
 
1822
                }
 
1823
            }
 
1824
        }
 
1825
        else {
 
1826
            fprintf(log_handle, "Error: can't open fd for %s\n", path);
 
1827
            break;
 
1828
        }
 
1829
    }
 
1830
 
 
1831
    if (!driver_match)
 
1832
        return 0;
 
1833
 
 
1834
    res = drmModeGetResources(fd);
 
1835
    if (!res) {
 
1836
        fprintf(log_handle, "Error: can't get drm resources.\n");
 
1837
        drmClose(fd);
 
1838
        return 0;
 
1839
    }
 
1840
 
 
1841
 
 
1842
    connected_outputs = count_connected_outputs(fd, res);
 
1843
 
 
1844
    fprintf(log_handle, "Number of connected outputs for %s: %d\n", path, connected_outputs);
 
1845
 
 
1846
    drmModeFreeResources(res);
 
1847
 
 
1848
    close(fd);
 
1849
 
 
1850
    return (connected_outputs > 0);
 
1851
}
 
1852
 
 
1853
 
 
1854
/* Check if any outputs are still connected to card0.
 
1855
 *
 
1856
 * By default we only check cards driver by i915.
 
1857
 * If so, then claim support for RandR offloading
 
1858
 */
 
1859
static int requires_offloading(void) {
 
1860
 
 
1861
    /* Let's check only /dev/dri/card0 and look
 
1862
     * for driver i915. We don't want to enable
 
1863
     * offloading to any other driver, as results
 
1864
     * may be unpredictable
1730
1865
     */
1731
 
    if (is_file(FORCE_LAPTOP)) {
1732
 
        fprintf(log_handle, "Forcing laptop mode as per %s\n", FORCE_LAPTOP);
1733
 
        return 1;
1734
 
    }
1735
 
    else {
1736
 
        if (! is_dir_empty("/sys/class/power_supply/") &&
1737
 
            is_dir("/proc/acpi/button/lid"))
1738
 
            return 1;
1739
 
        else
1740
 
            return 0;
1741
 
    }
 
1866
    return(has_driver_connected_outputs("i915"));
 
1867
}
 
1868
 
 
1869
 
 
1870
/* Set permanent settings for offloading */
 
1871
static int set_offloading(void) {
 
1872
    FILE *file;
 
1873
 
 
1874
    if (dry_run)
 
1875
        return 1;
 
1876
 
 
1877
    file = fopen(OFFLOADING_CONF, "w");
 
1878
    if (file != NULL) {
 
1879
        fprintf(file, "ON\n");
 
1880
        fflush(file);
 
1881
        fclose(file);
 
1882
        return 1;
 
1883
    }
 
1884
 
 
1885
    return 0;
1742
1886
}
1743
1887
 
1744
1888
 
2066
2210
    char *fake_lspci_file = NULL;
2067
2211
    char *new_boot_file = NULL;
2068
2212
 
2069
 
    static int fake_laptop = 0;
 
2213
    static int fake_offloading = 0;
2070
2214
 
2071
2215
    int has_intel = 0, has_amd = 0, has_nvidia = 0;
2072
2216
    int has_changed = 0;
2075
2219
        intel_loaded = 0, radeon_loaded = 0,
2076
2220
        nouveau_loaded = 0, bbswitch_loaded = 0;
2077
2221
    int fglrx_unloaded = 0, nvidia_unloaded = 0;
2078
 
    int laptop = 0;
 
2222
    int offloading = 0;
2079
2223
    int status = 0;
2080
2224
 
2081
2225
    /* Vendor and device id (boot vga) */
2108
2252
        {
2109
2253
        /* These options set a flag. */
2110
2254
        {"dry-run", no_argument,     &dry_run, 1},
2111
 
        {"fake-laptop", no_argument, &fake_laptop, 1},
2112
 
        {"fake-desktop", no_argument, &fake_laptop, 0},
 
2255
        {"fake-requires-offloading", no_argument, &fake_offloading, 1},
 
2256
        {"fake-no-requires-offloading", no_argument, &fake_offloading, 0},
2113
2257
        {"fake-lightdm", no_argument, &fake_lightdm, 1},
2114
2258
        /* These options don't set a flag.
2115
2259
          We distinguish them by their indices. */
2373
2517
        }
2374
2518
    }
2375
2519
 
2376
 
    /* Either simulate or check if dealing with a laptop */
 
2520
    /* Either simulate or check if dealing with a system than requires RandR offloading */
2377
2521
    if (fake_lspci_file)
2378
 
        laptop = fake_laptop;
 
2522
        offloading = fake_offloading;
2379
2523
    else
2380
 
        laptop = is_laptop();
2381
 
 
2382
 
    fprintf(log_handle, "Is laptop? %s\n", (laptop ? "yes" : "no"));
 
2524
        offloading = requires_offloading();
 
2525
 
 
2526
    fprintf(log_handle, "Does it require offloading? %s\n", (offloading ? "yes" : "no"));
 
2527
 
 
2528
    /* Remove a file that will tell other apps such as
 
2529
     * nvidia-prime if we need to offload rendering.
 
2530
     */
 
2531
    if (!offloading && !dry_run)
 
2532
        unlink(OFFLOADING_CONF);
2383
2533
 
2384
2534
    bbswitch_loaded = is_module_loaded("bbswitch");
2385
2535
    nvidia_loaded = is_module_loaded("nvidia");
2567
2717
 
2568
2718
        if (boot_vga_vendor_id == INTEL) {
2569
2719
            /* AMD PowerXpress */
2570
 
            if (laptop && fglrx_unloaded) {
 
2720
            if (offloading && fglrx_unloaded) {
2571
2721
                fprintf(log_handle, "PowerXpress detected\n");
2572
2722
 
2573
2723
                /* Get the BusID of the disabled discrete from dmesg */
2582
2732
                /* No further action */
2583
2733
                goto end;
2584
2734
            }
2585
 
            else if (laptop && nvidia_unloaded) {
 
2735
            else if (offloading && nvidia_unloaded) {
2586
2736
                /* NVIDIA PRIME */
2587
2737
                fprintf(log_handle, "PRIME detected\n");
2588
2738
 
2598
2748
                enable_prime(prime_settings, bbswitch_loaded,
2599
2749
                             discrete_vendor_id, alternative,
2600
2750
                             current_devices, cards_n);
 
2751
 
 
2752
                /* Write permanent settings about offloading */
 
2753
                set_offloading();
 
2754
 
2601
2755
                goto end;
2602
2756
            }
2603
2757
            else {
2711
2865
        if (boot_vga_vendor_id == INTEL) {
2712
2866
            fprintf(log_handle, "Intel IGP detected\n");
2713
2867
            /* AMD PowerXpress */
2714
 
            if (laptop && intel_loaded && fglrx_loaded && !radeon_loaded) {
 
2868
            if (offloading && intel_loaded && fglrx_loaded && !radeon_loaded) {
2715
2869
                fprintf(log_handle, "PowerXpress detected\n");
2716
2870
 
2717
2871
                enable_pxpress(current_devices, cards_n);
2718
2872
            }
2719
2873
            /* NVIDIA Optimus */
2720
 
            else if (laptop && (intel_loaded && !nouveau_loaded &&
 
2874
            else if (offloading && (intel_loaded && !nouveau_loaded &&
2721
2875
                                (alternative->nvidia_available ||
2722
2876
                                 alternative->prime_available) &&
2723
2877
                                 nvidia_loaded)) {
2724
 
                fprintf(log_handle, "Intel hybrid laptop\n");
 
2878
                fprintf(log_handle, "Intel hybrid system\n");
2725
2879
 
2726
2880
                enable_prime(prime_settings, bbswitch_loaded,
2727
2881
                             discrete_vendor_id, alternative,
2728
2882
                             current_devices, cards_n);
 
2883
 
 
2884
                /* Write permanent settings about offloading */
 
2885
                set_offloading();
 
2886
 
2729
2887
                goto end;
2730
2888
            }
2731
2889
            else {
2827
2985
        }
2828
2986
        /* AMD */
2829
2987
        else if (boot_vga_vendor_id == AMD) {
2830
 
            /* Either AMD+AMD hybrid laptop or AMD desktop APU + discrete card */
 
2988
            /* Either AMD+AMD hybrid system or AMD desktop APU + discrete card */
2831
2989
            fprintf(log_handle, "AMD IGP detected\n");
2832
2990
            if (discrete_vendor_id == AMD) {
2833
2991
                fprintf(log_handle, "Discrete AMD card detected\n");