GL ES: оптимизация фрагмента шейдера

8

Резюме: я получаю замедление FPS, как только я пытаюсь тонировать спрайты (то есть: умножить текстуру на цвет в фрагментном шейдере)

Подробности:

Аппаратное обеспечение: iPod touch 4

Я рисую 700 спрайтов на экране, используя glDrawArrays. И да, я собираю все это в один розыгрыш. Ниже показана структура данных Vertex:

struct Vertex {
    float Position[2];
    float Color[4];
    float Texture[2];
};

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

varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord );
}

До сих пор он работает БОЛЬШОЙ, давая мне полный 60 FPS !!!

НО

Как только я изменю фрагментный шейдер на следующий (чтобы разрешить тонирование):

varying lowp vec4 DestinationColor;
varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord ) * DestinationColor;
}

Используя следующую 64x64 png текстуру, содержащую альфа-канал, рендеринг с glEnable (GL_BLEND):

введите описание изображения здесь

Производительность падает до 47 FPS только из-за этого единственного изменения {просто умножением на ОДИН вектор}} (FPS измеряется с использованием инструментов xcode и детектива OpenGL). Есть идеи, что происходит?

Спасибо.

Редактировать:

Я также попытался удалить цвет каждого атрибута вершины:

struct Vertex {
    float Position[2];
    float Texture[2];
};

И модифицируем фрагмент шейдера следующим образом:

precision lowp float;
varying lowp vec2 TexCoord;
uniform sampler2D TextureSampler;

void main(void)
{
    gl_FragColor = texture2D( TextureSampler, TexCoord ) * vec4(1.0,0.0,0.0,1.0);
}

Он работает на скорости 52 FPS для 700 спрайтов (усиление всего 5 FPS). Так что это не интерполяция, кажется, что умножение очень дорого. Только это ОДНО умножение?

fakhir
источник
У вас включен vsync? Цифры могут означать, что после изменения вы начинаете пропускать каждый второй vsync, что в среднем приводит к 45 FPS.
Msell
Я тестирую на iPhone 4, я полагаю, vsync уже включен по умолчанию. Кстати, он показывает 47 FPS в инструментах xcode, так что я думаю, что vsync на самом деле не проблема. Но мой реальный вопрос: почему производительность замедляется и как ее улучшить?
Фахир
1
У вашей текстуры есть альфа-канал? Если текстура не имеет альфа-канала, а rgb умножается на vec3, она снова рисует со скоростью 60 кадров в секунду?
Будет
Да, текстура имеет альфа-канал. Пожалуйста, смотрите текстуру, прикрепленную выше.
Фахир
2
Одноядерный SGX 535, дисплей с высоким разрешением и графическим процессором никогда не предназначался для этого. Производительность графики на родном ресурсе на этих устройствах всегда была ужасной. Вы должны либо уменьшить разрешение, либо нацелиться на 30 кадров в секунду, либо использовать более новое оборудование. Вы ожидаете чудес от этого графического процессора. Это не займет много времени, чтобы заправить его.
Шон Мидлдитч

Ответы:

2

Я не думаю , что проблема производительности происходит на умножении, а на интерполяцию из ваших DestinationColorчерез треугольники, между вершиной и фрагментарными шейдерами. У вас есть четыре floatсекунды для интерполяции между вершинами дерева, для каждого фрагмента для каждого спрайта.

Для 700 спрайтов размером 64x64 пикселя это 11468800 дополнительных операций на кадр, которые вы запрашиваете для графического процессора. Вполне возможно, что вам будет не хватать некоторых vsyncs, и, следовательно, падение до 40-ти кадровых FPS.

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

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

Панда Пижама
источник
Я отредактировал вопрос выше и добавил некоторые детали. В основном я попытался удалить каждый цвет вершины и просто умножить текстуру на вектор CONSTANT, например: gl_FragColor = texture2D (TextureSampler, TexCoord) * vec4 (1.0,0.0,0.0,1.0); , Получил 52 FPS, усиление почти 5 FPS. Но все еще слишком медленно по сравнению с без оттенка. Замедление на 8 FPS только за счет умножения одного вектора?
Фахир
3
Но это не одиночное умножение - это ~ 11 миллионов на кадр.
Максимус Минимус
1
@fakhir Разрешение экрана iPod Touch 4 составляет 960x640 пикселей. Это всего 614400 пикселей. Вы хотите сделать 700 спрайтов размером 64x64 пикселей каждый. Это 2867200 пикселей, или почти в 5 раз больше экрана. Вы, вероятно, получили свои исходные 60 кадров в секунду, потому что оптимизатор выяснил, что вы делаете, и, возможно, сэмплировал изображение только один раз, но не ожидайте, что это произойдет во всех случаях. Мобильное графическое программирование намного более ограничено, чем настольное программирование, поэтому действуйте соответственно.
Panda Pajama