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);
}
相关推荐
Estar.Lee20 分钟前
时间操作[计算时间差]免费API接口教程
android·网络·后端·网络协议·tcp/ip
找藉口是失败者的习惯1 小时前
从传统到未来:Android XML布局 与 Jetpack Compose的全面对比
android·xml
Jinkey2 小时前
FlutterBasic - GetBuilder、Obx、GetX<Controller>、GetxController 有啥区别
android·flutter·ios
大白要努力!4 小时前
Android opencv使用Core.hconcat 进行图像拼接
android·opencv
天空中的野鸟5 小时前
Android音频采集
android·音视频
小白也想学C6 小时前
Android 功耗分析(底层篇)
android·功耗
曙曙学编程6 小时前
初级数据结构——树
android·java·数据结构
闲暇部落8 小时前
‌Kotlin中的?.和!!主要区别
android·开发语言·kotlin
诸神黄昏EX10 小时前
Android 分区相关介绍
android
大白要努力!11 小时前
android 使用SQLiteOpenHelper 如何优化数据库的性能
android·数据库·oracle