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);
}
相关推荐
氦客14 分钟前
Android Compose中的附带效应
android·compose·effect·jetpack·composable·附带效应·side effect
雨白1 小时前
Kotlin 协程的灵魂:结构化并发详解
android·kotlin
我命由我123451 小时前
Android 开发问题:getLeft、getRight、getTop、getBottom 方法返回的值都为 0
android·java·java-ee·android studio·android jetpack·android-studio·android runtime
Modu_MrLiu1 小时前
Android实战进阶 - 用户闲置超时自动退出登录功能详解
android·超时保护·实战进阶·长时间未操作超时保护·闲置超时
Jeled1 小时前
Android 网络层最佳实践:Retrofit + OkHttp 封装与实战
android·okhttp·kotlin·android studio·retrofit
信田君95271 小时前
瑞莎星瑞(Radxa Orion O6) 基于 Android OS 使用 NPU的图片模糊查找APP 开发
android·人工智能·深度学习·神经网络
tangweiguo030519872 小时前
Kotlin 实现 Android 网络状态检测工具类
android·网络·kotlin
nvvas3 小时前
Android Studio JAVA开发按钮跳转功能
android·java·android studio
怪兽20143 小时前
Android多进程通信机制
android·面试
叶羽西4 小时前
Android CarService调试操作
android