iOS: обработка кода OpenGL, выполняющегося в фоновых потоках во время перехода приложения - PullRequest
0 голосов
/ 31 мая 2018

Я работаю над приложением для iOS, которое, например, при нажатии кнопки, запускает несколько потоков, каждый из которых выполняет фрагмент кода Open GL.Эти потоки либо имеют другой набор EAGLContext, либо, если они используют один и тот же EAGLContext, то они синхронизируются (т.е. 2 потока не устанавливают один и тот же EAGLContext параллельно).

Теперь предположим, что приложение переходит в фоновый режим.Согласно документации Apple , мы должны прекратить все вызовы OpenGL в обратном вызове applicationWillResignActive:, чтобы к моменту вызова applicationDidEnterBackground: дальнейшие вызовы GL не производились.

Я использую dispatch_queues для создания фоновых тем.Например:

__block Byte* renderedData; // some memory already allocated
dispatch_sync(glProcessingQueue, ^{
  [EAGLContext setCurrentContext:_eaglContext];
  glViewPort(...)
  glBindFramebuffer(...)
  glClear(...)
  glDrawArrays(...)
  glReadPixels(...) // read in renderedData
}
use renderedData for something else

Мой вопрос - как обработать applicationWillResignActive:, чтобы любые такие фоновые вызовы GL можно было не только остановить, но и возобновить на applicationDidBecomeActive:?Стоит ли ждать завершения текущих блоков, прежде чем вернуться из applicationWillResignActive:?Или я должен просто приостановить glProcessingQueue и вернуться?

Я также читал, что аналогичный случай имеет место, когда приложение прерывается другими способами, такими как отображение предупреждения, телефонный звонок и т. Д.

У меня может быть несколько таких потоков в любой момент времени, вызванных, возможно, несколькими ViewControllers, поэтому я ищу какое-то масштабируемое решение или шаблон проектирования.

1 Ответ

0 голосов
/ 31 мая 2018

Как я вижу, вам нужно либо приостановить поток, либо убить его.

Если вы убьете его, вам нужно убедиться, что все ресурсы освобождены, что означает повторный вызов openGL, скорее всего.В этом случае может быть лучше просто дождаться окончания выполнения блока.Это означает, что блок не должен занимать слишком много времени для завершения, что невозможно гарантировать, и, поскольку у вас несколько контекстов и потоков, это может реально представлять проблему.

Так что приостановка кажется лучше.Я не уверен, есть ли прямой API для приостановки потока, но вы можете заставить его ждать.Возможно, в качестве системы, аналогичной , эта может помочь.

Кажется, что связанный пример обрабатывает именно то, что вы хотели бы;он уже проверяет текущий поток и блокирует его.Я полагаю, вы могли бы упаковать это в какой-то инструмент в виде статического метода или функции C, и там, где вы уверены, что вы можете приостановить поток, вы просто сделаете что-то вроде:

dispatch_sync(glProcessingQueue, ^{
    [EAGLContext setCurrentContext:_eaglContext];
    [ThreadManager pauseCurrentThreadIfNeeded];
    glViewPort(...)
    glBindFramebuffer(...)
    [ThreadManager pauseCurrentThreadIfNeeded];
    glClear(...)
    glDrawArrays(...)
    glReadPixels(...) // read in renderedData
    [ThreadManager pauseCurrentThreadIfNeeded];
}

У вас все еще может быть проблема сосновной поток, если он используется.Возможно, вы захотите пропустить паузу в этом случае, иначе ваша система может просто никогда больше не проснуться (хотя не уверен, попробуйте).

Итак, теперь вы смотрите на интерфейс вашего ThreadManager как что-то вроде:

+ (void)pause {
    __threadsPaused = YES;
}
+ (void)resume {
    __threadsPaused = NO;
}
+ (void)pauseCurrentThreadIfNeeded {
    if(__threadsPaused) {
        // TODO: insert code for locking until __threadsPaused becomes false
    }
}

Дайте нам знать, что вы узнали.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...