当前位置:网站首页>Android OpenGL es - EGL C + + implementation

Android OpenGL es - EGL C + + implementation

2020-12-06 10:42:59 YFan

PS
This article continues with the previous one , We come to the right Native EGL Each step of the environment implementation is analyzed in detail

EGL Native The realization of the layer

Last article Android OpenGL ES - EGL Source code analysis and C++ Realization

Let's review the flowchart first
 Insert picture description here

And the code

 //(1)  Attach thread to virtual machine , And get the env
     if (that->m_jvm_for_thread->AttachCurrentThread(&env, NULL) != JNI_OK) {
            LOGE(that->TAG, " Thread initialization exception ");
            return; 
     }
     // (2)  initialization  EGL 
    if (!that->InitEGL()) {
         // Thread and jvm relation 
         that->m_jvm_for_thread->DetachCurrentThread();
         return; 
     }
     
     // Into the loop 
    while (true) {
            // according to OpenGL Render state goes into different processing 
            switch (that->m_state) {
                // Refresh Surface, Set it from the outside Surface after m_state Set to this state , The explanation has been from the outside (java layer ) get Surface The object. 
                case FRESH_SURFACE:
                     LOGI(that->TAG, "Loop Render FRESH_SURFACE")
                     // (3)  initialization Window
                     that->InitDspWindow(env);
                     // (4)  establish EglSurface
                     that->CreateSurface();
                     // m_state Set as RENDERING State into rendering 
                     that->m_state = RENDERING;
                     break; 
                 case RENDERING:
                    LOGI(that->TAG, "Loop Render RENDERING")
                    // (5)  Rendering 
                    that->Render();
                    break; 
               
                 case STOP:
                    LOGI(that->TAG, "Loop Render STOP")
                    //(6)  Thread and jvm relation 
                     that->ReleaseRender();
                     that->m_jvm_for_thread->DetachCurrentThread();
                     return; 
                case SURFACE_DESTROY:
                    LOGI(that->TAG, "Loop Render SURFACE_DESTROY")
                    //(7)  Release resources 
                    that->DestroySurface();
                    that->m_state = NO_SURFACE;
                    break; 
                case NO_SURFACE:
                default:
                    break;
     }
    usleep(20000);
 }
}

First of all (1) Step Attach thread to virtual machine , And get the env, This step is simple and clear , We started from (2) Step on

EGL Packaging preparation

We knew in the last article that EGL Some basic knowledge of ,EGLDiaplay,EGLConfig,EGLSurface,EGLContext, We need to encapsulate these basic classes , So how to encapsulate , Let's take a look at the customized GLRender What does a class need
gl_render.h

//Surface quote , You have to use references , Otherwise, you can't operate in a thread 
jobject m_surface_ref = NULL;
// Local screen 
ANativeWindow *m_native_window = NULL;
//EGL Show surface   Notice here is our custom EglSurface The wrapper class is not provided by the system EGLSurface Oh 
EglSurface *m_egl_surface = NULL;

about gl_render Come on The input is external Surface object , What we have here is jobject m_surface_ref, So what the output needs is ANativeWindow,EglSurface

About ANativeWindow You can view the official documentation ANativeWindow

that EglSurface Well ,

egl_surface.h

class EglSurface {
private:
    const char *TAG = "EglSurface";
    // Local screen 
     ANativeWindow *m_native_window = NULL;
     // Encapsulates the EGLDisplay EGLConfig EGLContext User defined classes for 
     EglCore *m_core;
     //EGL API Provided  EGLSurface
     EGLSurface m_surface;
}
As you can see, the idea of our definition above is also V(View) and C(Controller) Separated .

egl_core.h

class EglCore {
private:
    const char *TAG = "EglCore";
     //EGL Display window 
     EGLDisplay m_egl_dsp = EGL_NO_DISPLAY;
     //EGL Context 
     EGLContext m_egl_context = EGL_NO_CONTEXT;
     //EGL To configure 
     EGLConfig m_egl_config;
}

With the above preparations , Let's follow the flow chart step by step

(2) initialization EGL

gl_render.cpp

bool GLRender::InitEGL() {
    // establish EglSurface object 
    m_egl_surface = new EglSurface();
    // call EglSurface Of init Method 
    return m_egl_surface->Init();
}

egl_surface.cpp

PS
We also said above EGL The initialization of is mainly for EGLDisplay EGLConfig EGLContext The operation of , So now it's right EGLCore The operation of
EglSurface::EglSurface() {
    // establish EGLCore
    m_core = new EglCore();
}

bool EglSurface::Init() {
    // call EGLCore Of init Method 
    return m_core->Init(NULL);
}

egl_core.cpp

EglCore::EglCore() {
}


