Android OpenGLES开发:EGL环境搭建

2024-09-04 16:52

本文主要是介绍Android OpenGLES开发:EGL环境搭建,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

努力,不是为了要感动谁,也不是要做给哪个人看,而是要让自己随时有能力跳出自己厌恶的圈子,并拥有选择的权利,用自己喜欢的方式过一生!

EGL是什么?

谈到openGL开发我们就不得不说EGL,那EGL是什么呢?请看下图

官方听不懂解释

EGL(Embedded Graphic Library)是渲染API(如OpenGL ES)和本地窗口系统(native platform window system)之间的中间层接口,它主要由系统制造商实现。

EGL是一套OpenGLES、OpenVG等渲染接口和它所运行的平台的底层原生窗口系统之间的桥接接口,也就是帮助OpenGLES或其他Khronos图形API渲染的内容投射到目标窗口的接口

EGL是一个与平台无关的接口,EGL可以在多种操作系统(如Android和Linux)和本机窗口系统上实现。

通俗类比解释

  • OpengGL:他才是真正的画家,他负责创作图像。OpenGL是一个操作GPU的API,你可以认为GPU就是画笔,如何妙笔生花就是OpenGL的功劳(哈哈哈,其实要画什么还是人发的指令,这里就不纠结了)。画家只负责饮酒作乐,哦不作画。至于我的画如何向别人展示,如何放到画室亦或是大街上供别人参观那我不管,我请一个公司EGL去负责,下面有请EGL登场。
  • EGL:画家(OpenGL)作了好多的画,我得想着怎么才能卖个好价钱:)。目前有Android画室、Linux画室以及windows画室在洽谈。我需要对接画家和画室,把画装裱到不同的画框、保证运输、并将画展示到画室。当然我们公司只提供了一套标准的流程,如何操作还需要Android、Linux画室工作人员来操作,他们需要遵循我们定的流程标准,将画正确无误的摆放到自己的画室供别人浏览参观。

提供了哪些功能?

  1. 与设备的原生窗口系统通信
  2. 查询绘图表面的可用类型和配置
  3. 创建绘图表面
  4. 在OpenGL ES 和其他图形渲染API之间同步渲染
  5. 管理纹理贴图等渲染资源

EGL怎么用

聪明的同学发现没有,我们使用GLSurfaceView编写OpenGL代码时好像并没有发现EGL的身影。那是因为GLSurfaceView早已帮我们搭建好了EGL环境,我们只需要编写OpenGL代码即可。如果我们想要更高的扩展性,以及真正了解他的运行机制我们需要自己搭建EGL。

下图请看EGL的主要使用API:

  • Display(EGLDisplay) 是对实际显示设备的抽象
  • Surface(EGLSurface)是对用来存储图像的内存区域
  • FrameBuffer 的抽象,包括 Color Buffer, Stencil Buffer ,Depth Buffer
  • Context (EGLContext) 存储 OpenGL ES绘图的一些状态信息

需要说明的是EGL是单线程模型,也就是说EGL环境创建、渲染操作、EGL环境的销毁都必须在同一个线程内完成,否则是无效的。那么我们要么在主线程创建,要么就是创建一个有消息循环的线程,聪明的你应该能想到那就得用HandlerThread或者自定义带Looper的Thread(GLSurfaceView采用该种方式)

