Рендеринг в текстуру на iOS OpenGL ES - работает на симуляторе, но не на устройстве - PullRequest
9 голосов
/ 06 сентября 2011

Чтобы улучшить производительность моего приложения OpenGL ES для iPad, я планировал рисовать редко обновляемый, но тяжелый для рендеринга элемент в текстуру, поэтому я могу просто использовать текстуру, если элемент не нужно перерисовывать.Однако, хотя текстура правильно отображается как на симуляторе, так и на устройстве, только на симуляторе что-то фактически отображается в текстуре.

Ниже приведен код, который я добавил в проект.При настройке сцены я создаю буферы и необходимую текстуру:

int width = 768;
int height = 270;

// Prepare texture for off-screen rendering.
glGenTextures(1, &wTexture);
glBindTexture(GL_TEXTURE_2D, wTexture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
glClearColor(.9f, .3f, .6f, 1.0f); // DEBUG
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA,
  GL_UNSIGNED_BYTE, 0);
glBindTexture(GL_TEXTURE_2D, 0);

// Depth attachment buffer, always needed.
glGenRenderbuffersOES(1, &wDepth);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, wDepth);
glRenderbufferStorageOES(GL_RENDERBUFFER_OES, GL_DEPTH_COMPONENT16_OES,
  width, height);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, 0);

// Create FBO for render-to-texture.
glGenFramebuffersOES(1, &wBuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, wBuffer);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES,
  GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, wTexture, 0);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES,
  GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, wDepth);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);

A glFramebufferStatusOES на новом FBO (до того, как он, конечно, не будет связан), возвращает возвращаемое значение framebuffer complete для обоихсимулятор и устройство.Обратите внимание, что я установил розовый прозрачный цвет для текстуры, чтобы подтвердить, что текстура действительно визуализирована, и проблема в том, что текстура просто не рисуется.

Всякий раз, когда текстуру необходимо перерисоватьЯ делаю это перед рендерингом элемента:

glBindFramebufferOES(GL_FRAMEBUFFER_OES, wBuffer);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, width, height);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
// ...

и после фактического рендеринга следующее:

// ...
glPopMatrix();
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);

Наконец, каждый раз, когда экран перерисовывается, я отображаю текстуру в квадв соответствующей позиции на экране, например:

float Vertices[] = {
  -65.0f, -100.0f, .0f,
  -65.0f, 100.0f, .0f,
  -10.0f, -100.0f, .0f,
  -10.0f, 100.0f, .0f};
float Texture[] = {.0f, .0f, 1.0f, .0f, .0f, 1.0f, 1.0f, 1.0f};

glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);

glBindTexture(GL_TEXTURE_2D, wTexture);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

glVertexPointer(3, GL_FLOAT, 0, Vertices);
glTexCoordPointer(2, GL_FLOAT, 0, Texture);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D, 0);

На симуляторах iPhone и iPad (4.2, 4.3) код работает должным образом.Я вижу динамически отображаемую текстуру, отображаемую в соответствующей позиции, конечно, с розовым вместо прозрачного фона из-за моего оператора отладки.Однако на моем устройстве iPad 4.2 отображается только розовый прямоугольник, а не то, что должно было быть нарисовано в нем на этапе рендеринга в текстуру.Таким образом, текстура отображается на экране правильно, но по какой-то причине на устройстве код рендеринга в текстуру не может фактически что-либо отобразить в текстуру.

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

1 Ответ

9 голосов
/ 12 сентября 2011

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

Проблема, как представляется, заключается в том, что если для вашего основного кадрового буфера включена множественная выборка, всеВаши пользовательские FBO также должны использовать мультисэмплинг.Вы не можете выполнить рендеринг на обычную немультисэмплированную GL_TEXTURE_2D, а мультипликативная GL_TEXTURE_2D_MULTISAMPLE недоступна в OpenGL ES 2.

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

glGenFramebuffersOES(1, &wmBuffer);
glGenRenderbuffersOES(1, &wmColor);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, wmBuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, wmColor);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, 4, GL_RGBA8_OES, width, height);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, wmColor);
glGenRenderbuffersOES(1, &wmDepth);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, wmDepth);
glRenderbufferStorageMultisampleAPPLE(GL_RENDERBUFFER_OES, 4, GL_DEPTH_COMPONENT16_OES, width, height);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_DEPTH_ATTACHMENT_OES, GL_RENDERBUFFER_OES, wmDepth);

Перед рендерингом с текстурой я связываю новый буфер MSAA:

glBindFramebufferOES(GL_FRAMEBUFFER_OES, wmBuffer);

Наконец, после рендеринга я преобразовываю MSAA FBO в текстурный FBO таким же образом, как я делаю для моего основного кадрового буфера рендеринга:

glBindFramebufferOES(GL_READ_FRAMEBUFFER_APPLE, wmBuffer);
glBindFramebufferOES(GL_DRAW_FRAMEBUFFER_APPLE, wBuffer);
glResolveMultisampleFramebufferAPPLE();
GLenum attachments[] = {GL_DEPTH_ATTACHMENT_OES, GL_COLOR_ATTACHMENT0_OES, GL_STENCIL_ATTACHMENT_OES};
glDiscardFramebufferEXT(GL_READ_FRAMEBUFFER_APPLE, 3, attachments);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);

Текстуры теперь отображаются правильно (ипроизводительность отличная!)

...