OpenGL ES 2.0: 2D-рендеринг игр, отсутствие увеличения производительности при пакетной доработке glDraw

Я просто сделал небольшой тест. К моему удивлению, рядовые спрайты в один призыв к призыву не дают значительного повышения производительности. Ниже приведены мои результаты:

Оборудование: iPod touch 4

Дополнительная информация: OpenGL ES 2.0 . 1 спрайт (64x64), имеющий некоторую прозрачность (смайлик с тенью). НЕТ вращения, НЕТ шкалы. (Текстура привязывается только один раз в начале в функции init). Скомпилирован в режиме «Release».

В первом столбце с надписью «N» показано количество тестируемых спрайтов. Второй столбец показывает FPS, когда спрайты массируются в огромном массиве вершин (всего 1 вызов рисования). Третий столбец показывает FPS для многократных вызовов, например: 5000 обратных вызовов для 5000 спрайтов.

Бенчмарк 1: смешение альфы

Бенчмарк 1: смешение альфы

Бенчмарк 2: включение альфа-включения

Бенчмарк 2: Смешивание альфа ON

Используемое изображение смайликов:

64x64 Smiley image

Исходный код:

Для одиночного вызова:

Vertex hugeArray[SPRITE_COUNT*6];
GLsizei stride = sizeof(Vertex);
int drawCallCount = 0;

const GLvoid* pCoords = &hugeArray[0].Position[0];
const GLvoid* pColors = &hugeArray[0].Color[0];
const GLvoid* pTexCoords = &hugeArray[0].Texture[0];

glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, pCoords);
glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
glVertexAttribPointer(textureSlot, 2, GL_FLOAT, GL_FALSE, stride, pTexCoords);

GLsizei vertexCount = sizeof(hugeArray) / sizeof(Vertex);
glDrawArrays(GL_TRIANGLES, 0, vertexCount);
drawCallCount++;

cout << "DrawCall Count: " << drawCallCount << endl;

Для вызовов с несколькими вызовами:

Vertex hugeArray[SPRITE_COUNT*6];
GLsizei stride = sizeof(Vertex);
int drawCallCount = 0;

for(int i = 0; i < SPRITE_COUNT; i++){

    const GLvoid* pCoords = &hugeArray[i*6].Position[0];
    const GLvoid* pColors = &hugeArray[i*6].Color[0];
    const GLvoid* pTexCoords = &hugeArray[i*6].Texture[0];

    glVertexAttribPointer(positionSlot, 2, GL_FLOAT, GL_FALSE, stride, pCoords);
    glVertexAttribPointer(colorSlot, 4, GL_FLOAT, GL_FALSE, stride, pColors);
    glVertexAttribPointer(textureSlot, 2, GL_FLOAT, GL_FALSE, stride, pTexCoords);

    GLsizei vertexCount = 6;
    glDrawArrays(GL_TRIANGLES, 0, vertexCount);
    drawCallCount++;
}
cout << "DrawCall Count: " << drawCallCount << endl;

Я думал, что пакетные спрайты в огромный массив, приводящий к одному обратному вызову, дадут ОГРОМНОЕ увеличение производительности, но тесты показывают иначе. Любые идеи, что здесь происходит?

Спасибо, что прочитали вопрос:)

5 голосов | спросил fakhir 18 Mayam13 2013, 02:33:19

2 ответа


4

Вот несколько догадок для экспериментов:

  • Счет партии - это в основном оптимизация загрузки ЦП, а не GPU. Вместо этого попробуйте измерить производительность процессора, например, отрегулировав позиции, чтобы все обрезалось с экрана.

  • Я не удивлюсь, если водитель осознает, что каждая партия фактически указывает на непрерывный массив и объединяет их все. D3D, конечно же, делает это в некоторых случаях.

  • Рендеринг точно такой же много раз имеет разные характеристики производительности для рендеринга этого количества разных вещей из-за стоимости изменений состояния рендера. Возможно, стоит попытаться измерить рендеринг чего-то более реалистичного.

ответил Adam 18 Mayam13 2013, 05:22:49
1

На самом деле вы получаете повышение производительности, что наиболее важно для отметки N = 3000 (в случае с альфа-смешением). Разумеется, твердое 60fps для более низких отсчетов вызвано vsync, что означает, что ваши цифры фактически недействительны. Вероятно, вы бы лучше сделали что-то вроде:

glFinish ();
startTime = GetTime (); // substitute with your own timing function
DrawABunchOfStuff ();
glFinish ();
endTime = GetTime (); // substitute with your own timing function
moreAccurateTime = endTime - startTime;
SwapBuffers ();

Даже в этом случае вы по-прежнему включаете накладные расходы из других частей трубопровода; например вы можете быть заполнены, что может привести к ограничению эффективности пакетной обработки (попробуйте рисовать в окне просмотра 1x1, чтобы исключить это), или вы можете быть привязаны к трансформации, что также является фиксированной накладной, независимо от того, вы или нет (попробуйте используя самый простой примитивный вершинный шейдер, чтобы это исключить).

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

ответил Maximus Minimus 18 Maypm13 2013, 17:17:45

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132