Frage

I'm trying to use NDK to display a bitmap on a full screen. The requirement force me to develop with completely native code. I use Skia to draw a SkBitmap, then display it by Opengl APIs. When my application first time run on a real android device, it always works well. However, after I keep opening and closing the program for several times, it will show a bad image. Why does this happen?

Function engine_init_display is to initialize OpenGL ES and EGL, create bitmap and load texture.

static int engine_init_display(struct engine* engine){
// initialize OpenGL ES and EGL

/*
 * Here specify the attributes of the desired configuration.
 * Below, we select an EGLConfig with at least 8 bits per color
 * component compatible with on-screen windows
 */
const EGLint attribs[] = {
        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
        EGL_DEPTH_SIZE, 16,
        EGL_BLUE_SIZE, 8,
        EGL_GREEN_SIZE, 8,
        EGL_RED_SIZE, 8,
        EGL_NONE
};
EGLint w, h, dummy, format;
EGLint numConfigs;
EGLConfig config;
EGLSurface surface;
EGLContext context;

EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(display, 0, 0);

/* Here, the application chooses the configuration it desires. In this
 * sample, we have a very simplified selection process, where we pick
 * the first EGLConfig that matches our criteria */
eglChooseConfig(display, attribs, &config, 1, &numConfigs);

/* EGL_NATIVE_VISUAL_ID is an attribute of the EGLConfig that is
 * guaranteed to be accepted by ANativeWindow_setBuffersGeometry().
 * As soon as we picked a EGLConfig, we can safely reconfigure the
 * ANativeWindow buffers to match, using EGL_NATIVE_VISUAL_ID. */
eglGetConfigAttrib(display, config, EGL_NATIVE_VISUAL_ID, &format);

ANativeWindow_setBuffersGeometry(engine->app->window, 0, 0, format);
surface = eglCreateWindowSurface(display, config, engine->app->window, NULL);
context = eglCreateContext(display, config, NULL, NULL);

if (eglMakeCurrent(display, surface, surface, context) == EGL_FALSE) {
    LOGW("Unable to eglMakeCurrent");
    return -1;
}

eglQuerySurface(display, surface, EGL_WIDTH, &w);
eglQuerySurface(display, surface, EGL_HEIGHT, &h);

engine->display = display;
engine->context = context;
engine->surface = surface;
engine->width = w;
engine->height = h;
engine->state.angle = 0;
engine->format=format;
// Initialize GL state.

glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glDisable(GL_DEPTH_TEST);
SkBitmap bitmap;
GLvoid* bitmapBuffer;
createBitmap(bitmap,bitmapBuffer,width,height);
drawBitmap(bitmap,width,height);
glEnable(GL_TEXTURE_2D);
glGenTextures(1,&sTexture);
glBindTexture(GL_TEXTURE_2D,sTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)bitmapBuffer);
glDisable(GL_TEXTURE_2D);
glFinish();
clearBitmapBuffer(bitmap,bitmapBuffer);
//engine_draw_frame(engine);
return 0;
}

Function render is to display a bitmap

void render(struct engine* engine, int width, int height){

glViewport((engine->width-width)/2, (engine->height-height)/2, width, height);
glClearColorx((GLfixed)(0.1f * 65536),(GLfixed)(0.2f * 65536),(GLfixed)(0.3f * 65536), 0x10000);
glClear(GL_COLOR_BUFFER_BIT);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();

glMatrixMode(GL_TEXTURE);
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterx(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glBindTexture(GL_TEXTURE_2D,sTexture);
glFrontFace(GL_CW);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoords);
glVertexPointer(3, GL_FLOAT, 0, vertices);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glFlush();
eglSwapBuffers(engine->display, engine->surface);
}

And when the window is being closed, engine_term_display will be called

static void engine_term_display(struct engine* engine) {
if (engine->display != EGL_NO_DISPLAY) {
    eglMakeCurrent(engine->display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
    if (engine->context != EGL_NO_CONTEXT) {
        eglDestroyContext(engine->display, engine->context);
    }
    if (engine->surface != EGL_NO_SURFACE) {
        eglDestroySurface(engine->display, engine->surface);
    }
    eglTerminate(engine->display);
}
engine->display = EGL_NO_DISPLAY;
engine->context = EGL_NO_CONTEXT;
engine->surface = EGL_NO_SURFACE;
}

update

android_main is the main entry point of my native application. I find that when this main function has returned, the whole application is still running.

void android_main(struct android_app* state) {
struct engine engine;

// Make sure glue isn't stripped.
app_dummy();
memset(&engine, 0, sizeof(engine));
state->userData = &engine;
state->onAppCmd = engine_handle_cmd;
state->onInputEvent = engine_handle_input;
engine.app = state;
ANativeActivity_setWindowFlags(engine.app->activity, AWINDOW_FLAG_FULLSCREEN, 0);

if (state->savedState != NULL) {
    // We are starting with a previous saved state; restore from it.
    engine.state = *(struct saved_state*)state->savedState;
}
while(1){
    int ident;
    int events;
    struct android_poll_source* source;
    if((ident=ALooper_pollAll(-1, NULL, &events,(void**)&source))>=0){
      // Process this event.
       if (source != NULL) {
           source->process(state, source);
       }
       if (state->destroyRequested != 0) {
           engine_term_display(&engine);
           return;
       }
  }
}
}
War es hilfreich?

Lösung

I fix it by myself, use exit(0) instead of return to finish the activity completely.

if (state->destroyRequested != 0) {
       engine_term_display(&engine);
       exit(0);
   }
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top