Вирішення проблеми втрати контексту OpenGL, коли Android призупиняється?


40

Документація на Android говорить:

Бувають ситуації, коли контекст надання EGL буде втрачено. Зазвичай це відбувається, коли пристрій прокидається після сну. При втраті контексту EGL всі ресурси OpenGL (наприклад, текстури), пов'язані з цим контекстом, будуть автоматично видалені. Для правильного відображення рендерінг повинен відтворити будь-які втрачені ресурси, які йому ще потрібні. Метод onSurfaceCreate (GL10, EGLConfig) є зручним місцем для цього.

Але перезавантажити всі текстури в контексті OpenGL - це і біль, і шкодить ігровому досвіду для користувача при повторному перегляді програми після паузи. Я знаю, що «Сердиті птахи» якось уникають цього, я шукаю пропозиції, як зробити те саме?

Я працюю з Android NDK r5 (версія CrystaX.) Я знайшов цей можливий злом проблеми, але я намагаюся уникати створення цілої спеціальної версії SDK.


сон і прокидання відносять до пристрою, тому, якщо користувач просто призупиняє вашу гру або перемикає процеси, вона повинна втратити будь-який контекст EGL.
Ali1S232

Відповіді:


22

Replica Island має модифіковану версію GLSurfaceView, яка займається цією проблемою (та працює з більш ранніми версіями Android). За словами Кріса Пруетта :

В основному, я зламав оригінальний GLSurfaceView, щоб вирішити дуже конкретну проблему: я хотів перейти до різних видів діяльності в моєму додатку, не викидаючи весь свій стан OpenGL. Основна зміна полягала в тому, щоб відокремити поверхню EGLStext від EGLContext та відкинути перше на Pauuse (), але зберегти останнє, поки контекст явно не буде втрачено. Реалізація GLSurfaceView за замовчуванням (яку я, до речі, не писав), викидає весь стан GL, коли діяльність призупинена, і викликаєSurfaceCreate (), коли вона відновлена. Це означало, що коли в моїй грі з’явилося діалогове вікно, закриття його спричинило затримку, оскільки всі текстури довелося перезавантажувати.

Вам слід використовувати стандартний GLSurfaceView. Якщо ви повинні мати той самий функціонал, що і мій, ви можете подивитися на моєму. Але, роблячи те, що я робив, викривали всілякі жахливі помилки драйверів у деяких телефонах (див. Дуже довгі коментарі наприкінці цього файлу), і ви можете уникнути всього цього безладу, просто скориставшись типовим.

Редагувати: Я щойно зрозумів, що ви вже розмістили посилання на аналогічний злом. Я не думаю, що існує якесь вбудоване рішення перед сот. Репліка-Айленд - популярна гра, що працює на багатьох пристроях, і вам можуть бути корисні реалізація та коментарі Кріса.


1
Спробувавши різні підходи до обходу цього, я вирішив, що найкращим рішенням є просто перекодувати додаток для відтворення контексту. Це такий марнотратний підхід, але схоже, що немає хорошого рішення code.google.com/p/android/isissue/detail?id=12774
Nick Gotch

9

Я хотів би додати ще одну відповідь до цього, яку мені передав рік-два назад Кріс Пруетт (Острів Репліки, Вітячий вітер тощо). Це особливо корисно тут у 2013 році, оскільки setPreserveEglContextOnPause (true) не працює на 4.3. (Я можу помилитися з цього приводу, але саме так мені здається зараз, коли я оновлював ігровий код, який востаннє торкнувся у 2011 році).

В основному хитрість полягає в тому, щоб відірвати GLSurfaceView від ієрархії подання від onPause (). Оскільки це не в ієрархії перегляду в точці запуску () (Paause ()), контекст ніколи не руйнується.

Отже, OnPause () вашої активності має виглядати так:

@Override
public void onPause() {
    view.setVisibility(View.GONE);
    super.onPause();
    ...
}

І ви відновите свій GLSurfaceView до ієрархії не з onResume (), а з onWindowFocusChanged ():

@Override
public void onWindowFocusChanged(boolean hasFocus) {
    super.onWindowFocusChanged(hasFocus);
    if (hasFocus && view.getVisibility() == View.GONE) {
         view.setVisibility(View.VISIBLE);
    }
    ...
}

Зауважте, що ви ніколи не викликаєте onPause () та onResume () GLSurfaceView, і що це офіційний SDK GLSurfaceView, не потрібна зламана альтернативна версія.


Насправді такий підхід, здається, не працює. Кріс Прует використовував це у поєднанні з Unity, чи можливо, що це вирішення не працює у рідних проектах? Але тільки виклик GLView.onPause (), здається, працює !? Чи є інші, які можуть це підтвердити?
sjkm

Він працював для мене, орієнтований на Android 2.2 OpenGl ES 2. Не впевнений, як він працює на інших пристроях. У мене телефон LG G2 D802. Хтось знає, чи це загальне рішення?
Піксель

7

<rant> Я витратив величезну кількість часу на цю проблему, я спробував багато різних рішень, і жоден не працював до сьогодні, я думаю, це одне з найжахливіших дизайнерських рішень, які я навіть бачив, але від команди Android я не дійсно здивований. </ rant>

Таким чином, рішення полягає в тому, щоб перемістити член eglContext вгору і зробити його статичним (глобальним), щоб він не був зруйнований, тоді вам просто потрібно перевірити, чи він нульовий чи ні, перш ніж створювати його знову.

Наразі це рішення, здається, працює для нас, і нам байдуже, чи не працює він на пристроях 2005 року.


4

Використовуйте API соти. Є можливість зберегти свій OGL-контекст. В іншому випадку вам потрібно перезавантажити свій контекст. Це не важко і не боляче.

Вам потрібно зрозуміти, що є два випадки (Android 2.1):

  • Екранна пауза: у вашій програмі завжди доступна передня панель => хак
  • Пауза програми: є ще одна передня програма => Немає рішення

Примітка: старий Android gpus не підтримує мультитекст. Таким чином, контекст opengl втрачається при переході на іншу програму => рішення не доступне (Ви можете зламати, щоб зберегти свій контекст на екранній паузі).

Примітка 2: Функція HoneyComb встановленаПрезерг


1
Я переношу гру C ++ на Android NDK, яка не призначена для легкого перезавантаження контексту, так що принаймні для мене це дещо складно. Труднощі в сторону, перевантаження текстур буде ввести затримку , яка не присутня на наших інших пристроях (iPhone, PSP, DS, і т.д ..) Радий чути стільникові виправлення цього , але , до жаль , ми повинні підтримувати 2.1 +
Нік Гоч

1
Це зовсім не відповідає на його запитання.
Нотлеш

1
Якщо ти не розумієш, ти не можеш цього зробити.
Елліс

2

Деякі відповіді тут обґрунтовані для раннього використання OpenGL ES на Android. Перші пристрої GLES підтримували лише один контекст, тому GLSurfaceView був розроблений для агресивного виходу із стану. Переконати GLSurfaceView зробити інакше непросто.

Для більш пізніх версій Android (напевно, все, що використовує GLES 2.x), найкраща відповідь - використовувати звичайний SurfaceView і робити власне управління EGL та потоками. Ви можете знайти кілька прикладів GLES, використовуваних із звичайним SurfaceView у Grafika , включаючи бібліотеку простих класів для створення та знищення контекстів EGL.

Це все-таки хороша практика розвантажувати стан, коли додаток переходить на другий план, але, наприклад, від Кріса Пруетта - де додаток все ще був на передньому плані, але активність, на якій розміщено GLSurfaceView, була відключена - немає значення для відриву вниз по контексту.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.