OpenGL ES 2.0 + Каир: HUD

Я пытаюсь отобразить HUD поверх приложения OpenGL ES 2.0, написанного на C на платформе ARM Linux.

В настоящее время я использую 2 треугольника, расположенных близко к плоскости отсечения и накладывая текстуру на них. Текстура - это размер экрана и в основном прозрачная, за исключением тех частей, где у меня есть текст. Текстура создается с помощью Pango/Cairo

Если я включу HUD (раскомментирую вызов render_ui), я в настоящее время получаю 50% -ный удар производительности (идет от 60 кадров в секунду до 30 кадров в секунду).

Вот код для отображения HUD:

void render_ui(OGL_STATE_T *state) {
 glUseProgram(state->uiHandle);
 matIdentity(modelViewMatrix);
 matTranslate(modelViewMatrix, 0, 0, -0.51);
 const GLfloat *mvMat2 = modelViewMatrix;
 glViewport(0,0,state->screen_width, state->screen_height);
 glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
 glEnable(GL_BLEND);
 glBindBuffer(GL_ARRAY_BUFFER, state->uiVB);
 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, state->uiIB);
 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, state->uiTex);
 glUniform1i(_uiTexUniform, 0);
 glUniformMatrix4fv(_uiProjectionUniform, 1, 0, pMat);
 glUniformMatrix4fv(_uiModelViewUniform, 1, 0, mvMat2);
 glVertexAttribPointer(_uiPositionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0); 
 glVertexAttribPointer(_uiColorSlot, 4, GL_FLOAT, GL_FALSE, sizeof(Vertex),
 (GLvoid *) (sizeof(GLfloat) * 3));
 glVertexAttribPointer(_uiTexCoordSlot, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex),
 (GLvoid *) (sizeof(GLfloat) * 7));
 glEnableVertexAttribArray(_uiPositionSlot);
 glEnableVertexAttribArray(_uiColorSlot);
 glEnableVertexAttribArray(_uiTexCoordSlot);
 glDrawElements(GL_TRIANGLES, uiIndicesArraySize / uiIndicesElementSize,
 GL_UNSIGNED_BYTE, 0); 
 glDisableVertexAttribArray(_uiTexCoordSlot);
 glDisable(GL_BLEND);
 GLenum err;
 if ((err = glGetError()) != GL_NO_ERROR)
 printf("There was an error");
}

Должен быть более разумный способ сделать это.

1 ответ

На мобильных устройствах графические процессоры очень чувствительны к смешиванию, это по нескольким причинам:

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

Поэтому короткими мобильными GPU любят непрозрачные полигоны и ненавидят прозрачные.

Обратите внимание, что общая площадь, занимаемая прозрачными полигонами на экране, также очень важна из-за "основанной на плитке" природы большинства мобильных графических процессоров (когда плитка/бин покрыта прозрачными полигонами, вы можете потерять некоторые оптимизации GPU для нее).

Кроме того, так как вы говорите, что получаете резкое падение с 60 кадров в секунду до 30 кадров в секунду, я бы пришел к выводу, что ваш графический процессор устройства блокируется, ожидая, пока экранная синхронизация на 60 Гц будет заменена, поэтому это означает, что ваш фрейм DT может быть только кратным 16 мс, поэтому вы, вероятно, можете получить только значения fps, такие как: 60, 30, 15, 7,5,...

Итак, если вы были на 60 кадров в секунду, но добавьте что-то в основной цикл приложения, который снизит теоретические fps до 57 кадров в секунду, то из-за ожидания вертикальной синхронизации вы резко перейдете на 30 кадров в секунду. VSync может быть отключен, или методы, такие как тройная буферизация, могут использоваться для смягчения этого, но с OpenGLES способ сделать это специфичен для ОС и оборудования, с которым вы работаете... нет "официального способа сделать это, который работает на всех устройствах".

Итак, зная все это, вот некоторые предложения вернуться к 60fps:

  • Используйте уменьшенное разрешение, например: 1280x720 вместо 1920x1080, это уменьшит использование полосы пропускания и обработку фрагментов. Разумеется, это не идеальный вариант, но это может быть использовано в качестве теста для подтверждения того, что у вас проблема с полосой пропускания или фрагмента (если вы получаете 60 кадров в секунду после уменьшения разрешения, тогда у вас есть такая проблема).
  • Используйте 16-битный (R5G6B5) backbuffer вместо 32bits backbuffer (R8G8B8A8), это может уменьшить использование полосы пропускания, но с некоторой визуальной потерей качества
  • Уменьшите область смешанных поверхностей: в вашем случае это будет означать, что вы должны упорядочить свои тексты с помощью "блоков", причем каждый блок максимально подходит к тексту, подобному этому изображению из IOS docs:
  • Найдите способ отключения Vsync на вашем устройстве/используйте тройную буферизацию. Если у вас есть доступ к документам Vivante GPU (я не знаю), это может быть описано внутри.

Точка 3 - это лучшее, что нужно сделать (это то, что было сделано в большинстве мобильных игр, над которыми я работал), однако это потребует некоторой незначительной дополнительной работы. Точки 1, 2 и 3 более просты, но представляют собой только "половинные решения".

licensed under cc by-sa 3.0 with attribution.