OpenGL ES eglCreatePbufferSurface() 和 eglCreateWindowSurface() 的对比和使用

一、介绍

相同点:

eglCreatePbufferSurfaceeglCreateWindowSurface 都是 OpenGL ES 中用于创建不同类型的EGL表面的函数,以便在OpenGL ES中进行渲染。

不同点:

选择使用哪种表面类型取决于你的需求。如果你只是需要在内存中进行离屏渲染,而不需要将结果显示在屏幕上,那么 eglCreatePbufferSurface 可能更适合。

如果你需要在窗口系统的窗口上显示OpenGL渲染的内容,那么 eglCreateWindowSurface 是更常见的选择。

二、eglCreatePbufferSurface

eglCreatePbufferSurface 用于创建一个离屏渲染表面,也称为Pbuffer表面。Pbuffer表面是一个虚拟的离屏缓冲区,可以在其中进行渲染操作,而不直接与屏幕交互。通常,它用于离屏渲染、渲染到纹理等场景。

1. 函数定义

cpp 复制代码
///< @param [in] dpy EGL显示连接
///< @param [in] config EGL配置
///< @param [in] attrib_list 属性列表,用于指定Pbuffer的一些属性,可以为NULL
///< @return 返回EGL表面
EGLSurface eglCreatePbufferSurface(EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);

2. 使用示例

cpp 复制代码
// 初始化EGL
eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
eglInitialize(eglDisplay, 0, 0);
// 配置EGL
EGLConfig config;
EGLint numConfigs;
EGLint configAttribs[] = {
    EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT_KHR,
    EGL_RED_SIZE, 8,
    EGL_GREEN_SIZE, 8,
    EGL_BLUE_SIZE, 8,
    EGL_NONE
};
eglChooseConfig(eglDisplay, configAttribs, &config, 1, &numConfigs);
// 创建EGL窗口表面(可以是Pbuffer等)
EGLint attribList[] = {EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE};
eglSurface = eglCreatePbufferSurface(eglDisplay, config, attribList);
// 创建EGL上下文
EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
eglContext = eglCreateContext(eglDisplay, config, EGL_NO_CONTEXT, contextAttribs);
// 关联上下文
eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

// 渲染操作...

// 交换缓冲区
eglSwapBuffers(eglDisplay, eglSurface);

// 销毁 EGLSurface
eglDestroySurface(eglDisplay, eglSurface);
// 销毁 EGLContext
eglDestroyContext(eglDisplay, eglContext);
// 终止 EGL
eglTerminate(eglDisplay);

三、eglCreateWindowSurface

eglCreateWindowSurface 用于创建一个与屏幕窗口相关的EGL表面。这个表面通常与设备的窗口系统交互,使得OpenGL ES渲染的内容能够显示在屏幕上。

1. 函数定义

cpp 复制代码
///< @param [in] dpy EGL显示连接
///< @param [in] config EGL配置
///< @param [in] win 与窗口系统相关的本地窗口类型。在Android中,通常是ANativeWindow*类型
///< @param [in] attrib_list 属性列表,用于指定Pbuffer的一些属性,可以为NULL
///< @return 返回EGL表面
EGLSurface eglCreateWindowSurface(EGLDisplay dpy,
        EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);

2. 使用示例

注意:

如果你需要渲染到屏幕上,那么建议直接使用封装好的 GLSurfaceView 类,它已经把复杂的 EGL 管理,线程管理等做好了,直接使用即可。

下面的示例参考演示我们自己应该如何使用 eglCreateWindowSurface。

JNI代码

cpp 复制代码
#include <EGL/egl.h>
#include <GLES3/gl3.h>
#include <android/native_window_jni.h>

EGLDisplay eglDisplay;
EGLSurface eglSurface;
EGLContext eglContext;

