Android OpenGLES开发:EGL环境搭建

news2024/12/23 19:16:59

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

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采用该种方式,他是内部起一个while循环)

使用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、SurfaceTexture
        int[] 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、初始化EGL
        int[] 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, 16,
                //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、ChooseConfig
        if (!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、创建渲染Surface
        int[] 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);
    }

    @Override
    public void surfaceCreated(@NonNull SurfaceHolder holder) {
        Log.i(TAG, "surfaceCreated.");
        mEGLHelper.initEGL(holder);
        draw();
        mEGLHelper.swapBuffers();
    }

    @Override
    public void surfaceChanged(@NonNull SurfaceHolder holder, int format, int width, int height) {
        Log.i(TAG, "surfaceChanged.");
        GLES20.glViewport(0, 0, width, height);
        draw();
        mEGLHelper.swapBuffers();
    }

    @Override
    public 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.MySurfaceView
        android: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和设备窗口来回周旋,将一幅幅精美的图案呈现到人们的眼前,给它点个赞。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2106378.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

eetrade:黄金分哪几种,什么金最好

随着黄金价格的持续走高&#xff0c;越来越多的消费者开始关注黄金的购买。市场上出现了多种黄金类型&#xff0c;如足金、千足金、万足金、3D硬金、古法黄金等&#xff0c;让人感到困惑。本文将为您详细解析这些黄金的种类及其含金量&#xff0c;帮助您更好地理解和选择。 一…

备忘录在哪添加图片?桌面备忘录能保存图片吗

在快节奏的生活中&#xff0c;备忘录app已成为我们日常工作和学习的得力助手。它帮助我们规划任务、提醒重要事件&#xff0c;确保一切井然有序。但备忘录的用途远不止于此&#xff0c;随着科技的发展&#xff0c;现在的备忘录功能已经越来越强大。 很多人习惯在备忘录中记录文…

2.门锁_STM32_舵机设备实现

概述 需求来源&#xff1a; 门锁的开启和关闭&#xff0c;就是电机来控制。这里不进行实际门锁机械结构的设计&#xff0c;选择用舵机或者电机转动一定的角度&#xff0c;就代表门锁开启。 舵机开发整体思路&#xff1a; 使用STM32裸机开发舵机&#xff0c;使得舵机可以实现…

悟空有枪:玩家解包文件发现《黑神话》有AK47

今日&#xff0c;Reddit的《黑神话》子版的一位玩家分享了本作的全新震撼内容&#xff1a;AK47。据他描述&#xff0c;这是一位中国玩家解包发现的&#xff0c;页面描述十分搞笑&#xff1a;不能化身白衣秀士&#xff0c;捻诀念咒&#xff0c;什么也不会发生&#xff0c;快慢机…

【有啥问啥】抽象语法树(Abstract Syntax Tree, AST)的原理详解

抽象语法树&#xff08;Abstract Syntax Tree, AST&#xff09;的原理详解 引言 在编译器设计、编程语言解析以及静态分析工具中&#xff0c;抽象语法树&#xff08;AST&#xff09;是一个至关重要的概念。AST是一种树状结构&#xff0c;用于表示源代码的抽象语法&#xff0c…

ubuntu 常见问题的收录

在使用过程中&#xff0c;发现ubuntu的问题一点不必windows少。因为每次遇到问题都需要要上网找&#xff0c;所以收集起来之后就会方便一些。 版本体验 24.04&#xff1a;整体的风格大变样&#xff0c;更趋近于“现代化”&#xff1f;反正我是更喜欢了 &#x1f604;。就着风…

PAT.7-1 按格式合并两个链表

题目 解题思路 题目一看是和链表相关的&#xff0c;而且是两个链表&#xff0c;那肯定核心思路和双指针相关了。 我们来一步步拆分问题&#xff1a; 首先我们要把给我们的链表构建出来&#xff0c;所以需要一个Node类&#xff0c;以及一个buildNode的方法。那么输入给我们的是…

CAS理解和说明

目录 1.CAS是什么? 2.CAS的应用场景 2.1 实现原子类 2.2 实现自旋锁 3.CAS的典型问题:ABA问题 1.CAS是什么? CAS:全称compare and swap(比较并交换) 我们假设内存中的原始数据V&#xff0c;旧的预期值A&#xff0c;需要修改的新值B 1.比较A与V是否相等&#xff08;比较…

EmguCV学习笔记 VB.Net 9.2 VideoWriter类

