оптимизация вывода текстур и частоты кадров OpenGL ES 2.0 2D - PullRequest
4 голосов
/ 20 марта 2012

Я надеялся, что кто-нибудь может помочь мне добиться некоторого прогресса в некоторых тестах текстуры, которые я делаю в OpenGL ES 2.0 и iPhone 4.

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

Итак, мой тест производительности сделан путем добавления 25 новых спрайтов за касание с различной непрозрачностью и изменения их вершин в обновлении, чтобы ониподпрыгивая вокруг экрана во время вращения и запуска OpenGL ES Analyzer в приложении.

Вот где я надеюсь на некоторую помощь .... Я могу получить около 275 спрайтов 32x32 с различной непрозрачностью, отскакивающих по экрану в60 кадров в секунду.К 400 я до 40 кадров в секунду.Когда я запускаю OpenGL ES Performance Detective, он говорит мне ...

Рендеринг приложения ограничен растеризацией треугольника - процессом преобразования треугольников в пиксели.Общая площадь в пикселях всех треугольников, которые вы визуализируете, слишком велика.Чтобы рисовать с более высокой частотой кадров, упростите сцену, сократив число треугольников, их размер или оба.

Дело в том, что я просто создал тест в cocos2D, используя CCSpriteBatchNode, используя ту же текстуруи создал 800 прозрачных спрайтов и частота кадров составляет 60 кадров в секунду.

Вот некоторый код, который может быть уместным ...

Shader.vsh (матрицы устанавливаются один раз в начале)

void main()
{
    gl_Position = projectionMatrix * modelViewMatrix * position;
    texCoordOut = texCoordIn;
    colorOut = colorIn;
}

Shader.fsh (colorOutиспользуется для вычисления непрозрачности)

void main()
{
    lowp vec4 fColor = texture2D(texture, texCoordOut);
    gl_FragColor = vec4(fColor.xyz, fColor.w * colorOut.a);
}

Настройка VBO

    glGenBuffers(1, &_vertexBuf);
    glGenBuffers(1, &_indiciesBuf);
    glGenVertexArraysOES(1, &_vertexArray);

    glBindVertexArrayOES(_vertexArray);

    glBindBuffer(GL_ARRAY_BUFFER, _vertexBuf);
    glBufferData(GL_ARRAY_BUFFER, sizeof(TDSEVertex)*12000, &vertices[0].x, GL_DYNAMIC_DRAW);
    glEnableVertexAttribArray(GLKVertexAttribPosition);
    glVertexAttribPointer(GLKVertexAttribPosition, 2, GL_FLOAT, GL_FALSE, sizeof(TDSEVertex), BUFFER_OFFSET(0));

    glEnableVertexAttribArray(GLKVertexAttribTexCoord0);
    glVertexAttribPointer(GLKVertexAttribTexCoord0, 2, GL_FLOAT, GL_FALSE, sizeof(TDSEVertex), BUFFER_OFFSET(8));

    glEnableVertexAttribArray(GLKVertexAttribColor);
    glVertexAttribPointer(GLKVertexAttribColor, 4, GL_FLOAT, GL_FALSE, sizeof(TDSEVertex), BUFFER_OFFSET(16));

    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _indiciesBuf);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(ushort)*12000, indicies, GL_STATIC_DRAW);

    glBindVertexArrayOES(0);

Обновление кода

    /*

        Here it cycles through all the sprites, gets their vert info (includes coords, texture coords, and color) and adds them to this giant array
        The array is of...
        typedef struct{
             float x, y;
             float tx, ty;
             float r, g, b, a;
        }TDSEVertex;
    */

     glBindBuffer(GL_ARRAY_BUFFER, _vertexBuf);
    //glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices[0])*(start), sizeof(TDSEVertex)*(indicesCount), &vertices[start]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(TDSEVertex)*indicesCount, &vertices[start].x, GL_DYNAMIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

Код визуализации

    GLKTextureInfo* textureInfo = [[TDSETextureManager sharedTextureManager].textures objectForKey:textureName];
    glBindTexture(GL_TEXTURE_2D, textureInfo.name);

    glBindVertexArrayOES(_vertexArray);
    glDrawElements(GL_TRIANGLE_STRIP, indicesCount, GL_UNSIGNED_SHORT, BUFFER_OFFSET(start));
    glBindVertexArrayOES(0);

Вот здесьснимок экрана с 400 спрайтами (800 треугольников + 800 вырожденных треугольников), чтобы дать представление о наложении непрозрачности при движении текстур ... Опять же, я должен отметить, что VBO создается и отправляется для каждой текстуры, поэтому я связываю, а затем рисую только дваждыза кадр (поскольку есть только две текстуры).

screenshot showing layering of sprites

Извините, если это ошеломляюще, но это мой первый пост здесь, и я хотел быть тщательным.Любая помощь будет принята с благодарностью.

PS, я знаю, что я мог бы просто использовать Cocos2D вместо того, чтобы писать все с нуля, но где в этом удовольствие (и обучение)?!

ОБНОВЛЕНИЕ #1 Когда я переключаю свой фрагментный шейдер только на

    gl_FragColor = texture2D(texture, texCoordOut);

, он достигает 802 спрайтов со скоростью 50 кадров в секунду (4804 треугольника, включая вырожденные треугольники), хотя настройка непрозрачности спрайта теряется. Любые предложения относительно того, как я могу все ещеобрабатывать непрозрачность в моем шейдере, не работая на 1/4 скорости?

ОБНОВЛЕНИЕ # 2 Итак, я отказался от контроллера View и View GLKit и написал собственное представление, загруженное из AppDelegate.902 спрайта с непрозрачностью и прозрачностью при 60 кадрах в секунду.

1 Ответ

1 голос
/ 21 марта 2012

В основном разные мысли ...

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

Вы также должны уменьшить площадь своих вершин. Я бы осмелился представить, что вы можете указать x, y, tx и ty как 16-битные целые числа, а ваши цвета - как 8-битные целые без каких-либо заметных изменений в рендеринге. Это уменьшило бы размер каждой вершины с 32 байтов (восемь компонентов, каждый по четыре байта в размере) до 12 байтов (четыре двухбайтовых значения плюс четыре однобайтовых значения, без заполнения, потому что все уже выровнено) - вырезание почти Там стоит 63% пропускной способности памяти.

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

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

Предполагая, что вы в настоящее время используете текстуру 32 бит / с, вы должны хотя бы посмотреть, достаточно ли обычной RGB-текстуры 16 бит / с с использованием любого из предоставленных аппаратных режимов (особенно если 1 бит альфа плюс 5 бит на цветовой канал в соответствии с вашим искусством, так как при этом теряется только 9 бит информации о цвете по сравнению с оригиналом при снижении затрат на пропускную способность на 50%).

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

...