Самая быстрая частота кадров в 2D возможна с Android NDK, моя попытка включена, доступны лучшие варианты?

Самая быстрая 2D-частота кадров возможна с Android NDK, моя попытка включена, доступны лучшие варианты?

Я использовал NDK и OpenGL ES 2.0 для отображения кадра как текстуры на GL_TRIANGLE_STRIP. Это было сделано на HTC Desire, на том же оборудовании, что и Nexus One. Я попытался загрузить несколько текстур GL_RGBA и переключаться между текстурами, потому что нормальная скорость заполнения с одной текстурой была разочаровывающе низкой:

  • 1 текстура: 4,78 кадра в секунду
  • 2 текстуры: 19,68 кадра в секунду
  • 3 текстуры: 20,18 кадра в секунду
  • 4 текстуры: 28,52 кадра в секунду
  • 5 текстур: 29.01 кадров в секунду
  • 6 текстур: 30,32 кадра в секунду

Я думаю, что даже 30,32 кадра в секунду RGBA все равно слишком медленно.

Так можно ли добиться максимальной частоты кадров в 2D (с таким же качеством)? Есть предложения по его ускорению?

Вот соответствующий код, он основан на примере hello-gl2 NDK:

=== GL2JNIView.java:

init(false, 0, 0);
ConfigChooser(5, 6, 5, 0, depth, stencil);

=== gl_code.cpp:

#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>

#include <android/log.h>

#include <stdlib.h>
#include <time.h>

typedef unsigned char byte;

static int view_width, view_height;
static byte* framebuffer;
static int framebuffer_size;
static GLuint texture_id[6];
static const char* vertexSrc =
 "precision highp float;\n"
 "precision highp int;\n"
 "attribute vec4 vertexCoords;\n"
 "attribute vec2 textureCoords;\n"
 "varying vec2 f_textureCoords;\n"
 "void main() {\n"
 "  f_textureCoords = textureCoords;\n"
 "  gl_Position = vertexCoords;\n"
 "}\n";
static const char* fragmentSrc  =
 "precision highp float;\n"
 "precision highp int;\n"
 "uniform sampler2D texture;\n"
 "varying vec2 f_textureCoords;\n"
 "void main() {\n"
 "  gl_FragColor = texture2D(texture, f_textureCoords);\n"
 "}\n";
static GLuint shaderProgram;
static GLint attrib_vertexCoords;
static GLint attrib_textureCoords;
static GLint uniform_texture;
static const GLfloat vertexCoords[] = {-1.0, 1.0, -1.0, -1.0, 1.0, 1.0, 1.0, -1.0};
static const GLfloat textureCoords[] = {0.0, 0.0, 0.0, 1.0, 1.0, 0.0, 1.0, 1.0};

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_init(JNIEnv * env, jobject obj,  jint width, jint height) {
 view_width = width;
 view_height = height;

 framebuffer_size = 4*view_width*view_height;
 framebuffer = (byte*)calloc(framebuffer_size, sizeof(byte));
 for (int i = 0; i < framebuffer_size; i++) framebuffer[i] = 0;

 glViewport(0, 0, view_width, view_height);

 glGenTextures(6, &texture_id[0]);
 glActiveTexture(GL_TEXTURE0);
 glBindTexture(GL_TEXTURE_2D, texture_id[0]);
 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, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
 glActiveTexture(GL_TEXTURE1);
 glBindTexture(GL_TEXTURE_2D, texture_id[1]);
 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, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
 glActiveTexture(GL_TEXTURE2);
 glBindTexture(GL_TEXTURE_2D, texture_id[2]);
 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, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
 glActiveTexture(GL_TEXTURE3);
 glBindTexture(GL_TEXTURE_2D, texture_id[3]);
 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, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
 glActiveTexture(GL_TEXTURE4);
 glBindTexture(GL_TEXTURE_2D, texture_id[4]);
 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, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
 glActiveTexture(GL_TEXTURE5);
 glBindTexture(GL_TEXTURE_2D, texture_id[5]);
 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, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);

 shaderProgram = glCreateProgram();
  GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER);
  glShaderSource(vertexShader, 1, &vertexSrc, NULL);
  glCompileShader(vertexShader);
 glAttachShader(shaderProgram, vertexShader);
  GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
  glShaderSource(fragmentShader, 1, &fragmentSrc, NULL);
  glCompileShader(fragmentShader);
 glAttachShader(shaderProgram, fragmentShader);
 glLinkProgram(shaderProgram);
 glUseProgram(shaderProgram);

 uniform_texture = glGetUniformLocation(shaderProgram, "texture");
 glUniform1i(uniform_texture, 0);

 attrib_vertexCoords = glGetAttribLocation(shaderProgram, "vertexCoords");
 glEnableVertexAttribArray(attrib_vertexCoords);
 glVertexAttribPointer(attrib_vertexCoords, 2, GL_FLOAT, GL_FALSE, 0, vertexCoords);

 attrib_textureCoords = glGetAttribLocation(shaderProgram, "textureCoords");
 glEnableVertexAttribArray(attrib_textureCoords);
 glVertexAttribPointer(attrib_textureCoords, 2, GL_FLOAT, GL_FALSE, 0, textureCoords);
}