JNIEXPORT void JNICALL
Java_com_afei_opengldemo_MySurfaceView_glDraw(JNIEnv *env, jclass clazz, jobject surface) {
    // 初始化EGL
    eglDisplay = eglGetDisplay(EGL_DEFAULT_DISPLAY);
    if (eglDisplay == EGL_NO_DISPLAY) {
        // Unable to open connection to local windowing system
        return;
    }
    EGLint majorVersion;
    EGLint minorVersion;
    if (!eglInitialize(eglDisplay, &majorVersion, &minorVersion)) {
        // Unable to initialize EGL. Handle and recover
        return;
    }
    // 配置EGL
    EGLConfig config;
    EGLint numConfigs;
    EGLint configAttribs[] = {
            EGL_RENDERABLE_TYPE, EGL_OPENGL_ES3_BIT,
            EGL_RED_SIZE, 8,
            EGL_GREEN_SIZE, 8,
            EGL_BLUE_SIZE, 8,
            EGL_DEPTH_SIZE, 1,
            EGL_NONE
    };
    if (!eglChooseConfig(eglDisplay, configAttribs, &config, 1, &numConfigs)) {
        return;
    }
    // 创建EGL窗口表面(可以是Pbuffer等)
    EGLint attribList[] = {EGL_RENDER_BUFFER, EGL_BACK_BUFFER, EGL_NONE};
    // 这里我们需要在Java层传递一个Surface对象供我们显示
    ANativeWindow *window = ANativeWindow_fromSurface(env, surface);
    eglSurface = eglCreateWindowSurface(eglDisplay, config, window, attribList);
    if (eglSurface == EGL_NO_SURFACE) {
        EGLint error = eglGetError();
        switch (error) {
            case EGL_BAD_MATCH:
                // Check window and EGLConfig attributes to determine
                // compatibility, or verify that the EGLConfig
                // supports rendering to a window,
                break;
            case EGL_BAD_CONFIG:
                // Verify that provided EGLConfig is valid
                break;
            case EGL_BAD_NATIVE_WINDOW:
                // Verify that provided EGLNativeWindow is valid
                break;
            case EGL_BAD_ALLOC:
                // Not enough resources available. Handle and recover
                break;
        }
        return;
    }
    // 创建EGL上下文
    EGLint contextAttribs[] = {EGL_CONTEXT_CLIENT_VERSION, 3, EGL_NONE};
    eglContext = eglCreateContext(eglDisplay, config, EGL_NO_CONTEXT, contextAttribs);
    if (eglContext == EGL_NO_CONTEXT) {
        EGLint error = eglGetError();
        if (error == EGL_BAD_CONFIG) {
            // Handle error and recover
            return;
        }
    }
    // 关联上下文
    eglMakeCurrent(eglDisplay, eglSurface, eglSurface, eglContext);

    // 初始化OpenGL和渲染操作...

    // 交换缓冲区
    eglSwapBuffers(eglDisplay, eglSurface);
    
    // 销毁 EGLSurface
    eglDestroySurface(eglDisplay, eglSurface);
    // 销毁 EGLContext
    eglDestroyContext(eglDisplay, eglContext);
    // 终止 EGL
    eglTerminate(eglDisplay);
}

Java调用代码

java 复制代码
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {

    private SurfaceHolder mSurfaceHolder;

    public MyView(Context context) {
        super(context);
        mSurfaceHolder = getHolder();
        mSurfaceHolder.addCallback(this);
    }
    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        // 初始化操作等
        glDraw(holder.getSurface());
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {}

    @Override
    public void surfaceDestroyed(@NonNull SurfaceHolder holder) {
        // 释放操作...
    }
    
    public native static void glDraw(Surface surface);
}
相关推荐
阿巴斯甜3 小时前
Android 报错:Zip file '/Users/lyy/develop/repoAndroidLapp/l-app-android-ble/app/bu
android
Kapaseker4 小时前
实战 Compose 中的 IntrinsicSize
android·kotlin
xq95275 小时前
Andorid Google 登录接入文档
android
黄林晴6 小时前
告别 Modifier 地狱,Compose 样式系统要变天了
android·android jetpack
冬奇Lab19 小时前
Android触摸事件分发、手势识别与输入优化实战
android·源码阅读
城东米粉儿21 小时前
Android MediaPlayer 笔记
android
Jony_1 天前
Android 启动优化方案
android
阿巴斯甜1 天前
Android studio 报错:Cause: error=86, Bad CPU type in executable
android
张小潇1 天前
AOSP15 Input专题InputReader源码分析
android
_小马快跑_1 天前
Kotlin | 协程调度器选择:何时用CoroutineScope配置,何时用launch指定?
android