Зачем 2 GPU?


Ноутбуки с двумя GPU появились уже очень давно. Первый MacBook Pro с такой технологией вышел еще в 2008 году.

Преимущество двух GPU в гибкости. Когда вам не нужна вся мощь видео системы, вы используете встроенное в процессор видео, наслаждаясь долгой работой от батарейки. Однако если вы захотели развлечься, то к вашим услугам мощный дискретный GPU. Да, он ест батарейку и жужжит вентиляторами, но дает хороший FPS в играх. Как же одному приложению переключать GPU?

В теории, переключение должно происходить автоматически при изменении нагрузки на видеокарту. Однако на практике все не так просто.

В Windows за переключение отвечают драйвера видеокарты. В них прописана куча игр и приложений с предпочитаемыми настройками. А пользователь может сам выбрать, когда задействовать мощное дискретное GPU, а когда хочется поработать в тишине.

В OS X с переключением все сложение. Начнем с того, что драйвера для OS X пишет сама Apple.

Кстати, это приводит к таким казусам, как очень устаревшая версия OpenGL. И никакие петиции не помогают исправить это положение.

image

gfxCardStatus


В OS X вы даже не можете понять, какой GPU сейчас работает. Если только по жужжанию вентиляторов.

К счастью, есть отличная утилита gfxCardStatus, которая показывает какая видеокарта активна, и даже позволяет переключаться между ними.

Когда включается дискретный GPU, утилита показывает, какое приложение вызвало переключение.

Проблема переключения и официальная документация


Подразумевается, что под OS X переключение происходит автоматически.

Например, в Safari обычно используется встроенный GPU. Но, если вы зайдете на сайт с WebGL, то произойдет переключение на дискретный GPU.

Однако, если вы сами захотите написать приложение, которое бы могло само выбирать режим работы, вас ждет неприятный сюрприз.

Начнем с того, что в официальной документации нет ответа на вопрос, как же правильно переключаться. При это написаны очень странные вещи. Но документация дает набор ключевых слов, по которым можно найти информацию.

Решение в Chromium


У нас есть отличный open-source проект chromium, который смог решить эту проблему. Надо создавать CGLPixelFormatObj с флагом kCGLPFAAllowOfflineRenderers при инициализации OpenGL контекста. В этом случае будет использоваться текущий (встроенный) GPU.

А если вы хотите переключится на дискретный GPU, то надо просто создать CGLPixelFormatObj без флагов. Даже OpenGL контекст не нужен. Для того, чтобы вернуться на встроенный GPU, просто удалить этот CGLPixelFormatObj:
CGLContextObj ctx;
CGLPixelFormatObj pix;
GLint npix;
std::vector<CGLPixelFormatAttribute> attribs;
    
// Use current GPU
attribs.push_back(kCGLPFAAllowOfflineRenderers); // comment this line for discrete GPU
attribs.push_back((CGLPixelFormatAttribute) 0);
    
CGLError err = CGLChoosePixelFormat(&attribs.front(), &pix, &npix);
CGLCreateContext(pix, NULL, &ctx);
CGLSetCurrentContext(ctx);
....


Закладка


Я написал тестовое приложение, которое почти работало. Почему почти? Потому что удаление CGLPixelFormatObj не приводило к переключению обратно на встроенный GPU! Причем у chromium это получалось.

Зная, что в драйверах Nvidia для Windows есть специальные настройки для chromium, и то, что они определяют chromium по имени exe'шника, я ожидал что-то подобное и здесь.

Под OS X есть более надежный способ определять приложение — Bundle Id. И если поменять Bundle Id моего приложения на org.chromium.Chromium, то, о чудо, все заработает как надо.

Самое неприятное, что без правильного Bundle Id, никак нельзя переключится обратно на встроенный GPU. А это уже не просто настройка, а серьезная проблема для написания хорошей программы.
Так же работает Bundle Id: com.apple.Safari. О себе позаботились.

А вот com.operasoftware.Opera не работает. В итоге в Opera наблюдается такое же поведение: однажды захваченный дискретный GPU никогда не освобождается, даже если вы закрываете прожорливую вкладку. Единственный способ вернутся на встроенный GPU — это закрыть приложение.

Тестовое приложение и видео


Тестовое приложение, на котором можно убедиться в отличии поведения программы при разных Bundle Id, можно скачать тут.
Так же я снял видео, на котором воспроизвел проблему.


Решение


Как же в итоге решить задачу? Так как активный GPU один на систему, то можно создавать отдельный процесс, когда вам нужен дискретный GPU. И завершать этот процесс, если нужно вернуться на встроенный GPU.

Комментарии (10)


  1. norlin
    08.02.2016 15:01

    Первый MacBook Pro с такой технологией вышел еще в 2008 году.

    Хм, а к каким моделям, всё-таки, это относится?
    У меня Macbook Pro 13 (Early 2015), и у него, насколько я знаю, нет двух GPU. gfxCardStatus тоже говорит, что «не поддерживается». Да и системная информация показывает одну только «Intel Iris Graphics 6100».

    Upd.: А, понял, дискретная стоит на 15".


    1. Lof
      08.02.2016 15:05

      В основном на 15шках, с быстрым процессором.
      en.wikipedia.org/wiki/MacBook_Pro#Technical_specifications_3


  1. AterCattus
    08.02.2016 15:03
    +3

    Интересный способ вставить палки в колеса, но себе не забыть постелить.


  1. artyfarty
    08.02.2016 17:49
    -3

    > В OS X вы даже не можете понять, какой GPU сейчас работает. Если только по жужжанию вентиляторов :)

    Activity Monitor -> Energy. Видно, какой GPU используется, и кто «виновник». Когда сталкивался с тем, что какое-то приложение без нужды подключало дискретную видяху, писал разрабам – исправляли. Не верю в какой-либо заговор :)


    1. vsapronov
      09.02.2016 05:08
      +4

      Ну да, у нас ведь на технических ресурсах так и принято: «верю», «не верю», «верю», «не верю»…


      1. artyfarty
        09.02.2016 10:59

        Ну да, а громкий заголовок про «закладку» – это так принято :)


        1. Lof
          09.02.2016 13:31
          +1

          Простите за заголовок.
          Кстати, скорее всего Apple пошла навстречу Гуглу вот тут:
          code.google.com/p/chromium/issues/detail?id=338925#c4
          «After discussion with Apple it was learned that we didn't need to actually delete and re-create those contexts. We just needed to allocate all the contexts (including the WebGL contexts) with kCGLPFAAllowOfflineRenderers:YES, and when we wanted to switch to the discrete GPU, simply allocate a standalone CGLPixelFormatObj without that specified. When we wanted to switch back to the integrated GPU, delete that CGLPixelFormatObj.»


  1. ViPppp
    08.02.2016 19:05

    > В Windows за переключение отвечают драйвера видеокарты. В них прописана куча игр и приложений с предпочитаемыми настройками.

    NVidia также включает дискретный чип при наличии D3D вызовов.


    1. Dreyk
      09.02.2016 12:26

      у меня на ноутбуке часто бывает, запускается какая-то новая игра и дико тормозит — это значит, что видеокарта не переключилась, и надо лезть в настройки и добавлять экзешник в «использовать дискретную»


      1. Lof
        09.02.2016 13:33

        Да, на Windows тоже все не просто с этим. Но все проблемы решаемы.