Почему этот код OpenGL ES работает медленно на iPhone? - PullRequest
6 голосов
/ 16 января 2009

Я немного изменил пример 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, в то время как координаты текстуры находятся в float. Код очень уродлив с точки зрения эффективности API: есть два изменения MatrixMode вместе с двумя нагрузками и двумя трансляциями, а затем - отрисовки для треугольной полосы (четырехугольника). Теперь это производит ~ 45 FPS.

Ответы [ 5 ]

19 голосов
/ 28 марта 2010

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

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

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

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

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

3 голосов
/ 16 января 2009

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

При скорости примерно 4 кадра в секунду вы потребляете 800 Мб / с только для чтения текстур. Для записи кадров и Zbuffer также необходима пропускная способность. Тогда есть процессор, и не стоит недооценивать требования к пропускной способности дисплея.

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

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

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

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

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

2 голосов
/ 03 февраля 2009

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

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

0 голосов
/ 03 февраля 2009

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

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

0 голосов
/ 03 февраля 2009

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

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

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