ARTICLE AD BOX
Problem Description
I am experiencing a native crash (SIGSEGV) on an Android device (Qualcomm Adreno GPU) when rendering stickers using OpenGL ES 3.0. The crash occurs inside the Adreno driver (libGLESv2_adreno.so) during a draw call.
I recently refactored my rendering code to use Vertex Array Objects (VAO) and Vertex Buffer Objects (VBO) to improve performance by reducing CPU-to-GPU command overhead. I am using OpenGL ES 3.0 to render a mix of standard 2D textures and ExternalOES (Camera/Video) textures in a high-frequency render loop. To optimize performance, I implemented Vertex Array Objects (VAO) and VBOs.
The application runs smoothly for 1 to 2 hours, but eventually, it crashes with a native SIGSEGV inside the Adreno GPU driver.
The Crash Log
The crash happens on the GL thread. Here is the relevant backtrace:
03-09 14:18:09.458 24558 25434 F libc : Fatal signal 11 (SIGSEGV), code 0 (SI_USER) in tid 25434 (HuoShanCameraCo), pid 24558 (unke.llhkb.test) 03-09 14:18:10.038 28883 28883 F DEBUG : *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** *** 03-09 14:18:10.038 28883 28883 F DEBUG : Build fingerprint: 'AiBoo/kona/kona:13/TKQ1.230531.001/eng.builde.20251230.195841:user/release-keys' 03-09 14:18:10.038 28883 28883 F DEBUG : Revision: '0' 03-09 14:18:10.038 28883 28883 F DEBUG : ABI: 'arm64' 03-09 14:18:10.038 28883 28883 F DEBUG : Timestamp: 2026-03-09 14:18:09.736754684+0800 03-09 14:18:10.038 28883 28883 F DEBUG : Process uptime: 5050s 03-09 14:18:10.038 28883 28883 F DEBUG : Cmdline: com.mysoft.yunke.llhkb.test 03-09 14:18:10.038 28883 28883 F DEBUG : pid: 24558, tid: 25434, name: HuoShanCameraCo >>> com.mysoft.yunke.llhkb.test <<< 03-09 14:18:10.038 28883 28883 F DEBUG : uid: 10142 03-09 14:18:10.038 28883 28883 F DEBUG : signal 11 (SIGSEGV), code 0 (SI_USER), fault addr -------- 03-09 14:18:10.038 28883 28883 F DEBUG : x0 0000000000000000 x1 0000000000000001 x2 b4000074932354f0 x3 000000742f3b8c48 03-09 14:18:10.038 28883 28883 F DEBUG : x4 0000000000000000 x5 0000000000000026 x6 022007802385a883 x7 0000000000000001 03-09 14:18:10.038 28883 28883 F DEBUG : x8 000000742f3b8c48 x9 000000000000635a x10 000000742f3c9928 x11 0000000000000000 03-09 14:18:10.038 28883 28883 F DEBUG : x12 0000000000000006 x13 0000000000000000 x14 0000000000000008 x15 b400007553347580 03-09 14:18:10.038 28883 28883 F DEBUG : x16 0000000000000001 x17 0000000000000000 x18 0000000000000000 x19 0000000000000001 03-09 14:18:10.038 28883 28883 F DEBUG : x20 b4000074c3f0ffc0 x21 b400007533c89230 x22 0000000000000000 x23 0000000000000001 03-09 14:18:10.038 28883 28883 F DEBUG : x24 0000000000000000 x25 0000000000000001 x26 b4000075634f9450 x27 b400007657b08808 03-09 14:18:10.038 28883 28883 F DEBUG : x28 0000000000000001 x29 0000007235b48d10 03-09 14:18:10.038 28883 28883 F DEBUG : lr 000000742f232b10 sp 0000007235b48d10 pc 000000742f232b2c pst 0000000060001000 03-09 14:18:10.038 28883 28883 F DEBUG : backtrace: 03-09 14:18:10.038 28883 28883 F DEBUG : #00 pc 000000000022db2c /vendor/lib64/egl/libGLESv2_adreno.so (!!!0000!44e6cf2d5367acd14cfb232e5f66a9!43fc279f3a!+612) (BuildId: 00bc7e95eb31ffde5a0d9db10cbea2ab) 03-09 14:18:10.038 28883 28883 F DEBUG : #01 pc 0000000000396058 /vendor/lib64/egl/libGLESv2_adreno.so (!!!0000!8c9f5a62f5a016bcd3b71c1e0c3a1d!43fc279f3a!+456) (BuildId: 00bc7e95eb31ffde5a0d9db10cbea2ab) 03-09 14:18:10.038 28883 28883 F DEBUG : #02 pc 0000000000389274 /vendor/lib64/egl/libGLESv2_adreno.so (!!!0000!f56be09eb88f86833124f1df42e945!43fc279f3a!+33252) (BuildId: 00bc7e95eb31ffde5a0d9db10cbea2ab) 03-09 14:18:10.038 28883 28883 F DEBUG : #03 pc 0000000000176c9c /vendor/lib64/egl/libGLESv2_adreno.so (!!!0000!6b200851123c7898055fe62ff9f71f!43fc279f3a!+620) (BuildId: 00bc7e95eb31ffde5a0d9db10cbea2ab) 03-09 14:18:10.038 28883 28883 F DEBUG : #04 pc 000000000015cc7c /vendor/lib64/egl/libGLESv2_adreno.so (!!!0000!28254c066fd778faffa7894b1bd8b1!43fc279f3a!+196) (BuildId: 00bc7e95eb31ffde5a0d9db10cbea2ab) 03-09 14:18:10.038 28883 28883 F DEBUG : #05 pc 00000000001bd6ac /system/framework/arm64/boot-framework.oat (art_jni_trampoline+124) (BuildId: c72164474d55ee50a3649a1ea2cbbc7fdfc07d50) 03-09 14:18:10.038 28883 28883 F DEBUG : #06 pc 00000000021bd140 /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.huoshan.opengl.StickerProgram.drawStickerOptimized+576) 03-09 14:18:10.038 28883 28883 F DEBUG : #07 pc 00000000021af10c /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.huoshan.opengl.StickerProgram.renderStickers+684) 03-09 14:18:10.038 28883 28883 F DEBUG : #08 pc 000000000217f374 /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.mix.StickerManager.process+564) 03-09 14:18:10.038 28883 28883 F DEBUG : #09 pc 0000000002040130 /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.mix.YunKeMixManager.processVideoFrameInternal+608) 03-09 14:18:10.038 28883 28883 F DEBUG : #10 pc 000000000215d54c /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.mix.YunKeMixManager.lambda$startVideoCapture$5+556) 03-09 14:18:10.038 28883 28883 F DEBUG : #11 pc 000000000206ed54 /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.mix.YunKeMixManager.$r8$lambda$es8J5oktwBFBaoRp1TYPKq_Fc8c+84) 03-09 14:18:10.038 28883 28883 F DEBUG : #12 pc 00000000020122dc /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.mix.YunKeMixManager$$ExternalSyntheticLambda3.onCameraViewVideoFrame+108) 03-09 14:18:10.038 28883 28883 F DEBUG : #13 pc 0000000002097e0c /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.CameraView.lambda$useYunKeGLSurfaceView$0+108) 03-09 14:18:10.038 28883 28883 F DEBUG : #14 pc 0000000002145ff0 /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.CameraView.$r8$lambda$l7qhTvnqbZt-1cRhOYHogxwJJCo+80) 03-09 14:18:10.038 28883 28883 F DEBUG : #15 pc 00000000020054fc /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.CameraView$$ExternalSyntheticLambda0.onPreEncodeVideoFrame+92) 03-09 14:18:10.038 28883 28883 F DEBUG : #16 pc 00000000020533c4 /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.huoshan.camera.HuoShanEffectCameraControl2.drawOnScreen+132) 03-09 14:18:10.038 28883 28883 F DEBUG : #17 pc 000000000200091c /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.huoshan.camera.HuoShanCameraControl2$RenderThread.doFrame+1356) 03-09 14:18:10.038 28883 28883 F DEBUG : #18 pc 00000000020795b0 /memfd:jit-cache (deleted) (com.mysoft.yunke.lib_livecore.camera.huoshan.camera.HuoShanCameraControl2$RenderThread.run+688) 03-09 14:18:10.038 28883 28883 F DEBUG : #19 pc 000000000021096c /apex/com.android.art/lib64/libart.so (art_quick_invoke_stub+556) (BuildId: 3c99f91941a4d3092e2569c2315c7080) 03-09 14:18:10.038 28883 28883 F DEBUG : #20 pc 000000000027b478 /apex/com.android.art/lib64/libart.so (art::ArtMethod::Invoke(art::Thread*, unsigned int*, unsigned int, art::JValue*, char const*)+188) (BuildId: 3c99f91941a4d3092e2569c2315c7080) 03-09 14:18:10.038 28883 28883 F DEBUG : #21 pc 0000000000611a28 /apex/com.android.art/lib64/libart.so (art::JValue art::InvokeVirtualOrInterfaceWithJValues<art::ArtMethod*>(art::ScopedObjectAccessAlreadyRunnable const&, _jobject*, art::ArtMethod*, jvalue const*)+464) (BuildId: 3c99f91941a4d3092e2569c2315c7080) 03-09 14:18:10.038 28883 28883 F DEBUG : #22 pc 000000000065a0ac /apex/com.android.art/lib64/libart.so (art::Thread::CreateCallback(void*)+1292) (BuildId: 3c99f91941a4d3092e2569c2315c7080) 03-09 14:18:10.038 28883 28883 F DEBUG : #23 pc 00000000000bba60 /apex/com.android.runtime/lib64/bionic/libc.so (__pthread_start(void*)+208) (BuildId: 3c0b572f737ca87433148a44975d6df1) 03-09 14:18:10.038 28883 28883 F DEBUG : #24 pc 0000000000055414 /apex/com.android.runtime/lib64/bionic/libc.so (__start_thread+68) (BuildId: 3c0b572f737ca87433148a44975d6df1) 03-09 14:18:10.071 1562 28924 I DropBoxManagerService: add tag=data_app_native_crash isTagEnabled=true flags=0x2my code:
package com.mysoft.yunke.lib_livecore.camera.huoshan.opengl; import android.opengl.GLES11Ext; import android.opengl.GLES30; import android.opengl.Matrix; import com.mysoft.yunke.lib_livecore.camera.mix.StickerManager; import com.mysoft.yunke.lib_livecore.push.bean.MixVideoBean; import com.mysoft.yunke.lib_livecore.utils.LogUtils; import com.ss.avframework.opengl.GLThreadManager; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.List; import java.util.Map; /** * StickerProgram ES 3.0 高性能优化版 * 优化点:VAO, VBO, 减少 CPU 指令提交 */ public class StickerProgram extends Program { private static final String VERTEX_SHADER = "#version 300 es\n" + "layout(location = 0) in vec4 aPosition;\n" + "layout(location = 1) in vec2 aTextureCoord;\n" + "uniform mat4 uMVPMatrix;\n" + "out vec2 vTextureCoord;\n" + "void main() {\n" + " gl_Position = uMVPMatrix * aPosition;\n" + " vTextureCoord = aTextureCoord;\n" + "}"; private static final String FRAGMENT_SHADER_2D = "#version 300 es\n" + "precision mediump float;\n" + "in vec2 vTextureCoord;\n" + "uniform sampler2D uTexture;\n" + "uniform float uAlpha;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec4 texColor = texture(uTexture, vTextureCoord);\n" + " fragColor = vec4(texColor.rgb, texColor.a * uAlpha);\n" + "}"; private static final String FRAGMENT_SHADER_OES = "#version 300 es\n" + "#extension GL_OES_EGL_image_external_essl3 : require\n" + "precision mediump float;\n" + "in vec2 vTextureCoord;\n" + "uniform samplerExternalOES uTextureOES;\n" + "uniform float uAlpha;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec4 texColor = texture(uTextureOES, vTextureCoord);\n" + " // 快速预乘转换逻辑\n" + " vec3 rgb = texColor.a > 0.0 ? texColor.rgb / texColor.a : texColor.rgb;\n" + " fragColor = vec4(rgb, texColor.a * uAlpha);\n" + "}"; private int muMVPMatrixLoc, muTextureLoc, muAlphaLoc; private int muMVPMatrixLocOES, muTextureLocOES, muAlphaLocOES; private int mProgramHandleOES = -1; // ES 3.0 句柄 private int[] mVaoId = new int[1]; private int[] mVboIds = new int[2]; // 0: 顶点, 1: 纹理坐标 private static final float[] VERTICES = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; private static final float[] TEX_COORDS = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; public StickerProgram() { super(VERTEX_SHADER, FRAGMENT_SHADER_2D); mProgramHandleOES = GlUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER_OES); getOESLocation(); initOptimizedBuffers(); } /** * 核心优化:初始化 VAO 和 VBO */ private void initOptimizedBuffers() { // 1. 生成 VAO 和 VBO GLES30.glGenVertexArrays(1, mVaoId, 0); GLES30.glGenBuffers(2, mVboIds, 0); // 2. 准备数据 FloatBuffer vertexBuf = ByteBuffer.allocateDirect(VERTICES.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(VERTICES); vertexBuf.position(0); FloatBuffer texBuf = ByteBuffer.allocateDirect(TEX_COORDS.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(TEX_COORDS); texBuf.position(0); // 3. 绑定 VAO 记录状态 GLES30.glBindVertexArray(mVaoId[0]); // 顶点 VBO GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVboIds[0]); GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, VERTICES.length * 4, vertexBuf, GLES30.GL_STATIC_DRAW); GLES30.glEnableVertexAttribArray(0); // 对应 layout(location = 0) GLES30.glVertexAttribPointer(0, 2, GLES30.GL_FLOAT, false, 0, 0); // 纹理坐标 VBO GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVboIds[1]); GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, TEX_COORDS.length * 4, texBuf, GLES30.GL_STATIC_DRAW); GLES30.glEnableVertexAttribArray(1); // 对应 layout(location = 1) GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 0, 0); // 4. 解绑 GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0); GLES30.glBindVertexArray(0); } @Override protected void getLocations() { muMVPMatrixLoc = GLES30.glGetUniformLocation(mProgramHandle, "uMVPMatrix"); muTextureLoc = GLES30.glGetUniformLocation(mProgramHandle, "uTexture"); muAlphaLoc = GLES30.glGetUniformLocation(mProgramHandle, "uAlpha"); } private void getOESLocation() { muMVPMatrixLocOES = GLES30.glGetUniformLocation(mProgramHandleOES, "uMVPMatrix"); muTextureLocOES = GLES30.glGetUniformLocation(mProgramHandleOES, "uTextureOES"); muAlphaLocOES = GLES30.glGetUniformLocation(mProgramHandleOES, "uAlpha"); } public int renderStickers(int cameraTexture, Map<Integer, StickerManager.StickerItem> stickers, List<Integer> stickerStreamOrder, int width, int height, float[] matrix) { if (cameraTexture <= 0 || stickers.isEmpty() || stickerStreamOrder.isEmpty()) { return cameraTexture; } GLES30.glHint(GLES30.GL_GENERATE_MIPMAP_HINT, GLES30.GL_FASTEST); try { initFrameBufferIfNeed(width, height); GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFrameBuffers[0]); GLES30.glViewport(0, 0, width, height); // 渲染背景 GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT); GLES30.glEnable(GLES30.GL_BLEND); GLES30.glBlendFunc(GLES30.GL_SRC_ALPHA, GLES30.GL_ONE_MINUS_SRC_ALPHA); // 绑定一次 VAO 即可 GLES30.glBindVertexArray(mVaoId[0]); int currentProgram = -1; for (Integer stickId : stickerStreamOrder) { StickerManager.StickerItem item = stickers.get(stickId); if (item != null && item.enabled) { // 内部自动判断是否需要切换 Program,减少不必要的 glUseProgram currentProgram = drawStickerOptimized(item, matrix, currentProgram); } } GLES30.glBindVertexArray(0); GLES30.glDisable(GLES30.GL_BLEND); GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0); } catch (Exception e) { LogUtils.aid("[StickerProgram]--" + "[renderStickers]--: is error" + e.getMessage()); } finally { GLES30.glFinish(); } return mFrameBufferTextures[0]; } private int drawStickerOptimized(StickerManager.StickerItem sticker, float[] matrix, int activeProgram) { if (sticker.textureId <= 0) return activeProgram; boolean isOes = (sticker.bean.type == MixVideoBean.TYPE_VIDEO || sticker.videoTexture2D); int targetProgram = isOes ? mProgramHandleOES : mProgramHandle; // 性能点:避免重复 glUseProgram if (activeProgram != targetProgram) { GLES30.glUseProgram(targetProgram); activeProgram = targetProgram; } int mvpLoc = isOes ? muMVPMatrixLocOES : muMVPMatrixLoc; int texLoc = isOes ? muTextureLocOES : muTextureLoc; int alphaLoc = isOes ? muAlphaLocOES : muAlphaLoc; int target = isOes ? GLES11Ext.GL_TEXTURE_EXTERNAL_OES : GLES30.GL_TEXTURE_2D; float[] mvp = (sticker.bean.type == MixVideoBean.TYPE_CAMERA && matrix != null) ? matrix : sticker.mvpMatrix; GLES30.glUniformMatrix4fv(mvpLoc, 1, false, mvp, 0); GLES30.glUniform1f(alphaLoc, sticker.bean.enableAlpha); GLES30.glUniform1i(texLoc, 0); GLES30.glActiveTexture(GLES30.GL_TEXTURE0); GLES30.glBindTexture(target, sticker.textureId); // 直接绘制,VAO 已经处理了顶点和纹理坐标的绑定 GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4); return activeProgram; } @Override public void release() { super.release(); if (mProgramHandleOES != -1) { GLES30.glDeleteProgram(mProgramHandleOES); mProgramHandleOES = -1; } // 释放 VBO 和 VAO GLES30.glDeleteBuffers(2, mVboIds, 0); GLES30.glDeleteVertexArrays(1, mVaoId, 0); } // 实现抽象占位 @Override protected Drawable2d getDrawable2d() { return null; } @Override public void drawFrameOnScreen(int t, int w, int h, float[] m) { } @Override public int drawFrameOffScreen(int t, int w, int h, float[] m) { return 0; } @Override public int drawFrameOffScreenForCompare(int t, int s, float p, int w, int h, float[] m) { return 0; } @Override public ByteBuffer readBuffer(int t, int w, int h) { return null; } } package com.mysoft.yunke.lib_livecore.camera.huoshan.opengl; import android.opengl.GLES11Ext; import android.opengl.GLES30; import android.opengl.Matrix; import com.mysoft.yunke.lib_livecore.camera.mix.StickerManager; import com.mysoft.yunke.lib_livecore.push.bean.MixVideoBean; import com.mysoft.yunke.lib_livecore.utils.LogUtils; import com.ss.avframework.opengl.GLThreadManager; import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.FloatBuffer; import java.util.List; import java.util.Map; /** * StickerProgram ES 3.0 高性能优化版 * 优化点:VAO, VBO, 减少 CPU 指令提交 */ public class StickerProgram extends Program { private static final String VERTEX_SHADER = "#version 300 es\n" + "layout(location = 0) in vec4 aPosition;\n" + "layout(location = 1) in vec2 aTextureCoord;\n" + "uniform mat4 uMVPMatrix;\n" + "out vec2 vTextureCoord;\n" + "void main() {\n" + " gl_Position = uMVPMatrix * aPosition;\n" + " vTextureCoord = aTextureCoord;\n" + "}"; private static final String FRAGMENT_SHADER_2D = "#version 300 es\n" + "precision mediump float;\n" + "in vec2 vTextureCoord;\n" + "uniform sampler2D uTexture;\n" + "uniform float uAlpha;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec4 texColor = texture(uTexture, vTextureCoord);\n" + " fragColor = vec4(texColor.rgb, texColor.a * uAlpha);\n" + "}"; private static final String FRAGMENT_SHADER_OES = "#version 300 es\n" + "#extension GL_OES_EGL_image_external_essl3 : require\n" + "precision mediump float;\n" + "in vec2 vTextureCoord;\n" + "uniform samplerExternalOES uTextureOES;\n" + "uniform float uAlpha;\n" + "out vec4 fragColor;\n" + "void main() {\n" + " vec4 texColor = texture(uTextureOES, vTextureCoord);\n" + " // 快速预乘转换逻辑\n" + " vec3 rgb = texColor.a > 0.0 ? texColor.rgb / texColor.a : texColor.rgb;\n" + " fragColor = vec4(rgb, texColor.a * uAlpha);\n" + "}"; private int muMVPMatrixLoc, muTextureLoc, muAlphaLoc; private int muMVPMatrixLocOES, muTextureLocOES, muAlphaLocOES; private int mProgramHandleOES = -1; // ES 3.0 句柄 private int[] mVaoId = new int[1]; private int[] mVboIds = new int[2]; // 0: 顶点, 1: 纹理坐标 private static final float[] VERTICES = { -1.0f, -1.0f, 1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f }; private static final float[] TEX_COORDS = { 0.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f, 1.0f, 0.0f }; public StickerProgram() { super(VERTEX_SHADER, FRAGMENT_SHADER_2D); mProgramHandleOES = GlUtil.createProgram(VERTEX_SHADER, FRAGMENT_SHADER_OES); getOESLocation(); initOptimizedBuffers(); } /** * 核心优化:初始化 VAO 和 VBO */ private void initOptimizedBuffers() { // 1. 生成 VAO 和 VBO GLES30.glGenVertexArrays(1, mVaoId, 0); GLES30.glGenBuffers(2, mVboIds, 0); // 2. 准备数据 FloatBuffer vertexBuf = ByteBuffer.allocateDirect(VERTICES.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(VERTICES); vertexBuf.position(0); FloatBuffer texBuf = ByteBuffer.allocateDirect(TEX_COORDS.length * 4).order(ByteOrder.nativeOrder()).asFloatBuffer().put(TEX_COORDS); texBuf.position(0); // 3. 绑定 VAO 记录状态 GLES30.glBindVertexArray(mVaoId[0]); // 顶点 VBO GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVboIds[0]); GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, VERTICES.length * 4, vertexBuf, GLES30.GL_STATIC_DRAW); GLES30.glEnableVertexAttribArray(0); // 对应 layout(location = 0) GLES30.glVertexAttribPointer(0, 2, GLES30.GL_FLOAT, false, 0, 0); // 纹理坐标 VBO GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, mVboIds[1]); GLES30.glBufferData(GLES30.GL_ARRAY_BUFFER, TEX_COORDS.length * 4, texBuf, GLES30.GL_STATIC_DRAW); GLES30.glEnableVertexAttribArray(1); // 对应 layout(location = 1) GLES30.glVertexAttribPointer(1, 2, GLES30.GL_FLOAT, false, 0, 0); // 4. 解绑 GLES30.glBindBuffer(GLES30.GL_ARRAY_BUFFER, 0); GLES30.glBindVertexArray(0); } @Override protected void getLocations() { muMVPMatrixLoc = GLES30.glGetUniformLocation(mProgramHandle, "uMVPMatrix"); muTextureLoc = GLES30.glGetUniformLocation(mProgramHandle, "uTexture"); muAlphaLoc = GLES30.glGetUniformLocation(mProgramHandle, "uAlpha"); } private void getOESLocation() { muMVPMatrixLocOES = GLES30.glGetUniformLocation(mProgramHandleOES, "uMVPMatrix"); muTextureLocOES = GLES30.glGetUniformLocation(mProgramHandleOES, "uTextureOES"); muAlphaLocOES = GLES30.glGetUniformLocation(mProgramHandleOES, "uAlpha"); } public int renderStickers(int cameraTexture, Map<Integer, StickerManager.StickerItem> stickers, List<Integer> stickerStreamOrder, int width, int height, float[] matrix) { if (cameraTexture <= 0 || stickers.isEmpty() || stickerStreamOrder.isEmpty()) { return cameraTexture; } GLES30.glHint(GLES30.GL_GENERATE_MIPMAP_HINT, GLES30.GL_FASTEST); try { initFrameBufferIfNeed(width, height); GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, mFrameBuffers[0]); GLES30.glViewport(0, 0, width, height); // 渲染背景 GLES30.glClearColor(0.0f, 0.0f, 0.0f, 0.0f); GLES30.glClear(GLES30.GL_COLOR_BUFFER_BIT); GLES30.glEnable(GLES30.GL_BLEND); GLES30.glBlendFunc(GLES30.GL_SRC_ALPHA, GLES30.GL_ONE_MINUS_SRC_ALPHA); // 绑定一次 VAO 即可 GLES30.glBindVertexArray(mVaoId[0]); int currentProgram = -1; for (Integer stickId : stickerStreamOrder) { StickerManager.StickerItem item = stickers.get(stickId); if (item != null && item.enabled) { // 内部自动判断是否需要切换 Program,减少不必要的 glUseProgram currentProgram = drawStickerOptimized(item, matrix, currentProgram); } } GLES30.glBindVertexArray(0); GLES30.glDisable(GLES30.GL_BLEND); GLES30.glBindFramebuffer(GLES30.GL_FRAMEBUFFER, 0); } catch (Exception e) { LogUtils.aid("[StickerProgram]--" + "[renderStickers]--: is error" + e.getMessage()); } finally { GLES30.glFinish(); } return mFrameBufferTextures[0]; } private int drawStickerOptimized(StickerManager.StickerItem sticker, float[] matrix, int activeProgram) { if (sticker.textureId <= 0) return activeProgram; boolean isOes = (sticker.bean.type == MixVideoBean.TYPE_VIDEO || sticker.videoTexture2D); int targetProgram = isOes ? mProgramHandleOES : mProgramHandle; // 性能点:避免重复 glUseProgram if (activeProgram != targetProgram) { GLES30.glUseProgram(targetProgram); activeProgram = targetProgram; } int mvpLoc = isOes ? muMVPMatrixLocOES : muMVPMatrixLoc; int texLoc = isOes ? muTextureLocOES : muTextureLoc; int alphaLoc = isOes ? muAlphaLocOES : muAlphaLoc; int target = isOes ? GLES11Ext.GL_TEXTURE_EXTERNAL_OES : GLES30.GL_TEXTURE_2D; float[] mvp = (sticker.bean.type == MixVideoBean.TYPE_CAMERA && matrix != null) ? matrix : sticker.mvpMatrix; GLES30.glUniformMatrix4fv(mvpLoc, 1, false, mvp, 0); GLES30.glUniform1f(alphaLoc, sticker.bean.enableAlpha); GLES30.glUniform1i(texLoc, 0); GLES30.glActiveTexture(GLES30.GL_TEXTURE0); GLES30.glBindTexture(target, sticker.textureId); // 直接绘制,VAO 已经处理了顶点和纹理坐标的绑定 GLES30.glDrawArrays(GLES30.GL_TRIANGLE_STRIP, 0, 4); return activeProgram; } @Override public void release() { super.release(); if (mProgramHandleOES != -1) { GLES30.glDeleteProgram(mProgramHandleOES); mProgramHandleOES = -1; } // 释放 VBO 和 VAO GLES30.glDeleteBuffers(2, mVboIds, 0); GLES30.glDeleteVertexArrays(1, mVaoId, 0); } // 实现抽象占位 @Override protected Drawable2d getDrawable2d() { return null; } @Override public void drawFrameOnScreen(int t, int w, int h, float[] m) { } @Override public int drawFrameOffScreen(int t, int w, int h, float[] m) { return 0; } @Override public int drawFrameOffScreenForCompare(int t, int s, float p, int w, int h, float[] m) { return 0; } @Override public ByteBuffer readBuffer(int t, int w, int h) { return null; } }What I've Checked Memory: No obvious Java-side memory leak.
Context: All calls are strictly on the same GL thread and EGL context.
Buffers: VBOs are initialized with GL_STATIC_DRAW and are not updated or deleted during the session.
Questions Is there a known issue in Adreno drivers where switching between SAMPLER_2D and SAMPLER_EXTERNAL_OES while a VAO is bound leads to internal state corruption or memory leaks in the driver?
Should I be calling glBindVertexArray(0) and re-binding it every time I change the glUseProgram or texture target to "flush" the driver state?
Could the glFinish() call in my finally block be exacerbating a driver-level race condition or resource exhaustion over time?