版权声明&#xff1a;本文为博主原创文章&#xff0c;转载请在显著位置标明本文出处以及作者网名&#xff0c;未经作者允许不得用于商业目的。 EmguCV是一个基于OpenCV的开源免费的跨平台计算机视觉库,它向C#和VB.NET开发者提供了OpenCV库的大部分功能。 教程VB.net版本请访问…

Android Camera 之 CameraInfo 编码模板(前后置摄像头理解、摄像头图像的自然方向理解)

一、Camera.CameraInfo Camera.CameraInfo 是用于获取设备上摄像头信息的一个类&#xff0c;它提供摄像头的各种详细信息&#xff0c;例如&#xff0c;摄像头的方向、是否支持闪光灯等&#xff0c;以下是它的常用属性 static int CAMERA_FACING_BACK&#xff1a;表示设备的后置…

kubernetes 中 利用yaml文件部署应用

目录 1 用yaml文件部署应用有以下优点 1.1 声明式配置&#xff1a; 1.2 灵活性和可扩展性&#xff1a; 1.3 与工具集成&#xff1a; 2 资源清单参数介绍 2.1 获得资源帮助指令explain 2.2 编写示例 2.2.1 示例1&#xff1a;运行简单的单个容器pod 2.2.2 示例2&#xff1a;运行…

二叉树 - 最大二叉树

654. 最大二叉树 方法一 /*** Definition for a binary tree node.* function TreeNode(val, left, right) {* this.val (valundefined ? 0 : val)* this.left (leftundefined ? null : left)* this.right (rightundefined ? null : right)* }*/ /*** param…

java整合Redission

1.maven仓库查询Redisson并倒入项目 <dependency><groupId>org.redisson</groupId><artifactId>redisson-spring-boot-starter</artifactId><version>3.35.0</version> </dependency> 2.配置文件&#xff08;采用yml配置方式&…

江协科技STM32学习- P9 OLED调试工具

&#x1f680;write in front&#x1f680; &#x1f50e;大家好&#xff0c;我是黄桃罐头&#xff0c;希望你看完之后&#xff0c;能对你有所帮助&#xff0c;不足请指正&#xff01;共同学习交流 &#x1f381;欢迎各位→点赞&#x1f44d; 收藏⭐️ 留言&#x1f4dd;​…

2024年9月5日历史上的今天大事件早读

1885年9月5日 左宗棠病逝福州 1894年9月5日 中国古文字学家容庚出生 1905年9月5日 在中国土地上进行的日俄战争结束 1919年9月5日 可口可乐公司成立 1929年9月5日 上海沙逊大厦落成 1937年9月5日 最大一次纳粹集会在纽伦堡举行 1939年9月5日 汪伪政权设立特务组织“七十六…

vue3安装sass时报错:Embedded Dart Sass couldn‘t find the embedded compiler executable

vue3安装sass&#xff1a; npm install sass --save-dev 引用 <template><div class"c1"><h1>hello</h1></div> </template> <style lang"scss">.c1{background-color:red;h1{color:yellow;}} </style>报…

通信算法之230: 5G随机接入PRACH及长度计算

在介绍超远覆盖特性之前&#xff0c;先需了解一下终端接入网络的基本过程。在任何情况下&#xff0c;终端同网络建立通信&#xff0c;都需通过RACH(随机接入信道)向网络发送一个报文来向系统申请一条信令信道&#xff0c;这就是随机接入的过程。根据3GPP 5G R15标准&#xff0c…

如何禁止 Ubuntu 内核更新 ?

更新系统对于保持它的安全和运行是很重要的&#xff0c;然而有时您可能希望停止内核的更新。如果您需要保持系统稳定&#xff0c;或者特定软件在某个内核版本上运行得最好&#xff0c;那么这将非常有用。 在本指南中&#xff0c;我们将向您展示如何在 Ubuntu 中阻止内核更新。…

基于 Konva 实现Web PPT 编辑器(二)

动画系统 为了实现演示中复杂的动画效果&#xff0c;使用 Animation 类统一管理&#xff1b;切换动画通过 css animation 实现&#xff0c;并且是应用在 konvajs-content 上&#xff0c;动画则通过 gsap 实现&#xff0c;应用在 Konva.Node 上&#xff0c;实现思路如下&#xf…

win12R2安装.NET Framework 3.5

一丶安装原因 因此插件的缺失, 有些软件或系统不支持安装. 二丶安装步骤 1丶下载.NET Framework 3.5 点击插件下载, 提取码: 1995, 下载完成之后解压到想要安装的位置上. 2丶打开 服务器管理器 3丶点击: 管理 -> 添加角色和功能 4丶点击下一步到服务器角色, 选择web服…