JNIEXPORT void JNICALL Java_com_android_gl2jni_GL2JNILib_step(JNIEnv * env, jobject obj) {
 static int frame_count = 0;
 static clock_t last_time = clock();
 static int last_frame_count = 0;

 frame_count++;
 if (clock()-last_time > 1e7) {
  __android_log_print(ANDROID_LOG_INFO, "libgl2jni", "fps: %f", ((float)frame_count-last_frame_count)/(clock()-last_time)*1e6);
  last_time = clock();
  last_frame_count = frame_count;
 }

 static byte val = 0;
 val++;
 if (val == 256) val = 0;
 for (int i = 0; i < framebuffer_size; i++) framebuffer[i] = val;

 int tst = frame_count%6;
 if (tst == 0) {
  glActiveTexture(GL_TEXTURE0);
 } else if (tst == 1) {
  glActiveTexture(GL_TEXTURE1);
 } else if (tst == 2) {
  glActiveTexture(GL_TEXTURE2);
 } else if (tst == 3) {
  glActiveTexture(GL_TEXTURE3);
 } else if (tst == 4) {
  glActiveTexture(GL_TEXTURE4);
 } else if (tst == 5) {
  glActiveTexture(GL_TEXTURE5);
 }
 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
 glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
}

person user346617    schedule 20.05.2010    source источник
comment
Ваш вопрос не очень ясен (и ваш код тоже). Что именно вы пытаетесь проверить? К 6-му кадру у вас будет 6 активных текстур, и мы понятия не имеем, что делает ваш шейдер. Не говоря уже о том, что все они активируются в коде инициализации. В равной степени, почему вы создаете текстуру в каждом кадре?   -  person Goz    schedule 13.08.2010


Ответы (2)


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

Прежде всего, glTexImage2D требует от графической подсистемы освобождения памяти и перераспределения объекта текстуры каждый раз, когда вы его вызываете, поскольку параметры текстуры могут изменяться между вызовами. Оптимизированный драйвер может смотреть на ширину, высоту и формат, и если они все одинаковы, то перераспределение можно пропустить, но маловероятно, что разработчики драйверов Android действительно это делают.

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

Подводя итог, измените код инициализации текстуры для вызова glTexImage2D с нулевым указателем растрового изображения, чтобы OpenGL выделял только память для текстуры и фактически не копировал в нее какие-либо данные следующим образом:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

Затем обновите каждый кадр в своем игровом цикле с помощью:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, view_width, view_height, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
person falken    schedule 04.04.2011

Максимально возможная частота кадров на экране ограничена частотой обновления экрана, которая зависит от производителя. Я предполагаю, что будет не менее 60 Гц (60 кадров в секунду). Внеэкранный рендеринг не ограничен частотой обновления и зависит от интенсивности выполняемых вами вычислений. Бесконечный цикл с некоторым кодом gl может работать значительно быстрее, чем 60 Гц, или, если на то пошло, медленнее.

person mr.pd    schedule 13.10.2014
comment
60 ГГц означает 60 миллиардов кадров в секунду, пожалуйста, отредактируйте до 60 Гц (я не могу меньше 6 символов) - person Fathy; 27.07.2017