Почему этот код OpenGL ES работает медленно на iPhone?

Я немного изменил пример GLSprite для iPhone SDK во время изучения OpenGL ES, и он оказался довольно медленным. Даже в симуляторе (в худшем случае) я, должно быть, делаю что-то не так, потому что там всего 400 текстурированных треугольников.

const GLfloat spriteVertices[] = {
  0.0f, 0.0f, 
  100.0f, 0.0f,  
  0.0f, 100.0f,
  100.0f, 100.0f
};

const GLshort spriteTexcoords[] = {
  0,0,
  1,0,
  0,1,
  1,1
};

- (void)setupView {
    glViewport(0, 0, backingWidth, backingHeight);
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrthof(0.0f, backingWidth, backingHeight,0.0f, -10.0f, 10.0f);
    glMatrixMode(GL_MODELVIEW);

    glClearColor(0.3f, 0.0f, 0.0f, 1.0f);

    glVertexPointer(2, GL_FLOAT, 0, spriteVertices);
    glEnableClientState(GL_VERTEX_ARRAY);
    glTexCoordPointer(2, GL_SHORT, 0, spriteTexcoords);
    glEnableClientState(GL_TEXTURE_COORD_ARRAY);

    // sprite data is preloaded. 512x512 rgba8888   
    glGenTextures(1, &spriteTexture);
    glBindTexture(GL_TEXTURE_2D, spriteTexture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    free(spriteData);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glEnable(GL_TEXTURE_2D);
    glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
    glEnable(GL_BLEND);
} 

- (void)drawView {
  ..
    glClear(GL_COLOR_BUFFER_BIT);
    glLoadIdentity();
    glTranslatef(tx-100, ty-100,10);
    for (int i=0; i<200; i++) { 
        glTranslatef(1, 1, 0);
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
    }
  ..
}

drawView вызывается каждый раз при касании экрана или перемещении пальца по экрану, а tx, ty устанавливаются в координаты x, y, в которых произошло это касание.

Я также пробовал использовать GLBuffer, когда перевод был предварительно сгенерирован и был только один DrawArray, но давал ту же производительность (~ 4 FPS).

=== РЕДАКТИРОВАТЬ ===

Тем временем я изменил это так, чтобы использовались квадрицепсы гораздо меньшего размера (размер: 34x20) и было намного меньше перекрытий. На весь экран ~ 400 квадратов-> 800 треугольников. Размер текстуры - атлас 512x512 и RGBA_8888, а координаты текстуры - плавающие. Код очень уродлив с точки зрения эффективности API: есть два изменения MatrixMode вместе с двумя загрузками и два перевода, а затем вытяжные массивы для треугольной полосы (четырехугольника). Теперь это дает ~ 45 FPS.


person f3r3nc    schedule 16.01.2009    source источник


Ответы (5)


(Я знаю, что это уже очень поздно, но я не мог устоять. Я все равно отправлю сообщение, на случай, если другие люди придут сюда за советом.)

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

После того, как треугольник был отображен во вьюпорте, он растрируется. Для каждого пикселя на экране, который покрывает ваш треугольник, вызывается шейдер фрагмента. Фрагментный шейдер по умолчанию (OpenGL ES 1.1, который вы используете) будет искать тексел, который наиболее точно отображает (GL_NEAREST) ​​на пиксель, который вы рисуете. Он может найти 4 текселя, поскольку вы используете более качественный метод GL_LINEAR для усреднения лучшего текселя. Тем не менее, если количество пикселей в вашем треугольнике составляет, скажем, 100, то наибольшее количество байтов текстуры, которое вам нужно будет прочитать, составляет 4 (поиск) * 100 (пикселей) * 4 (байтов на цвет. Намного меньше, чем то, что говорил Нильс. Удивительно, что он может заставить это звучать так, будто действительно знает, о чем говорит.

WRT мозаичная архитектура, это распространено во встроенных устройствах OpenGL для сохранения локальности ссылки. Я считаю, что каждая плитка подвергается каждой операции рисования, быстро удаляя большинство из них. Затем плитка сама решает, что нарисовать. Это будет намного медленнее, когда вы включили смешивание, как и вы. Поскольку вы используете большие треугольники, которые могут перекрываться и сливаться с другими плитками, графическому процессору приходится делать много дополнительной работы. Если бы вместо рендеринга примера квадрата с альфа-краями вы должны были рендерить фактическую форму (вместо квадратного изображения фигуры), тогда вы могли бы отключить смешивание для этой части сцены, и я уверен, что это ускорит процесс. чрезвычайно.

Если вы хотите попробовать, просто отключите смешивание и посмотрите, насколько все ускоряется, даже если оно выглядит неправильно. glDisable (GL_BLEND);

person Bruce Miller    schedule 28.03.2010
comment
спасибо за Ваш ответ. собственно, вызов 200x2 ogl тоже надо убрать. вместо этого вся сцена должна быть заглушена одним вызовом glDraw. Я попробую оба и дам вам знать результат. - person f3r3nc; 30.03.2010
comment
отключение смешивания увеличивает fps в 10 раз. Коэффициент использования плиточника со смешиванием составил ~ 5%. ~ 45% без. gldraw по-прежнему вызывается 200 раз. ух ты. - person f3r3nc; 15.04.2010
comment
Насколько я понимаю, на каждой плитке должна храниться очередь из каждого пересекающего ее треугольника. Без смешивания треугольник, покрывающий плитку, может очистить очередь плиток от всего, что было нарисовано до него. При смешивании плитки должны держать полную очередь всего нарисованного до самого конца. Раньше я работал над графическими процессорами для компании, которая использовала специальные ASIC для графических процессоров на своих видеочипах. И я до сих пор не совсем понимаю тайлинг. Удачи. - person Bruce Miller; 16.04.2010
comment
если мы предположим, что коэффициент использования плиточника на самом деле постоянный, если мы увеличим общую скорость в 10 раз, относительный процент времени плиточника также должен вырасти (почти) в 10 раз. Скорость заполнения пикселей стала намного выше без альфа-смешивания по двум причинам. Первая причина в том, что альфа-смешение само по себе является дорогостоящим процессом, а во-вторых, механизм тайлинга может выполнять свою работу только тогда, когда альфа-блендирование / альфа-тест отключено. - person noop; 20.07.2010
comment
Забыл добавить, что, вероятно, каждое оборудование для текстурирования имеет встроенный кеш текстур. Поэтому при использовании GL_LINEAR обычно не умножают объем выборки памяти на 4. Вместо того, чтобы делать одну выборку из кеша, аппаратное обеспечение будет делать 4 параллельно. В случае пропуска кеша из системной памяти будет прочитана вся строка кеша с данными для нескольких соседних пикселей. - person noop; 26.12.2011

Ваша текстура имеет размер 512 * 512 * 4 байта на пиксель. Это мегабайт данных. Если вы визуализируете его 200 раз за кадр, вы создаете нагрузку на полосу пропускания в 200 мегабайт на кадр.

При примерно 4 кадрах в секунду вы потребляете 800 МБ / с только на чтение текстур. Для записи в фрейм и в Z-буфер также требуется полоса пропускания. Затем идет ЦП, и не стоит недооценивать требования к пропускной способности дисплея.

ОЗУ во встроенных системах (например, вашем iphone) не так быстро, как на настольном ПК. Здесь вы видите эффект нехватки полосы пропускания. ОЗУ просто не может обрабатывать данные быстрее.

Как вылечить эту проблему:

  • выберите разумный размер текстуры. В среднем у вас должен быть 1 тексель на пиксель. Это дает четкие текстуры. Я знаю - это не всегда возможно. Используй здравый смысл.

  • использовать MIP-карты. Это занимает 33% дополнительного места, но позволяет графическому чипу использовать MIP-карту с более низким разрешением, если это возможно.

  • Попробуйте меньшие форматы текстур. Может быть, вы можете использовать формат ARGB4444. Это удвоит скорость рендеринга. Также обратите внимание на форматы сжатых текстур. Декомпрессия не приводит к падению производительности, как это делается на оборудовании. На самом деле верно обратное: из-за меньшего объема памяти графический чип может быстрее читать текстурные данные.

person Nils Pipenbrinck    schedule 16.01.2009
comment
Почему текстура загружается для каждого треугольника? Разве это уже не в видеопамяти? - person f3r3nc; 16.01.2009
comment
Я не знаю об IPhone, но на портативных и встраиваемых устройствах обычно нет физической разницы между видеопамятью и системной памятью. Это называется объединенной памятью. - person Nils Pipenbrinck; 16.01.2009
comment
Также не имеет значения, находится ли текстура в видеопамяти или системной памяти с точки зрения использования полосы пропускания. Тот факт, что текстура находится в видеопамяти, не означает, что видеопамять имеет неограниченную пропускную способность. Также vid-mem не намного быстрее и умнее или около того .. - person Nils Pipenbrinck; 16.01.2009
comment
использование меньшего формата текстур не ускорило его. хотя, используя меньшие вершины (очевидно?). когда квадраты имеют размер 20x20, рендеринг выполняется достаточно быстро (~ 50 кадров / сек). даже с крупной текстурой. Я думаю, что низкая производительность связана с настройкой: 200 наложенных квадратов. - person f3r3nc; 19.01.2009
comment
Я имел в виду меньшие квадраты, а не вершины. Imagination (производитель PowerVR mbx lite) также предлагает использовать атлас текстур. и поскольку этот чип использует рендеринг на основе тайлов, я должен попробовать такую ​​настройку, в которой используются меньшие треугольники, которые распространяются по всему экрану с разумным перекрытием. - person f3r3nc; 19.01.2009
comment
Действительно, трудно понять, почему этот явно неверный ответ получил столько голосов. Да, большие текстуры будут уничтожать кеш текстур, но объем выборки памяти пропорционален только количеству визуализированных пикселей. Совет по снижению использования пропускной способности памяти на самом деле верен, но в данном случае не имеет значения. Кстати, на MBX / SGX доступ к Z-буферу / фреймбуферу использует лишь небольшой объем пропускной способности памяти, если вы не запрограммируете его неправильно. - person noop; 26.12.2011
comment
Что я считаю смешным в этом ответе, так это то, что тот, кто явно не знает iPhone, говорит о том, что скорость возможностей opengl iPhone меньше, чем у настольного компьютера. Кажется, что это происходит часто при переполнении стека. Я бы не был так уверен в этом. В частности, iPhone 5 невероятно быстр. - person badweasel; 28.09.2013
comment
@badweasel Вы ведь знаете, что ответ был написан примерно 4 года назад, верно? - person Nils Pipenbrinck; 13.10.2013
comment
Думаю, я знал об этом. Это было несколько недель назад, поэтому я точно не помню. Должно быть, я чувствовал, что ответ неверен даже в контексте того времени, когда он был написан. Прости. - person badweasel; 14.10.2013

Думаю, моя первая попытка была просто плохой (или очень хорошей) проверкой. В iPhone установлен PowerVR MBX Lite с мозаичным графическим процессором. Он разделяет экран на более мелкие плитки и делает их параллельными. Теперь в первом случае, описанном выше, подразделение могло быть немного исчерпано из-за очень большого перекрытия. Более того, они не могли быть обрезаны из-за того же расстояния, и поэтому все координаты текстуры должны были быть рассчитаны (это можно легко проверить, изменив перевод в цикле). Также из-за перекрытия параллелизм нельзя было использовать, и некоторые плитки бездействовали, а остальные (1/3) много работали.

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

person f3r3nc    schedule 03.02.2009
comment
Если включено альфа-смешение или альфа-тестирование, оптимизация перерисовки невозможна, потому что каждый пиксель может быть прозрачным и, следовательно, ничто не может быть отклонено. Тайлы не рендерится параллельно, кстати, они рендерится последовательно, но z-буфер ограничен размером тайла и реализован с использованием встроенной памяти. - person noop; 19.07.2010

Я не знаком с iPhone, но если у него нет специального оборудования для обработки чисел с плавающей запятой (я подозреваю, что нет), тогда было бы быстрее использовать целые числа, когда это возможно.

В настоящее время я разрабатываю для Android (который также использует OpenGL ES), и, например, мой массив вершин - int вместо float. Я не могу сказать, насколько это важно, но, думаю, стоит попробовать.

person Maciej Gryka    schedule 03.02.2009
comment
Огромная разница между недорогим и высокопроизводительным оборудованием Android - одна из причин, по которой Android уступала игровой платформе. У iPhone с самого начала был VFP и очень приличные аппаратные характеристики. Нет причин для отнимающих много времени уловок с целочисленной математикой. Аппаратное обеспечение PowerVR изначально принимает и использует числа с плавающей запятой. Фактически, 32-битная математика с фиксированной запятой снижает производительность. - person noop; 26.12.2011

Apple очень умалчивает о конкретных аппаратных характеристиках iPhone, что кажется очень странным для тех из нас, кто работает с консолями. Но люди смогли определить, что процессор представляет собой 32-разрядный RISC ARM1176JZF. Хорошая новость заключается в том, что в нем есть модуль с плавающей запятой, поэтому мы можем продолжать писать математический и физический код так, как мы это делаем на большинстве платформ.

http://gamesfromwithin.com/?p=239

person user61805    schedule 03.02.2009