使用EGL的基本步骤

  1. 获取OpenGL ES与原生窗口系统的连接:调用eglGetDisplay方法得到EGLDisplay
    public static native EGLDisplay eglGetDisplay(int display_id);
  1. 初始化EGL链接:调用 eglInitialize 方法初始化
    public static native boolean eglInitialize(EGLDisplay dpy,    // 要进行初始化的EGL连接,即上一步的返回值int[] major,       // 主版本号int majorOffset,   // 主版本号偏移int[] minor,       // 次版本号int minorOffset    // 次版本号偏移)
  1. 确定渲染表面的配置信息:调用eglChooseConfig方法得到EGLConfig
    指定一组需求,然后再让EGL推荐(eglChooseChofig)最佳配置
  2. 创建渲染上下文:通过 EGLDisplay 和 EGLConfig ,调用 eglCreateContext 方法创建渲染上下文,得到 EGLContext
    public static native EGLContext eglCreateContext(EGLDisplay dpy,EGLConfig config,EGLContext share_context,int[] attrib_list,int offset)
  1. 创建渲染表面:通过 EGLDisplay 和 EGLConfig ,调用 eglCreateWindowSurface 方法创建渲染表面,得到 EGLSurface
    public static EGLSurface eglCreateWindowSurface(EGLDisplay dpy,      // EGLDisplay连接EGLConfig config,    // EGL frame buffer配置,定义了可用于Surface的frame buffer资源Object win,          // Android的窗口,可以是SurfaceView、Surface、SurfaceHolder、SurfaceTextureint[] attrib_list,   // 配置int offset           // 配置偏移)
  1. 绑定上下文:将EGL上下文绑定到当前线程,实现渲染环境的设置。通过eglMakeCurrent 方法将EGLSurface、EGLContext、EGLDisplay 三者绑定,接下来就可以使用 OpenGL 进行绘制了
public static native boolean eglMakeCurrent(EGLDisplay dpy,EGLSurface draw,EGLSurface read,EGLContext ctx);
  1. 绘制图像:使用OpenGL的API绘制精美的图像
  2. 交换缓冲区:当用 OpenGL 绘制结束后,使用 eglSwapBuffers 方法交换前后缓冲,将绘制内容显示到屏幕上
  3. 释放 EGL 环境 :绘制结束,不再需要使用 EGL 时,取消 eglMakeCurrent 的绑定,销毁 EGLDisplay、EGLSurface、EGLContext

EGL代码实现

创建EGLHelper工具类如下:

package com.android.xz.egldemo.gles;import android.opengl.EGL14;
import android.opengl.EGLConfig;
import android.opengl.EGLContext;
import android.opengl.EGLDisplay;
import android.opengl.EGLSurface;
import android.util.Log;/*** EGL环境搭建类* <p>* 1.创建显示屏幕类EGLDisplay* 2.配置FrameBuffer类EGLConfig* 3.创建FrameBuffer的EGLSurface* 4.创建上下文EGLContext,并与Surface绑定*/
public class EGLHelper {private static final String TAG = EGLHelper.class.getSimpleName();/*** 屏幕显示类,表示一个可以现实的屏幕*/private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;/*** 系统窗口或FrameBuffer*/private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;/*** FrameBuffer的配置属性*/private EGLConfig mEGLConfig;/*** 渲染上下文,用于绑定上面3个属性,将其关联起来*/private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;/*** 初始化EGL环境** @param surface*/public void initEGL(Object surface) {// 1、获取显示设备mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {throw new RuntimeException("unable to get EGL14 display");}// 2、初始化EGLint[] version = new int[2];if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {mEGLDisplay = null;throw new RuntimeException("unable to initialize EGL14");}// 3、资源配置,例如颜色配置等int[] attribList = {EGL14.EGL_RED_SIZE, 8,EGL14.EGL_GREEN_SIZE, 8,EGL14.EGL_BLUE_SIZE, 8,EGL14.EGL_ALPHA_SIZE, 8,EGL14.EGL_DEPTH_SIZE, 8,EGL14.EGL_STENCIL_SIZE, 8,EGL14.EGL_RENDERABLE_TYPE, EGL14.EGL_OPENGL_ES2_BIT,EGL14.EGL_NONE, 0,      // placeholder for recordable [@-3]EGL14.EGL_NONE};EGLConfig[] configs = new EGLConfig[1];int[] numConfigs = new int[1];// 4、ChooseConfigif (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length,numConfigs, 0)) {throw new RuntimeException("unable to find RGB8888 / " + version + " EGLConfig");}mEGLConfig = configs[0];// 5、创建上下文int[] attrib2_list = {EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,EGL14.EGL_NONE};EGLContext context = EGL14.eglCreateContext(mEGLDisplay, mEGLConfig, EGL14.EGL_NO_CONTEXT, attrib2_list, 0);if (context == EGL14.EGL_NO_CONTEXT) {throw new RuntimeException("eglCreateContext error");}mEGLContext = context;// 6、创建渲染Surfaceint[] attrib_list = {EGL14.EGL_NONE};EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface, attrib_list, 0);if (eglSurface == null) {throw new RuntimeException("surface was null");}mEGLSurface = eglSurface;// 7、将EGL上下文绑定到当前线程,实现渲染环境的设置,之后就可以使用OpenGL进行绘制了if (!EGL14.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext)) {throw new RuntimeException("eglMakeCurrent failed");}Log.i(TAG, "egl init success!");}/*** 交换缓冲区*/public void swapBuffers() {if (mEGLDisplay != EGL14.EGL_NO_DISPLAY && mEGLSurface != EGL14.EGL_NO_SURFACE) {if (!EGL14.eglSwapBuffers(mEGLDisplay, mEGLSurface)) {throw new RuntimeException("swap buffers error");}}}/*** 销毁EGL环境*/public void destroyEGL() {if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,EGL14.EGL_NO_CONTEXT);}if (mEGLDisplay != EGL14.EGL_NO_DISPLAY && mEGLSurface != EGL14.EGL_NO_SURFACE) {EGL14.eglDestroySurface(mEGLDisplay, mEGLSurface);mEGLSurface = EGL14.EGL_NO_SURFACE;}if (mEGLDisplay != EGL14.EGL_NO_DISPLAY && mEGLContext != EGL14.EGL_NO_CONTEXT) {EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);mEGLContext = EGL14.EGL_NO_CONTEXT;}if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {EGL14.eglReleaseThread();EGL14.eglTerminate(mEGLDisplay);mEGLDisplay = EGL14.EGL_NO_DISPLAY;}mEGLConfig = null;}
}

自定义MySurfaceView创建EGL环境

  • surfaceCreated中初始化EGL环境
  • surfaceChanged中更新画布大小并重新绘制
  • surfaceDestroyed中销毁EGL环境
public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback {private static final String TAG = MySurfaceView.class.getSimpleName();private EGLHelper mEGLHelper = new EGLHelper();public MySurfaceView(Context context) {super(context);init(context);}public MySurfaceView(Context context, AttributeSet attrs) {super(context, attrs);init(context);}public MySurfaceView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);init(context);}private void init(Context context) {getHolder().addCallback(this);}@Overridepublic void surfaceCreated(@NonNull SurfaceHolder holder) {Log.i(TAG, "surfaceCreated.");mEGLHelper.initEGL(holder);draw();mEGLHelper.swapBuffers();}@Overridepublic void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {Log.i(TAG, "surfaceChanged.");GLES20.glViewport(0, 0, width, height);draw();mEGLHelper.swapBuffers();}@Overridepublic void surfaceDestroyed(@NonNull SurfaceHolder holder) {Log.v(TAG, "surfaceDestroyed.");mEGLHelper.destroyEGL();}/*** 该方法中编写OpenGL绘制相关代码*/private void draw() {// 蓝色清屏GLES20.glClearColor(0f, 0f, 1f, 1f);GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);}
}

xlm中加入自定义视图

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.android.xz.egldemo.view.MySurfaceViewandroid:layout_width="200dp"android:layout_height="200dp"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /></androidx.constraintlayout.widget.ConstraintLayout>

EGL环境创建好后,我们就可以在draw方法中编写OpenGL代码来绘制各种各样的图像了。EGL环境代码基本都是固定的流程,OpenGL绘制完成后,调用EGLswapBuffers将OpenGL绘制的内容显示到EGLSurface上也就是设备的屏幕上。

最后

本文简述了OpenGL是如何将绘制的图像显示到设备上的,这离不开EGL的功劳,它通过和OpenGL和设备窗口来回周旋,将一幅幅精美的图案呈现到人们的眼前,给它点个赞。

本文代码已经全部粘贴出来,所以就不放项目地址了:)

这篇关于Android OpenGLES开发:EGL环境搭建的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1136490

相关文章

Android开发中gradle下载缓慢的问题级解决方法

《Android开发中gradle下载缓慢的问题级解决方法》本文介绍了解决Android开发中Gradle下载缓慢问题的几种方法,本文给大家介绍的非常详细,感兴趣的朋友跟随小编一起看看吧... 目录一、网络环境优化二、Gradle版本与配置优化三、其他优化措施针对android开发中Gradle下载缓慢的问

使用Go语言开发一个命令行文件管理工具

《使用Go语言开发一个命令行文件管理工具》这篇文章主要为大家详细介绍了如何使用Go语言开发一款命令行文件管理工具,支持批量重命名,删除,创建,移动文件,需要的小伙伴可以了解下... 目录一、工具功能一览二、核心代码解析1. 主程序结构2. 批量重命名3. 批量删除4. 创建文件/目录5. 批量移动三、如何安

Android 悬浮窗开发示例((动态权限请求 | 前台服务和通知 | 悬浮窗创建 )

《Android悬浮窗开发示例((动态权限请求|前台服务和通知|悬浮窗创建)》本文介绍了Android悬浮窗的实现效果,包括动态权限请求、前台服务和通知的使用,悬浮窗权限需要动态申请并引导... 目录一、悬浮窗 动态权限请求1、动态请求权限2、悬浮窗权限说明3、检查动态权限4、申请动态权限5、权限设置完毕后

Android里面的Service种类以及启动方式

《Android里面的Service种类以及启动方式》Android中的Service分为前台服务和后台服务,前台服务需要亮身份牌并显示通知,后台服务则有启动方式选择,包括startService和b... 目录一句话总结:一、Service 的两种类型:1. 前台服务(必须亮身份牌)2. 后台服务(偷偷干

本地搭建DeepSeek-R1、WebUI的完整过程及访问

《本地搭建DeepSeek-R1、WebUI的完整过程及访问》:本文主要介绍本地搭建DeepSeek-R1、WebUI的完整过程及访问的相关资料,DeepSeek-R1是一个开源的人工智能平台,主... 目录背景       搭建准备基础概念搭建过程访问对话测试总结背景       最近几年,人工智能技术

在Mysql环境下对数据进行增删改查的操作方法

《在Mysql环境下对数据进行增删改查的操作方法》本文介绍了在MySQL环境下对数据进行增删改查的基本操作,包括插入数据、修改数据、删除数据、数据查询(基本查询、连接查询、聚合函数查询、子查询)等,并... 目录一、插入数据:二、修改数据:三、删除数据:1、delete from 表名;2、truncate

基于Python开发PPTX压缩工具

《基于Python开发PPTX压缩工具》在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,不便于传输和存储,所以本文将使用Python开发一个PPTX压缩工具,需要的可以了解下... 目录引言全部代码环境准备代码结构代码实现运行结果引言在日常办公中,PPT文件往往因为图片过大而导致文件体积过大,

Android kotlin语言实现删除文件的解决方案

《Androidkotlin语言实现删除文件的解决方案》:本文主要介绍Androidkotlin语言实现删除文件的解决方案,在项目开发过程中,尤其是需要跨平台协作的项目,那么删除用户指定的文件的... 目录一、前言二、适用环境三、模板内容1.权限申请2.Activity中的模板一、前言在项目开发过程中,尤

5分钟获取deepseek api并搭建简易问答应用

《5分钟获取deepseekapi并搭建简易问答应用》本文主要介绍了5分钟获取deepseekapi并搭建简易问答应用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需... 目录1、获取api2、获取base_url和chat_model3、配置模型参数方法一:终端中临时将加

使用DeepSeek API 结合VSCode提升开发效率

《使用DeepSeekAPI结合VSCode提升开发效率》:本文主要介绍DeepSeekAPI与VisualStudioCode(VSCode)结合使用,以提升软件开发效率,具有一定的参考价值... 目录引言准备工作安装必要的 VSCode 扩展配置 DeepSeek API1. 创建 API 请求文件2.