Войти
AndroidФорумОбщее

Белый экран. Внезапно

#0
17:19, 26 мар. 2013

Activity + GLSurfaceView.Renderer
Игра запускается, текстуры на месте, всё хорошо. Я нажимаю на кнопку уровня в меню игры, загружаются необходимые текстуры и экран становится белый, а в логах выскакивает:
03-26 05:44:20.695: E/libEGL(5771): call to OpenGL ES API with no current context (logged once per thread)

Если выключить экран, а затем включить - текстуры корректно перезагружаются и уровень отображается уже нормально. Немного кода Java:

GLSurfaceView.Renderer renderer = new GLSurfaceView.Renderer()
{
    public void onSurfaceCreated(GL10 gl, EGLConfig config)
    {
      if(PlayJin.started == false)
      {
        Engine.onStart();
        Engine.started = true;
      }
      else
      {
        Engine.onResume();
      }
    }

    public void onSurfaceChanged(GL10 gl, int width, int height)
    {
        Engine.onResolutionChange(width, height);
    }

    public void onDrawFrame(GL10 gl)
    {
      Engine.onUpdate();
    }
};

Теперь по порядку:
Engine.onStart(); - загружается меню игры (текстуры) и т.д.
Engine.onResume(); - перезагружаются текстуры в случае пересоздания контекста
Engine.onResolutionChange(width, height); - установка вьюпорта, матриц
Engine.onUpdate(); - обновление/рисование

Текстуры уровня начинают загружаться в Engine.onUpdate(); при открытии уровня из меню. Такое чувство, что public void onDrawFrame(GL10 gl) и public void onSurfaceCreated(GL10 gl, EGLConfig config) вызываются из разных потоков.

Подскажите, в чём "шляпа"...

Добавлю, ранее код работал на чистом NativeActivity и такого поведения не наблюдалось.


#1
17:29, 26 мар. 2013

Tiarwe
> Такое чувство, что public void onDrawFrame(GL10 gl) и public void onSurfaceCreated(GL10 gl, EGLConfig config) вызываются из разных потоков.
А так оно и есть, если почитать маны: http://developer.android.com/reference/android/opengl/GLSurfaceView.html

Renders on a dedicated thread to decouple rendering performance from the UI thread. 
#2
17:55, 26 мар. 2013

RPGman
Я считал, что есть главный поток интерфейса (activity и т.д.) и поток рендера (GLSurfaceView). Методы интерфейса GLSurfaceView.Renderer вызываются из разных потоков что-ли? Почему тогда одни функции Gl'а вызываются корректно (вызовы рисования), а другие нет (загрузка текстур)?

#3
18:50, 26 мар. 2013

Мм.. Я погорячился, и все методы рендерера должны работать в одном треде.
Проблема в чём-то ещё. Вроде вызовов Engine.что_нибудь_юзающее_gl() из коллбеков самой активити/вьюшки.

#4
19:03, 26 мар. 2013

RPGman
Из коллбеков у меня есть следующие:

Вызываются в

GLSurfaceView:
  public static native void onPause(); // тут только остановка воспроизведения звука

  public static native void onTouchDown(float x, float y);
  public static native void onTouchMove(float x, float y);
  public static native void onTouchUp(float x, float y);

GLSurfaceView.Renderer:
  public static native int onStart();
  public static native int onUpdate();
  public static native int onResume();
  public static native void onResolutionChange(int width, int height);

Activity:
  public static native void onSetAssetManager(AssetManager assetManager);
  public static native void onSetInternalDataPath(String string);

Всё, что касается рендера (_gl()) - вызывается в GLSurfaceView.Renderer. И ещё, если потом из уровня возвращаться обратно в меню - приложение просто падает. В логе пусто...

#5
19:27, 26 мар. 2013

> Из коллбеков у меня есть следующие:
Сам факт, что методы движка зовутся не только из рендера. Оно локами обёрнуто?

#6
19:34, 26 мар. 2013

RPGman
Нет, не обёрнуто. Смысла не вижу, ведь по сути со всем работает только поток рендера. Делал по примеру sunangeles.
И ещё. При запуске уровня - экран белый, НО! Некоторые спрайты имеют правильный размер (текстура разве что либо чёрная, либо белая) и альфу видно (серые квадраты). Если контекст потерян, то разве такое должно быть? Позже скину скрин.

#7
19:44, 26 мар. 2013

Tiarwe
> Нет, не обёрнуто. Смысла не вижу, ведь по сути со всем работает только поток рендера.
Не только рендер. Все остальные события - те же остановка звука на onPause, или события ввода onTochDown и т.д. - тоже позовут твой двиг, разве нет?

> Делал по примеру sunangeles.
Там треды пересекаются на одном флаге sDemoStopped, что совершенно безопасно.

#8
22:20, 26 мар. 2013

RPGman
Буду экспериментировать, ещё раз изучу пример...

#9
14:41, 27 мар. 2013

RPGman
Всунул во все вызываемые функции из Java мьютексы - картина не изменилась. Поковырялся в логах и обратил внимание вот на что:

TID=17745 - родительский поток
TID=17754 - поток рендера

17745 ОТПРАВКА В C++ ДИРЕКТОРИИ ПРИЛОЖЕНИЯ
17754 ЗАГРУЗКА ТЕКСТУР МЕНЮ
17754 ОБНОВЛЕНИЕ/РИСОВАНИЕ
нажимаем на кнопку уровня и получаем и вдруг:
17745 ЗАГРУЗКА ТЕКСТУР УРОВНЯ
call to OpenGL ES API with no current context (logged once per thread)
17745 ЗАГРУЗКА ТЕКСТУР УРОВНЯ
17754 ОБНОВЛЕНИЕ/РИСОВАНИЕ

Отсюда и белые текстуры. Как-так получается, что загрузка текстур вдруг вызывается из родительского потока?

Из родительского потока я выполняю лишь:

JNIEXPORT void JNICALL Java_com_creobit_playjin_PlayJin_onSetAssetManager(JNIEnv* env, jclass jc, jobject jo)
{
  JIN::JC_AUTOLOCK autoLock(mutex);

  APP::_assetManager = AAssetManager_fromJava(env, jo);
}

JNIEXPORT void JNICALL Java_com_creobit_playjin_PlayJin_onSetInternalDataPath(JNIEnv* env, jclass jc, jobject jo)
{
  JIN::JC_AUTOLOCK autoLock(mutex);

  APP::_sgInternalDataFolder = env->GetStringUTFChars((jstring)(jo), 0);
}
Всё остальное вызывается из потока рендера.

#10
15:53, 27 мар. 2013

Tiarwe
> нажимаем на кнопку уровня и получаем и вдруг:
> 17745 ЗАГРУЗКА ТЕКСТУР УРОВНЯ
Такое получается, если загрузка текстур синхронная, и код, желающий грузить новые текстуры, синхронно стартует при получении события касания.
Как ты касания передаёшь и отрабатываешь?
Бронебойно будет, если передача события движку только покладёт это событие в очередь, а разгребаться очередь будет исключительно в Engine.onUpdate(). Про локи в обоих тредах не забудь, чтоб не сломать эту очередь конкурентным доступом.
Синхронно нужно передавать только onPause/onResume, и в игровом коде реакции на эти критические события не должно быть синхронных вызовов к рендеру.

#11
17:51, 27 мар. 2013

RPGman
Спасибо большое! Действительно, проблема была именно в этом.

AndroidФорумОбщее

Тема в архиве.