Boot Animation 변경 방법

========================================================================================================
출처 : http://blog.daum.net/baramjin/16010965

사실 Surface Flinger 응용이라고 했지만 맞는 표현은 아닌것 같다.

 

BootAnimation은 Surface Flinger가 생성되고 가장 먼저 동작하는 것이다. 당연히 아직 안드로이드 플랫폼의 어플리케이션이 동작하지 않은 상태에서 초기화 과정 중에 화면을 표시하는 영역이라서 한번 쯤 봐두어야 하는 부분이다.

 

단 이 부분에서 Surface Flinger와 관련된 전체적인 내용이 있다고는 생각되지 않는다. (도리어 EGL 초기화 과정이 한번 더 반복되고 OpenGL 사용 예가 나온다는 말이 맞다.)

 

Surface Flinger 에서 초기화를 위하여 사용하는 클래스가 DisplayHardware 이고 여기서는 surface를 생성하기 위하여 EGLDisplaySurface 클래스를 생성한다(여기서 Fb 디바이스 드라이버가 열리고, Frame Buffer 관련된 정보를 얻는다.) 이미 이런 초기화 작업이 이루어 졌기 때문에 BootAnimation에서 Fb 디바이스 드라이버 관련된 내용은 없고 새로운 surface를 EGLNativeWindowSurface로 생성한다.

 

생성자에서 보면 composer를 받아서 binding 하는 과정만 있다 (관련 정보는 mSession에 저장된다) 사실 binding이라는 의미는 아직도 낯설다.

BootAnimation::BootAnimation(const sp<ISurfaceComposer>& composer) :
    Thread(false) {
    mSession = SurfaceComposerClient::clientForConnection(
            composer->createConnection()->asBinder());
}

 

초기화 과정을 보면 다음과 같다.

 

status_t BootAnimation::readyToRun() {
    mAssets.addDefaultAssets();

 

    DisplayInfo dinfo;
    status_t status = session()->getDisplayInfo(0, &dinfo);
    if (status)
        return -1;

 

    // create the native surface
    sp<Surface> s = session()->createSurface(getpid(), 0, dinfo.w, dinfo.h,
            PIXEL_FORMAT_RGB_565);
    session()->openTransaction();
    s->setLayer(0x40000000);
    session()->closeTransaction();

 

    // initialize opengl and egl
    const EGLint attribs[] = { EGL_RED_SIZE, 5, EGL_GREEN_SIZE, 6,
            EGL_BLUE_SIZE, 5, EGL_DEPTH_SIZE, 0, EGL_NONE };
    EGLint w, h, dummy;
    EGLint numConfigs;
    EGLConfig config;
    EGLSurface surface;
    EGLContext context;
    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    eglChooseConfig(display, attribs, &config, 1, &numConfigs);

    mNativeWindowSurface = new EGLNativeWindowSurface(s);
    surface = eglCreateWindowSurface(display, config, 
            mNativeWindowSurface.get(), NULL);

 

    context = eglCreateContext(display, config, NULL, NULL);
    eglQuerySurface(display, surface, EGL_WIDTH, &w);
    eglQuerySurface(display, surface, EGL_HEIGHT, &h);
    eglMakeCurrent(display, surface, surface, context);
    mDisplay = display;
    mContext = context;
    mSurface = surface;
    mWidth = w;
    mHeight = h;
    mFlingerSurface = s;

 

    // initialize GL
    glShadeModel(GL_FLAT);
    glEnable(GL_TEXTURE_2D);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

    return NO_ERROR;
}

 

초기화 과정을 보면 DisplayHardware 에서 했던 EGL 초기화와 같다. (위에서 말한 것처럼 다른 클래스를 이용하여 Fb 디바이스 드라이버를 오픈하지 않는 것만 다르다)

 

BootAnimation에서 일단 EGL 초기화가 되었으면 쓰레드에서 일정 시간 단위로 로고를 변화시켜주는 역활이 다이다.

이 부분은 대부분 OpenGL API 로 구현되어 있기 때문에 대충 이해하면 될 것 같고 하나의 준비가 되면 버퍼 스왑하는 과정이 보여진다.

 

bool BootAnimation::android() {
    initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png");
    initTexture(&mAndroid[1], mAssets, "images/android-logo-shine.png");

 

    // clear screen
    glDisable(GL_DITHER);
    glDisable(GL_SCISSOR_TEST);
    glClear(GL_COLOR_BUFFER_BIT);
    eglSwapBuffers(mDisplay, mSurface);

 

    const GLint xc = (mWidth  - mAndroid[0].w) / 2;
    const GLint yc = (mHeight - mAndroid[0].h) / 2;
    const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h);

 

    // draw and update only what we need
    mNativeWindowSurface->setSwapRectangle(updateRect.left,
            updateRect.top, updateRect.width(), updateRect.height());

 

    glEnable(GL_SCISSOR_TEST);
    glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(),
            updateRect.height());

 

    // Blend state
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);

 

    const nsecs_t startTime = systemTime();
    do {
        nsecs_t now = systemTime();
        double time = now - startTime;
        float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w;
        GLint offset = (1 - (t - floorf(t))) * mAndroid[1].w;
        GLint x = xc - offset;

 

        glDisable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[1].name);
        glDrawTexiOES(x,                 yc, 0, mAndroid[1].w, mAndroid[1].h);
        glDrawTexiOES(x + mAndroid[1].w, yc, 0, mAndroid[1].w, mAndroid[1].h);

 

        glEnable(GL_BLEND);
        glBindTexture(GL_TEXTURE_2D, mAndroid[0].name);
        glDrawTexiOES(xc, yc, 0, mAndroid[0].w, mAndroid[0].h);

        eglSwapBuffers(mDisplay, mSurface);
        
        // 12fps: don't animate too fast to preserve CPU
        const nsecs_t sleepTime = 83333 - ns2us(systemTime() - now);
        if (sleepTime > 0)
            usleep(sleepTime); 
    } while (!exitPending());

 

    glDeleteTextures(1, &mAndroid[0].name);
    glDeleteTextures(1, &mAndroid[1].name);
    return false;
}

 

흠 정리하고 보니 사실 Surface Flinger와 관련된 내용은 초기에 SurfaceComposerClient의 API로 session을 구성하는 것은 관련이 있지만 대부분은 EGL 초기화와 Buffer Swap 관련된 내용이 대부분이다.

 

단 BootAnimation::android()에서 png 파일을 바꾸면 다른 부팅 화면을 구현할 수 있다는 정도 정리한 것에 만족해야 할 것 같다.


http://blog.daum.net/baramjin/16010965

'Platform > Android' 카테고리의 다른 글

[Android] Android 부팅  (0) 2010.03.18
[Android] Android 의 개요  (0) 2010.03.18
[Android] SGL  (0) 2010.03.18
[Android] Surface Flinger의 쓰레드  (1) 2010.03.18
[Android] Surface Flinger와 초기화 과정  (0) 2010.03.18

+ Recent posts