Максимальная частота 2D-кадров возможна с Android NDK, моя попытка включена, лучшие варианты доступны? - PullRequest
2 голосов
/ 21 мая 2010

Самая быстрая 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);
}

Ответы [ 2 ]

9 голосов
/ 04 апреля 2011

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

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

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

Подводя итог, измените код инициализации текстуры на вызов glTexImage2D с указателем NULL для растрового изображения, поэтому 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);
0 голосов
/ 13 октября 2014

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

...