当前位置: 首页 > news >正文

Open GL ES -> SurfaceView + 自定义EGL实现OpenGL渲染框架

SurfaceView + 自定义EGL实现OpenGL渲染

Android开发中,当需要灵活控制OpenGL渲染或在多个Surface间共享EGL上下文时,自定义EGL环境是必要的选择

核心实现流程

+--------------------+     +--------------------+     +--------------------+
| 1. 创建SurfaceView | --> | 2. 初始化EGL环境   | --> | 3. 渲染线程管理    |
+--------------------+     +--------------------+     +--------------------+

1. 创建SurfaceView

继承SurfaceView并实现SurfaceHolder.Callback接口,管理Surface生命周期:

class MySurfaceView(context: Context, attrs: AttributeSet) : SurfaceView(context, attrs), SurfaceHolder.Callback {init {holder.addCallback(this)}private var mEGLHelper = MyEGLHelper()private var mEGLRender = MyEGLRender(context)private var mEGLThread: MyEGLThread? = nulloverride fun surfaceCreated(holder: SurfaceHolder) {// 创建并启动渲染线程mEGLThread = MyEGLThread(holder.surface).apply {start()}}override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {mEGLThread?.changeSize(width, height)}override fun surfaceDestroyed(holder: SurfaceHolder) {mEGLThread?.release()}// 渲染线程实现inner class MyEGLThread(private val mSurface: Surface) : Thread() {private var mWidth = 0private var mHeight = 0@Volatileprivate var mRunning = true@Volatileprivate var mSizeChanged = falseoverride fun run() {super.run()try {mEGLHelper.initEGL(mSurface)mEGLRender.onSurfaceCreated()while (mRunning) {// 宽高变化,回调渲染器的onSurfaceChanged方法if (mSizeChanged) {mEGLRender.onSurfaceChanged(mWidth, mHeight)mSizeChanged = false}// 渲染一帧, 回调渲染器的onDrawFrame方法mEGLRender.onDrawFrame()mEGLHelper.swapBuffer()}} catch (e: Exception) {Log.e("yang", "EGL thread error ${e.message}")}}fun changeSize(width: Int, height: Int) {mWidth = widthmHeight = heightmSizeChanged = true}fun release() {mRunning = falsemEGLRender.onSurfaceDestroyed()mEGLHelper.releaseEGL()interrupt()}}

2. 初始化EGL环境

负责EGL环境的初始化、配置和销毁:

class MyEGLHelper {private lateinit var mEGL: EGL10private lateinit var mEGLDisplay: EGLDisplayprivate lateinit var mEGLContext: EGLContextprivate lateinit var mEGLSurface: EGLSurface// 初始化EGLfun initEGL(surface: Surface) {if (::mEGL.isInitialized &&::mEGLDisplay.isInitialized &&::mEGLContext.isInitialized &&::mEGLSurface.isInitialized) {Log.e("yang", "EGL already initialized")return}// 1. 获取EGL实例mEGL = EGLContext.getEGL() as EGL10// 2. 获取默认的显示设备(就是窗口)mEGLDisplay = mEGL.eglGetDisplay(EGL10.EGL_DEFAULT_DISPLAY)takeIf { mEGLDisplay == EGL10.EGL_NO_DISPLAY }?.apply {throw RuntimeException("eglGetDisplay failed")}// 3. 初始化默认显示设备val version = IntArray(2)takeIf { !mEGL.eglInitialize(mEGLDisplay, version) }?.apply {throw RuntimeException("eglInitialize failed")}// 4. 设置显示设备的属性val display_attribute_list = intArrayOf(EGL_RED_SIZE, 8,EGL_GREEN_SIZE, 8,EGL_BLUE_SIZE, 8,EGL_ALPHA_SIZE, 8,EGL_DEPTH_SIZE, 8,EGL_STENCIL_SIZE, 4,EGL_NONE)// 5. 查找配置并进行 attribute_list 的匹配, 匹配成功返回一个数组val num_config = IntArray(1)takeIf {!mEGL.eglChooseConfig(mEGLDisplay,display_attribute_list,null,0,num_config)}?.apply {throw RuntimeException("eglChooseConfig failed")}// 匹配是否成功takeIf { num_config[0] <= 0 }?.apply {throw RuntimeException("eglChooseConfig#1 failed")}val eglConfigs = arrayOfNulls<EGLConfig>(num_config[0])takeIf {!mEGL.eglChooseConfig(mEGLDisplay,display_attribute_list,eglConfigs,num_config[0],num_config)}?.apply {throw RuntimeException("eglChooseConfig#2 failed")}// 6. 创建EGLContextval context_display_list = intArrayOf(EGL_CONTEXT_CLIENT_VERSION, 3,EGL_NONE)takeIf { ::mEGLContext.isInitialized == false }?.apply {mEGLContext = mEGL.eglCreateContext(mEGLDisplay,eglConfigs[0],EGL10.EGL_NO_CONTEXT,context_display_list)}takeIf { mEGLContext == EGL10.EGL_NO_CONTEXT }?.apply {throw RuntimeException("eglCreateContext failed")}// 7. 创建EGLSurfacetakeIf { ::mEGLSurface.isInitialized == false }?.apply {mEGLSurface = mEGL.eglCreateWindowSurface(mEGLDisplay, eglConfigs[0], surface, null)}takeIf { mEGLSurface == EGL10.EGL_NO_SURFACE }?.apply {throw RuntimeException("eglCreateWindowSurface failed")}// 8. 绑定EGLContext和EGLSurfacetakeIf { !mEGL.eglMakeCurrent(mEGLDisplay, mEGLSurface, mEGLSurface, mEGLContext) }?.apply {throw RuntimeException("eglMakeCurrent failed")}}// 释放EGLfun releaseEGL() {takeIf { ::mEGL.isInitialized }?.apply {// 解绑EGLContext和EGLSurfacemEGL.eglMakeCurrent(mEGLDisplay,EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_SURFACE,EGL10.EGL_NO_CONTEXT)// 释放EGLSurfacemEGL.eglDestroySurface(mEGLDisplay, mEGLSurface)// 释放EGLContextmEGL.eglDestroyContext(mEGLDisplay, mEGLContext)// 释放EGLDisplaymEGL.eglTerminate(mEGLDisplay)}}// 交换渲染数据fun swapBuffer() {takeIf { ::mEGL.isInitialized && ::mEGLDisplay.isInitialized }?.apply {takeIf { !mEGL.eglSwapBuffers(mEGLDisplay, mEGLSurface) }?.apply {throw RuntimeException("eglSwapBuffers failed")}}}
}

3. 渲染线程管理

在独立线程中处理渲染循环:

inner class MyEGLThread(private val mSurface: Surface) : Thread() {private var mWidth = 0private var mHeight = 0@Volatileprivate var mRunning = true@Volatileprivate var mSizeChanged = falseoverride fun run() {super.run()try {mEGLHelper.initEGL(mSurface)mEGLRender.onSurfaceCreated()while (mRunning) {// 宽高变化,回调渲染器的onSurfaceChanged方法if (mSizeChanged) {mEGLRender.onSurfaceChanged(mWidth, mHeight)mSizeChanged = false}// 渲染一帧, 回调渲染器的onDrawFrame方法mEGLRender.onDrawFrame()mEGLHelper.swapBuffer()}} catch (e: Exception) {Log.e("yang", "EGL thread error ${e.message}")}}fun changeSize(width: Int, height: Int) {mWidth = widthmHeight = heightmSizeChanged = true}fun release() {mRunning = falsemEGLRender.onSurfaceDestroyed()mEGLHelper.releaseEGL()interrupt()}}

4. 渲染器接口

定义渲染器接口,类似于GLSurfaceView.Renderer

interface EGLRender {fun onSurfaceCreated()  // Surface创建时调用fun onSurfaceChanged(width: Int, height: Int)  // Surface尺寸变化时调用fun onDrawFrame()  // 每帧渲染时调用fun onSurfaceDestroyed()  // Surface销毁时调用
}

5. 渲染器实现

实现渲染器接口,处理具体的OpenGL渲染逻辑:

class MyEGLRender(private val mContext: Context) : EGLRender {override fun onSurfaceCreated() {GLES30.glClearColor(0.0f, 0.5f, 0.5f, 1.0f)// 加载纹理...// 初始化顶点缓冲区...// 初始化着色器程序...}override fun onSurfaceChanged(width: Int, height: Int) {GLES30.glViewport(0, 0, width, height)// 改变渲染数据的宽高...}override fun onDrawFrame() {GLES30.glEnable(GLES30.GL_DEPTH_TEST)GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT or GLES30.GL_DEPTH_BUFFER_BIT)// 具体绘制方法...}override fun onSurfaceDestroyed() {// 销毁渲染数据...}
}

完整流程图

整体渲染流程图

+----------------------+     +----------------------+
| SurfaceView创建      | --> | 注册SurfaceHolder    |
| MySurfaceView构造函数|     | Callback回调        |
+----------------------+     +----------------------+|v
+----------------------+     +----------------------+     +----------------------+
| Surface创建          | --> | 创建渲染线程        | --> | 初始化EGL环境        |
| surfaceCreated回调   |     | MyEGLThread.start() |     | mEGLHelper.initEGL() |
+----------------------+     +----------------------+     +----------------------+|                                                        ||                                                        v
+----------------------+     +----------------------+     +----------------------+
| Surface尺寸变化      | --> | 通知渲染线程        |     | 初始化渲染器         |
| surfaceChanged回调   |     | changeSize()        |     | onSurfaceCreated()   |
+----------------------+     +----------------------+     +----------------------+|                                                        ||                                                        v
+----------------------+                                 +----------------------+
| Surface销毁          |                                 | 渲染循环开始         |
| surfaceDestroyed回调 |                                 | 循环检查尺寸变化     |
+----------------------+                                 +----------------------+|                                                        |v                                                        v
+----------------------+     +----------------------+     +----------------------+
| 停止渲染线程        | <-- | 释放OpenGL资源       | <-- | 执行渲染操作        |
| mEGLThread.release() |     | onSurfaceDestroyed() |     | onDrawFrame()       |
+----------------------+     +----------------------+     +----------------------+|                                                        |v                                                        v
+----------------------+     +----------------------+     +----------------------+
| 释放EGL资源         |     | 线程退出            |     | 交换缓冲区          |
| mEGLHelper.releaseEGL()|     | 渲染循环结束        |     | swapBuffer()        |
+----------------------+     +----------------------+     +----------------------+

EGL初始化流程图

+------------------+     +------------------+     +------------------+
| 获取EGL实例      | --> | 获取显示设备     | --> | 初始化显示设备   |
| mEGL = EGLContext|     | eglGetDisplay    |     | eglInitialize    |
| .getEGL()        |     |                  |     |                  |
+------------------+     +------------------+     +------------------+|                                                 |v                                                 v
+------------------+     +------------------+     +------------------+
| 设置EGL属性      | --> | 选择EGL配置      | --> | 创建EGL上下文    |
| RGB/Alpha/Depth  |     | eglChooseConfig  |     | eglCreateContext |
+------------------+     +------------------+     +------------------+|                                                 |v                                                 v
+------------------+     +------------------+
| 创建渲染Surface  | --> | 绑定EGL组件      |
| eglCreateWindow  |     | eglMakeCurrent   |
| Surface          |     |                  |
+------------------+     +------------------+
渲染线程管理流程图
+------------------+     +------------------+     +------------------+
| 线程启动         | --> | 初始化EGL环境    | --> | 初始化渲染器     |
| Thread.start()   |     | initEGL(surface) |     | onSurfaceCreated |
+------------------+     +------------------+     +------------------+|                                                 |v                                                 v
+------------------+     +------------------+     +------------------+
| 渲染循环         | --> | 检查尺寸变化     | --> | 执行渲染         |
| while(mRunning)  |     | if(mSizeChanged) |     | onDrawFrame()    |
+------------------+     +------------------+     +------------------+|                          |                      ||                          v                      v|              +------------------+     +------------------+|              | 更新视口         |     | 交换缓冲区       ||              | onSurfaceChanged |     | swapBuffer()     ||              +------------------+     +------------------+|                                                 |v                                                 v
+------------------+     +------------------+     +------------------+
| 接收释放信号     | --> | 通知渲染器销毁   | --> | 释放EGL资源      |
| release()调用    |     | onSurfaceDestroy |     | releaseEGL()     |
+------------------+     +------------------+     +------------------+|v
+------------------+
| 线程结束         |
| interrupt()      |
+------------------+

相关文章:

Open GL ES -> SurfaceView + 自定义EGL实现OpenGL渲染框架

SurfaceView 自定义EGL实现OpenGL渲染 在Android开发中&#xff0c;当需要灵活控制OpenGL渲染或在多个Surface间共享EGL上下文时&#xff0c;自定义EGL环境是必要的选择 核心实现流程 -------------------- -------------------- -------------------- | 1. 创建Su…...

Solidity入门实战—web3

项目介绍 在这个项目中&#xff0c;我们建立一个小型智能合约应用&#xff0c;他允许用户向合约地址捐赠&#xff0c;允许合约所有者从合约中提取余额&#xff1b;并且还设定了捐赠的金额门槛&#xff1b;针对直接对地址进行的捐赠行为&#xff0c;我们也予以记录 源代码 ht…...

Open Scene Graph动画系统

OSG 提供了强大的动画功能&#xff0c;支持多种动画实现方式&#xff0c;从简单的变换动画到复杂的骨骼动画。以下是 OSG 动画系统的全面介绍&#xff1a; 1. 基本动画类型 1.1 变换动画 (Transform Animation) // 创建动画路径 osg::AnimationPath* createAnimationPath(co…...

无需libpacp库,BPF指令高效捕获指定数据包

【环境】无libpacp库的Linux服务器 【要求】高效率读取数据包&#xff0c;并过滤指定端口和ip 目前遇到两个问题 一是手写BPF&#xff0c;难以兼容&#xff0c;有些无法正常过滤二是性能消耗问题&#xff0c;尽可能控制到1% 大方向&#xff1a;过滤数据包要在内核层处理&…...

重回全面发展亲自操刀

项目场景&#xff1a; 今年工作变动&#xff0c;优化后在一家做国有项目的私人公司安顿下来了。公司环境不如以前&#xff0c;但是好在瑞欣依然可以每天方便的买到。人文氛围挺好&#xff0c;就是工时感觉有点紧&#xff0c;可能长期从事产品迭代开发&#xff0c;一下子转变做项…...

DimensionX

旨在通过可控的视频扩散模型从单张图像生成高质量的3D和4D场景。 1. 背景与问题 3D和4D生成的目标 3D生成&#xff1a;从单张或多张2D图像中重建出三维场景或物体&#xff0c;包含空间信息&#xff08;长、宽、高&#xff09;。4D生成&#xff1a;在3D的基础上加入时间维度&a…...

2025年04月08日Github流行趋势

项目名称&#xff1a;markitdown 项目地址url&#xff1a;https://github.com/microsoft/markitdown项目语言&#xff1a;Python历史star数&#xff1a;44895今日star数&#xff1a;1039项目维护者&#xff1a;afourney, gagb, sugatoray, PetrAPConsulting, l-lumin项目简介&a…...

数据结构与算法-数学-容斥原理,高斯消元解线性方程组

容斥原理 容斥原理用于计算多个集合的并集元素个数&#xff0c;公式为 ∣A1∪A2∪⋯∪An∣∑i1n∣Ai∣−∑1≤i<j≤n∣Ai∩Aj∣∑1≤i<j<k≤n∣Ai∩Aj∩Ak∣−⋯(−1)n−1∣A1∩A2∩⋯∩An∣ 举一个例题&#xff1a; 给定一个整数 nn 和 mm 个不同的质数 p1,p2,…,p…...

告别运动控制不同步:某车企用异构PLC实现99.98%焊接合格率

在长三角某新能源汽车电池工厂&#xff0c;工程师们正面临棘手的生产难题&#xff1a;随着产线速度提升到每分钟12个电芯&#xff0c;原有PLC系统开始频繁出现运动控制不同步现象。这直接导致极片焊接合格率从99.2%骤降至94.7%&#xff0c;每条产线日均损失超23万元。这个场景折…...

BetaFlight参数配置解读

BetaFlight参数配置解读 &#x1f4cc;相关篇《Betaflight固件编译和烧录说明》&#x1f955;各型号已编译好的配置文件资源&#xff08;.config&#xff09;&#xff1a;https://github.com/betaflight/unified-targets/tree/master/configs/default&#x1f33f;各型号配置头…...

PowerBI累计分析

累计分析 累计分析主要有三种&#xff1a;年初至今&#xff08;YTD&#xff09;、季初至今&#xff08;QTD&#xff09;、月初至今&#xff08;MTD&#xff09;。DAX中计算累计的函数有两类&#xff1a;一类是datesytd、datesqtd、datesmtd&#xff0c;该类返回一个单列日期表…...

最新 OpenHarmony 系统一二级目录整理

我们在学习 OpenHarmony 的时候&#xff0c;如果对系统的目录结构了解&#xff0c;那么无疑会提升自己对 OpenHarmony 更深层次的认识。 于是就有了今天的整理。 首先在此之前&#xff0c;我们要获取源码 获取源码的方式 OpenHarmony 主干代码获取 方式一&#xff08;推荐&am…...

多模态大语言模型arxiv论文略读(七)

MLLM-DataEngine: An Iterative Refinement Approach for MLLM ➡️ 论文标题&#xff1a;MLLM-DataEngine: An Iterative Refinement Approach for MLLM ➡️ 论文作者&#xff1a;Zhiyuan Zhao, Linke Ouyang, Bin Wang, Siyuan Huang, Pan Zhang, Xiaoyi Dong, Jiaqi Wang,…...

STM32单片机入门学习——第27节: [9-3] USART串口发送串口发送+接收

写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难&#xff0c;但我还是想去做&#xff01; 本文写于&#xff1a;2025.04.08 STM32开发板学习——第27节: [9-3] USART串口发送&串口发送接收 前言开发板说…...

【元表 vs 元方法】

元表 vs 元方法 —— 就像“魔法书”和“咒语”的关系 1. 元表&#xff08;Metatable&#xff09;&#xff1a;魔法书 是什么&#xff1f; 元表是一本**“规则说明书”**&#xff0c;它本身是一个普通的 Lua 表&#xff0c;但可以绑定到其他表上&#xff0c;用来定义这个表应该…...

小型园区网实验

划分VLAN SW3 [sw3]vlan batch 2 3 20 30 [sw3]interface GigabitEthernet 0/0/1 [sw3-GigabitEthernet0/0/1]port link-type access [sw3-GigabitEthernet0/0/1]port default vlan 2 [sw3-GigabitEthernet0/0/1]int g0/0/2 [sw3-GigabitEthernet0/0/2]port link-type acces…...

python 数组append数组

在Python中&#xff0c;可以通过多种方式将一个数组&#xff08;列表&#xff09;添加到另一个数组&#xff08;列表&#xff09;中。以下是几种常见的方法&#xff1a; 1. 使用 append() 方法 append() 方法将一个数组作为整体添加到另一个数组的末尾。 list1 [1, 2, 3] l…...

从0到1:STM32 RTC定时器配置全流程

1. 什么是RTC&#xff1f; RTC&#xff08;Real-Time Clock&#xff09; 是嵌入式系统中用于提供独立计时功能的硬件模块&#xff0c;具有以下特点&#xff1a; 独立于主系统时钟&#xff08;即使MCU进入低功耗模式仍可运行&#xff09;提供日历功能&#xff08;年/月/日/时/…...

(学习总结33)Linux Ext2 文件系统与软硬链接

Linux Ext2 文件系统与软硬链接 理解硬件磁盘、服务器、机柜、机房磁盘物理结构磁盘的逻辑结构实际过程 CHS 与 LBA 地址转换 引入文件系统引入 " 块 " 概念引入 " 分区 " 概念引入 " inode " 概念 ext2 文件系统宏观认识Block Group 块组与其内…...

LeetCode算法题(Go语言实现)_36

题目 给定一个二叉树的根节点 root &#xff0c;和一个整数 targetSum &#xff0c;求该二叉树里节点值之和等于 targetSum 的 路径 的数目。 路径 不需要从根节点开始&#xff0c;也不需要在叶子节点结束&#xff0c;但是路径方向必须是向下的&#xff08;只能从父节点到子节点…...

牛客华为机试--HJ48 从单向链表中删除指定值的节点C++

题目描述 示例1 示例2 该题的核心是每来一组数据&#xff0c;都要从头开始找&#xff0c;找到数据后再插入。而不是直接在尾部插入数据。 上代码 #include <iostream> using namespace std;struct ListNode {int val;ListNode *next;ListNode(int x) : val(x), next(nu…...

Jmeter 插件【性能测试监控搭建】

1. 安装Plugins Manager 1.1 下载路径&#xff1a; Install :: JMeter-Plugins.org 1.2 放在lib/ext目录下 1.3 重启Jmeter&#xff0c;会在菜单-选项下多一个 Plugins Manager菜单&#xff0c;打开即可对插件进行安装、升级。 2. 客户端(Jmeter端) 2.1 安装plugins manager…...

从攻防演练到AI防护:网络安全服务厂商F5的全方位安全策略

随着AI和云原生技术的蓬勃兴起&#xff0c;多云架构的广泛采用&#xff0c;企业内部IT系统正经历着翻天覆地的变化。在这个转型期&#xff0c;传统的攻击手段和防守策略正面临着巨大的挑战。基于此&#xff0c;用户需要跳出传统的思维模式&#xff0c;采取新的视角&#xff0c;…...

【Introduction to Reinforcement Learning】翻译解读5

4 核心算法 我们将算法分为三类&#xff1a;基于价值的方法、基于策略的方法和混合算法。 4.1 基于价值的方法Value-based 一个重要的突破是Q-learning的引入&#xff0c;它是一种无模型算法&#xff0c;被视为off-policy时间差分&#xff08;TD&#xff09;学习。TD学习无疑…...

Jmeter中的bzm-concurrency thread group 与普通线程组的区别

在 JMeter 中,bzm - Concurrency Thread Group(由 BlazeMeter 提供)和标准的 Thread Group 是两种不同的线程组实现,主要区别在于 并发控制模型 和 负载调节方式。以下是详细对比: 1. 核心区别 特性bzm - Concurrency Thread Group标准 Thread Group负载模型基于并发数(C…...

VBA将Word文档内容逐行写入Excel

如果你需要将Word文档的内容导入Excel工作表来进行数据加工&#xff0c;使用下面的代码可以实现&#xff1a; Sub ImportWordToExcel()Dim wordApp As Word.ApplicationDim wordDoc As Word.DocumentDim excelSheet As WorksheetDim filePath As VariantDim i As LongDim para…...

ubuntu22部署 3d-tiles-tools

安装fnm curl -fsSL https://fnm.vercel.app/install | bash安装nodejs 20.17.0LTS版本 https://nodejs.org/zh-cn/download/package-manager安装依赖包 # Download and install nvm: curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash# in…...

WebStrom关闭模板字符串自动转换

WebStrom关闭模板字符串自动转换 Editor > General > smart Keys > JavaScript > Automatically replace string literal with template string on typing "${"...

【零基础入门unity游戏开发——动画篇】新动画Animator的使用 —— AnimatorController和Animator的使用

考虑到每个人基础可能不一样&#xff0c;且并不是所有人都有同时做2D、3D开发的需求&#xff0c;所以我把 【零基础入门unity游戏开发】 分为成了C#篇、unity通用篇、unity3D篇、unity2D篇。 【C#篇】&#xff1a;主要讲解C#的基础语法&#xff0c;包括变量、数据类型、运算符、…...

npx vite 可以成功运行,但 npm run dev 仍然报错 Missing script: “dev“

npx vite 可以成功运行,但 npm run dev 仍然报错 Missing script: "dev",说明问题可能出在 npm 的脚本解析 或 项目配置 上。以下是具体解决方案: 1. 检查 package.json 的物理位置 可能原因: 你当前运行的目录下可能有一个 无效的 package.json,而真正的 packa…...

Java 泛型的逆变与协变:深入理解类型安全与灵活性

泛型是 Java 中强大的特性之一&#xff0c;它提供了类型安全的集合操作。然而&#xff0c;泛型的类型关系&#xff08;如逆变与协变&#xff09;常常让人感到困惑。 本文将深入探讨 Java 泛型中的逆变与协变&#xff0c;帮助你更好地理解其原理和应用场景。 一、什么是协变与…...

C语言核心知识点整理:结构体对齐、预处理、文件操作与Makefile

目录 结构体的字节对齐预处理指令详解文件操作基础Makefile自动化构建总结 1. 结构体的字节对齐 字节对齐原理 内存对齐&#xff1a;CPU访问内存时&#xff0c;对齐的地址能提高效率。操作系统要求变量按类型大小对齐。对齐规则&#xff1a; 每个成员的起始地址必须是min(成…...

深度学习|注意力机制

一、注意力提示 随意&#xff1a;跟随主观意识&#xff0c;也就是指有意识。 注意力机制&#xff1a;考虑“随意线索”&#xff0c;有一个注意力池化层&#xff0c;将会最终选择考虑到“随意线索”的那个值 二、注意力汇聚 这一部分也就是讲第一大点中“注意力汇聚”那个池化…...

特权FPGA之乘法器

完整代码如下&#xff1a; timescale 1ns / 1ps// Company: // Engineer: // // Create Date: 23:08:36 04/21/08 // Design Name: // Module Name: mux_16bit // Project Name: // Target Device: // Tool versions: // Description: // // Dependencies: …...

安全的企业局域网聊天工具哪个好用?

在当今数字化时代&#xff0c;企业对于局域网聊天工具的需求日益增长&#xff0c;尤其是在对数据安全和定制化服务有较高要求的大中型政企单位中。安全的企业局域网聊天工具哪个好用&#xff1f;虽然市面上有很多即时通讯软件&#xff0c;今天来介绍一下已经拥有十年行业经验的…...

如何应对客户频繁变更需求

如何应对客户频繁变更需求&#xff1f;要点包括&#xff1a; 快速响应、深入沟通、灵活规划、过程记录、风险管控。这些策略既能降低项目失控风险&#xff0c;也能帮助团队在变动环境中保持高效率。其中深入沟通尤为关键&#xff0c;它不仅能够让团队第一时间了解客户意图&…...

R语言进行聚类分析

目录 简述6种系统聚类法 实验实例和数据资料&#xff1a; 上机实验步骤&#xff1a; 进行最短距离聚类&#xff1a; 进行最长距离聚类&#xff1a; 进行中间距离聚类&#xff1a; 进行类平均法聚类&#xff1a; 进行重心法聚类&#xff1a; 进行ward.D聚类&#xff1a;…...

1.6-抓包技术(Burp Suite\Yakit抓包\Web、APP、小程序)

1.6-抓包技术&#xff08;Burp Suite\Yakit抓包\Web、APP、小程序&#xff09; 如果要使用抓包软件&#xff0c;基本上第一步都是要安装证书的。原因如下&#xff1a; 客户端&#xff08;浏览器或应用&#xff09;会检测到证书不受信任&#xff0c;并弹出 证书错误&#xff0…...

DAPP实战篇:使用web3.js连接合约

说明 本系列内容目录:专栏:区块链入门到放弃查看目录 如果你还没有创建好项目请先查看:《DApp实战篇:先用前端起个项目》,如果你还不知道web3.js是什么请先查看:《DApp实战篇:前端技术栈一览》。 安装 点此查看web3.js官方文档 打开项目根目录,并唤起终端: 键入w…...

用 Python 构建一个简单的本地视频流媒体服务器

你是否曾经想过在本地网络上轻松地将电脑上的视频分享给手机或平板电脑观看&#xff1f;也许你下载了一部电影&#xff0c;想在客厅的智能电视上播放&#xff0c;却不想费力地拷贝文件。今天&#xff0c;我们将深入分析一个 Python 脚本&#xff0c;它使用 wxPython 创建图形用…...

汇丰xxx

1. Spring Boot 的了解&#xff0c;解决什么问题&#xff1f; 我的理解&#xff1a; Spring Boot 是一个基于 Spring 框架的快速开发脚手架&#xff0c;它简化了 Spring 应用的初始搭建和开发过程。解决的问题&#xff1a; 简化配置&#xff1a; 传统的 Spring 应用需要大量的…...

ruby基础语法

以下是 Ruby 基础语法的简明总结&#xff0c;适合快速入门&#xff1a; 一、变量与常量 局部变量 小写字母或下划线开头&#xff0c;作用域为当前代码块。 name "Alice" _age 20实例变量 以 开头&#xff0c;属于对象实例。 name "Bob"类变量 以 开头…...

智体OS-V3.1版:新增了rt-datalink底层数据链通讯,实现【无网络】本机使用

##智体OS-V3.1版本发布 更新简介 dtns.os智体OS-V3.1版&#xff1a;新增了rt-datalink底层数据链通讯&#xff08;使用本地局域网的websocket端口通讯&#xff09;&#xff0c;解决了本机【无网络】正常使用的问题。 更新内容 dtns.connector支持使用新的rt-datalink与智体…...

Windows系统安装Git以及Git常用命令介绍

本文主要介绍Windows系统安装Git的方法&#xff0c;以及Git常用命令介绍。 一、下载Git 官网&#xff1a; Git - Downloads (git-scm.com) 根据自己的系统选择 我的是64位的Windows系统&#xff0c;选择对应的安装包&#xff0c;点击后开始下载 等待下载完成 二、安装Git 双…...

HTML 开发者的智能助手:通义灵码在 VSCode 中的应用

引言 在 HTML 开发领域&#xff0c;提高编码效率和质量是每位开发者追求的目标。通义灵码&#xff0c;作为一款由阿里云技术团队开发的智能编码助手&#xff0c;能够通过其强大的 AI 能力&#xff0c;为 HTML 开发者提供包括代码自动补全、智能注释、代码优化等多方面的支持。…...

MySQL随机获取记录之方法(The Method of Randomly Obtaining Records in MySQL)

MySQL中如何随机获取一条记录 随机获取一条记录是在数据库查询中常见的需求&#xff0c;特别在需要展示随机内容或者随机推荐的场景下。在 MySQL 中&#xff0c;有多种方法可以实现随机获取一条记录&#xff0c;每种方法都有其适用的情况和性能特点。在本文中&#xff0c;我们将…...

ngx_core_module 的 create_conf

Ubuntu 下 nginx-1.24.0 源码分析 - ngx_core_module-CSDN博客 定义在 src\core\nginx.c ngx_module_t ngx_core_module {NGX_MODULE_V1,&ngx_core_module_ctx, /* module context */ngx_core_commands, /* module directives */…...

41--华为IPSec主备链路实验:当加密隧道遇上“双保险“

&#x1f6a6; 华为IPSec主备链路实验&#xff1a;当加密隧道遇上"双保险" “如果你的IPSec隧道只有一条路&#xff0c;那就像走钢丝不系安全带——刺激但危险&#xff01;” —— 本文将用华为设备打造主备双加密通道&#xff0c;结合IP-link智能检测&#xff0c;让…...

Reactive编程框架与工具

文章目录 6.2 后端 Reactive 框架6.2.1 Spring WebFlux核心架构核心组件实际应用高级特性性能优化适用场景与限制 6.2.2 Akka&#xff08;Actor模型&#xff09;Actor模型基础基本用法高级特性响应式特性实现性能优化实际应用场景优势与挑战 6.2.3 Vert.x&#xff08;事件驱动&…...

vi/vim常用快捷键

那么今天我们继续昨天没有介绍完的vi编辑器,来看看常用的一些快捷键,方便我们对文件的编辑. 1.拷贝当前行yy,拷贝当前行向下的5行5yy,并粘贴(输入p) 2.删除当前行dd,删除当前行向下的5行5d 3.在文件中查找某个单词[命令模式/关键字,回车查找,输入n就是查找下一个] ⭐️&…...