Хит производительности от смешивания большого четырехугольника - PullRequest
9 голосов
/ 21 ноября 2011

У меня есть игра, которая работает довольно хорошо (55-60 кадров в секунду) на дисплее сетчатки. Я хочу добавить полноэкранный оверлей, который сочетается с существующей сценой. Тем не менее, даже при использовании небольших текстур, производительность снижается. Могу ли я выполнить оптимизацию, чтобы сделать это полезным?

Если я использую текстуру 80x120 (текстура отображается на лету, поэтому она не квадратная), я получаю 25-30FPS. Если я уменьшу текстуру, производительность повысится, но качество не будет приемлемым. Однако в целом качество наложения не очень важно (это просто освещение).

Коэффициент использования рендерера составляет 99%.

Даже если я использую квадратную текстуру из файла (.png), производительность плохая.

Вот как я создаю текстуру:

    [EAGLContext setCurrentContext:context];

    // Create default framebuffer object.
    glGenFramebuffers(1, &lightFramebuffer);
    glBindFramebuffer(GL_FRAMEBUFFER, lightFramebuffer);

    // Create color render buffer and allocate backing store.
    glGenRenderbuffers(1, &lightRenderbuffer);
    glBindRenderbuffer(GL_RENDERBUFFER, lightRenderbuffer);
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, LIGHT_WIDTH, LIGHT_HEIGHT);

    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, lightRenderbuffer);

    glGenTextures(1, &lightImage);
    glBindTexture(GL_TEXTURE_2D, lightImage);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, LIGHT_WIDTH, LIGHT_HEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

    glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, lightImage, 0);

А вот и рендеринг ...

/* Draw scene... */

glBlendFunc(GL_ONE, GL_ONE);


//Switch to offscreen texture buffer
glBindFramebuffer(GL_FRAMEBUFFER, lightFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, lightRenderbuffer);
glViewport(0, 0, LIGHT_WIDTH, LIGHT_HEIGHT);

glClearColor(ambientLight, ambientLight, ambientLight, ambientLight);
glClear(GL_COLOR_BUFFER_BIT);

/* Draw lights to texture... */

//Switch back to main frame buffer
glBindFramebuffer(GL_FRAMEBUFFER, defaultFramebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
glViewport(0, 0, framebufferWidth, framebufferHeight);  

glBlendFunc(GL_DST_COLOR, GL_ZERO);

glBindTexture(GL_TEXTURE_2D, glview.lightImage);    

/* Set up drawing... */

glDrawElements(GL_TRIANGLE_FAN, 4, GL_UNSIGNED_SHORT, 0);

Вот некоторые критерии, которые я взял, пытаясь сузить проблему. «Без наложения» означает, что я glDisable (GL_BLEND) перед тем, как нарисовать квад. «Без переключения буфера» означает, что я не переключаюсь назад и вперед из закадрового буфера перед рисованием.

(Tests using a static 256x256 .png)
No blend, No buffer switching: 52FPS
Yes blend, No buffer switching: 29FPS //disabled the glClear, which would artificially speed up the rendering
No blend, Yes buffer switching: 29FPS
Yes blend, Yes buffer switching: 27FPS

Yes buffer switching, No drawing: 46FPS

Любая помощь приветствуется. Спасибо!

UPDATE

Вместо того, чтобы смешивать всю карту освещения впоследствии, я закончил тем, что написал шейдер, чтобы сделать работу на лету. Каждый фрагмент сэмплируется и смешивается с картой освещения (что-то вроде мультитекстурирования). Сначала прирост производительности был минимальным, но затем я использовал lowp sampler2d для карты освещения, а затем я получил около 45FPS.

Вот фрагментный шейдер:

lowp vec4 texColor = texture2D(tex, texCoordsVarying);
lowp vec4 lightColor = texture2D(lightMap, worldPosVarying);
lightColor.rgb *= lightColor.a;
lightColor.a = 1.0;

gl_FragColor = texColor * color * lightColor;

Ответы [ 4 ]

3 голосов
/ 22 ноября 2011

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

Итак, смешанный квад по размеру экрана читает, а затем записывает каждый фрагмент на экране. Ой!

Ускорение glClear связано с тем, что вы говорите GL, что вам нет никакого дела до содержимого буфера перед рендерингом, что сохраняет загрузку предыдущего содержимого в память.

Здесь очень хороший обзор оборудования iOS: http://www.imgtec.com/factsheets/SDK/POWERVR%20SGX.OpenGL%20ES%202.0%20Application%20Development%20Recommendations.1.1f.External.pdf

Что касается фактического решения - я бы попытался напрямую визуализировать ваше наложение на игровую сцену.

Например, ваш цикл рендеринга должен выглядеть так:

[EAGLContext setCurrentContext:context];

// Set up game view port and render the game
InitGameViewPort();
GameRender();

// Change camera to 2d/orthographic, turn off depth write and compare
InitOverlayViewPort()

// Render overlay into same buffer 
OverlayRender()
1 голос
/ 27 августа 2012

Если вы выполняете рендеринг на цель рендеринга на микросхеме PowerVR, переключаетесь на другую цель рендеринга и выполняете рендеринг, а затем переключаетесь обратно на любую предыдущую цель рендеринга, и вы сильно пострадаете.Этот тип шаблона доступа помечен как «Логическая загрузка буфера» анализатором OpenGL ES, встроенным в новейшие инструменты.

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

0 голосов
/ 24 мая 2013

Еще до того, как возиться с текстурой, убедитесь, что ваш шейдер оптимизирован. При заполнении экрана 960x640 (614400 пикселей) любая операция в фрагментном шейдере оказывает огромное влияние.

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

varying mediump vec2 vertexTexCoord;
uniform sampler2D texture;

void main() {
    gl_FragColor = texture2D(texture, vertexTexCoord);
}

Создайте еще одну программу с этим фрагментным шейдером и используйте ее перед рисованием большого квадрата, затем восстановите обычную программу. IPhone 4 способен отображать около 7 полноэкранных текстурированных квадратов 1: 1 на кадр с наложением, но с более сложным шейдером он быстро падает до 1.

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

0 голосов
/ 26 февраля 2013

Я могу подтвердить, на iPad 1 с помощью iOS 4.2, включить / отключить GL_BLEND для одного полноэкранного квадроцикла, переключаемого между 18 и 31 кадр / с.В обоих прогонах использование рендерера составляло 90-100%.

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