bool EglCore::Init(EGLContext share_ctx) {
    if (m_egl_dsp != EGL_NO_DISPLAY) {
        LOGE(TAG, "EGL already set up")
        return true;
     }
    if (share_ctx == NULL) {
            share_ctx = EGL_NO_CONTEXT;
     }
     // obtain Dispaly
    m_egl_dsp = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (m_egl_dsp == EGL_NO_DISPLAY || eglGetError() != EGL_SUCCESS) {
            LOGE(TAG, "EGL init display fail")
            return false;
     }
        EGLint major_ver, minor_ver;
     // initialization egl
     EGLBoolean success = eglInitialize(m_egl_dsp, &major_ver, &minor_ver);
     if (success != EGL_TRUE || eglGetError() != EGL_SUCCESS) {
            LOGE(TAG, "EGL init fail")
            return false;
     }
        LOGI(TAG, "EGL version: %d.%d", major_ver, minor_ver)
     // obtain EGLConfig   
     m_egl_config = GetEGLConfig();
     const EGLint attr[] = {EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE};
     // establish EGLContext
     m_egl_context = eglCreateContext(m_egl_dsp, m_egl_config, share_ctx, attr);
     if (m_egl_context == EGL_NO_CONTEXT) {
            LOGE(TAG, "EGL create fail, error is %x", eglGetError());
     return false; }
        EGLint egl_format;
     success = eglGetConfigAttrib(m_egl_dsp, m_egl_config, EGL_NATIVE_VISUAL_ID, &egl_format);
     if (success != EGL_TRUE || eglGetError() != EGL_SUCCESS) {
            LOGE(TAG, "EGL get config fail, error is %x", eglGetError())
            return false;
     }
    LOGI(TAG, "EGL init success")
    return true;
}

EGLConfig EglCore::GetEGLConfig() {
    EGLint numConfigs;
    EGLConfig config;

    // The minimum configuration you want ,
    static const EGLint CONFIG_ATTRIBS[] = {
            EGL_BUFFER_SIZE, EGL_DONT_CARE,
            EGL_RED_SIZE, 8,//R  digit 
            EGL_GREEN_SIZE, 8,//G  digit 
            EGL_BLUE_SIZE, 8,//B  digit 
            EGL_ALPHA_SIZE, 8,//A  digit 
            EGL_DEPTH_SIZE, 16,// depth 
            EGL_STENCIL_SIZE, EGL_DONT_CARE,
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
            EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
            EGL_NONE // the end  End mark 
    };
    // According to the minimum configuration you set, the system will choose a configuration that meets your minimum requirements , The actual configuration is often more than you expect 
    EGLBoolean success = eglChooseConfig(m_egl_dsp, CONFIG_ATTRIBS, &config, 1, &numConfigs);
    if (!success || eglGetError() != EGL_SUCCESS) {
        LOGE(TAG, "EGL config fail")
        return NULL;
    }
    return config;
}

(3) establish Window

gl_render.cpp

void GLRender::InitDspWindow(JNIEnv *env) {
    // incoming Surface References to objects 
    if (m_surface_ref != NULL) {
        //  Initialize window 
        m_native_window = ANativeWindow_fromSurface(env, m_surface_ref);

        //  Draw the width and height of the area 
        m_window_width = ANativeWindow_getWidth(m_native_window);
        m_window_height = ANativeWindow_getHeight(m_native_window);

        // Set the width and height to limit the number of pixels in the buffer 
        ANativeWindow_setBuffersGeometry(m_native_window, m_window_width,
                                         m_window_height, WINDOW_FORMAT_RGBA_8888);

        LOGD(TAG, "View Port width: %d, height: %d", m_window_width, m_window_height)
    }
}

(4) establish EglSurface And bind to the thread

gl_render.cpp

void GLRender::CreateSurface() {
    m_egl_surface->CreateEglSurface(m_native_window, m_window_width, m_window_height);
    glViewport(0, 0, m_window_width, m_window_height);
}

egl_surface.cpp

/**
 * 
 * @param native_window  Pass in the... Created in the previous step ANativeWindow
 * @param width 
 * @param height 
 */
void EglSurface::CreateEglSurface(ANativeWindow *native_window, int width, int height) {
    if (native_window != NULL) {
        this->m_native_window = native_window;
        m_surface = m_core->CreateWindSurface(m_native_window);
    } else {
        m_surface = m_core->CreateOffScreenSurface(width, height);
    }
    if (m_surface == NULL) {
        LOGE(TAG, "EGL create window surface fail")
        Release();
    }
    MakeCurrent();
}

void EglSurface::MakeCurrent() {
    m_core->MakeCurrent(m_surface);
}

egl_core.cpp

EGLSurface EglCore::CreateWindSurface(ANativeWindow *window) {
    // call EGL Native API establish Window Surface
    EGLSurface surface = eglCreateWindowSurface(m_egl_dsp, m_egl_config, window, 0);
    if (eglGetError() != EGL_SUCCESS) {
        LOGI(TAG, "EGL create window surface fail")
        return NULL;
    }
    return surface;
}

void EglCore::MakeCurrent(EGLSurface egl_surface) {
    // call EGL Native API  Bind rendering environment to current thread 
    if (!eglMakeCurrent(m_egl_dsp, egl_surface, egl_surface, m_egl_context)) {
        LOGE(TAG, "EGL make current fail");
    }
}

(5) Rendering

gl_render.cpp

void GLRender::Render() {
    if (RENDERING == m_state) {
        pImageRender->DoDraw();// Draw and draw ....
        m_egl_surface->SwapBuffers();
    }
}

egl_surface.cpp

void EglSurface::SwapBuffers() {
    m_core->SwapBuffer(m_surface);
}

egl_core.cpp

void EglCore::SwapBuffer(EGLSurface egl_surface) {
    // call EGL Native API
    eglSwapBuffers(m_egl_dsp, egl_surface);
}

The latter stop and destroy are left to the reader to study by themselves .

Code

EGLDemoActivity.java

EGL Native

版权声明
本文为[YFan]所创,转载请带上原文链接,感谢
https://chowdera.com/2020/12/20201206104031008h.html