Android NDK可以实现最快的2D帧速率,包括我的尝试,更好的选择?

use*_*617 2 video android frame-rate opengl-es glteximage2d

Android NDK可以实现最快的2D帧速率,包括我的尝试,更好的选择?

我使用NDK和OpenGL ES 2.0在GL_TRIANGLE_STRIP上将框架显示为纹理.这是在HTC Desire上完成的,与Nexus One相同.我试图加载多个GL_RGBA纹理并在纹理之间切换,因为单个纹理的正常填充率令人失望地低:

  • 1纹理:4.78 fps
  • 2纹理:19.68 fps
  • 3纹理:20.18 fps
  • 4种纹理:28.52 fps
  • 5纹理:29.01 fps
  • 6种纹理:30.32 fps

我认为即使30.32 fps RGBA仍然太慢.

那么这是实现最快2D帧速率(具有相同质量)的方法吗?有什么建议可以加快速度吗?

这是相关代码,它基于hello-gl2 NDK示例:

=== GL2JNIView.java:

init(false, 0, 0);
ConfigChooser(5, 6, 5, 0, depth, stencil);
Run Code Online (Sandbox Code Playgroud)

=== 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);
}
Run Code Online (Sandbox Code Playgroud)

Fal*_*ken 9

我意识到你的问题相当陈旧,而且你可能要么已经解决了问题,要么转移到别的东西上,但如果有其他人遇到这个问题,我会给出一个建议.

首先,glTexImage2D要求图形子系统在每次调用时都执行无内存和纹理对象的重新分配,因为纹理参数可以在调用之间改变.优化的驱动程序可能会查看宽度,高度和格式,如果它们都相同,则可以跳过重新分配,但Android驱动程序实现者实际上不太可能这样做.

为了完全避免纹理重新分配,您可以使用glTexSubImage2D替换完整的位图,或仅替换其中的一部分.如果将此与上面的纹理缓冲方案结合使用,您应该会看到相当大的速度增加.您甚至可以扩展它以检测显示器的修改区域,并仅更新帧之间已更改的矩形部分.

总而言之,更改纹理初始化代码以glTexImage2D使用NULL位图指针调用,因此OpenGL仅为纹理分配内存,并且实际上不会将任何数据复制到其中,如下所示:

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, view_width, view_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
Run Code Online (Sandbox Code Playgroud)

然后使用以下命令更新游戏循环中的每一帧:

glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, view_width, view_height, GL_RGBA, GL_UNSIGNED_BYTE, framebuffer);
Run Code Online (Sandbox Code Playgroud)