Android OpenGL ES创建着色器时触发SIGSEGV崩溃求助
解决OpenGL ES中glCreateShader触发SIGSEGV崩溃的问题
崩溃原因分析
Fatal signal 11 (SEGV_MAPERR)在glCreateShader行,本质是OpenGL上下文未就绪时调用了GL API,或是在非GL线程(如主线程)执行了GL操作。glCreateShader必须在GLThread(Renderer的回调线程)中调用,且要确保GL上下文已绑定。
具体修复步骤
将所有GL操作限制在Renderer回调方法内:
若你的loadShader方法在主线程或Renderer初始化前调用,必然触发崩溃。必须把着色器加载、编译逻辑放在onSurfaceCreated方法中——该方法是GLThread在上下文就绪后才会调用的。
正确实现示例:@Override public void onSurfaceCreated(GL10 unused, EGLConfig config) { // 在此处加载、编译着色器 int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, vertexShaderCode); int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, fragmentShaderCode); // 后续创建着色器程序等操作 }完善loadShader方法的健壮性:
确保传入的着色器代码非空且格式正确,同时添加编译错误检查(新手必备,便于排查问题):private int loadShader(int type, String shaderCode) { if (shaderCode == null || shaderCode.isEmpty()) { Log.e("OpenGL", "Shader code is empty or null"); return 0; } int shader = GLES20.glCreateShader(type); GLES20.glShaderSource(shader, shaderCode); GLES20.glCompileShader(shader); // 检查编译状态 int[] compileStatus = new int[1]; GLES20.glGetShaderiv(shader, GLES20.GL_COMPILE_STATUS, compileStatus, 0); if (compileStatus[0] == GLES20.GL_FALSE) { Log.e("OpenGL", "Shader compile failed: " + GLES20.glGetShaderInfoLog(shader)); GLES20.glDeleteShader(shader); return 0; } return shader; }规范GLSurfaceView初始化流程:
在MainActivity中,确保GLSurfaceView在onCreate中初始化,设置Renderer后再显示:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); GLSurfaceView glView = new GLSurfaceView(this); glView.setRenderer(new YourRenderer()); // 非连续渲染场景下,设为WHEN_DIRTY优化性能 glView.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY); setContentView(glView); }
针对2D图像伪3D视差的简化实现建议(适合新手)
你只需基于传感器值实现伪3D效果,无需复杂深度图管线,可简化流程:
- 用矩形(两个三角形)绘制2D图像,顶点数据包含纹理坐标和模拟深度值(可从深度图提取,或给不同区域设固定深度)。
- 在顶点着色器中,根据传感器倾斜值(如加速度计x/y轴数据),对不同深度的顶点做偏移:
// 顶点着色器示例 attribute vec4 aPosition; attribute vec2 aTexCoord; attribute float aDepth; uniform vec2 uSensorOffset; // 传感器传入的偏移量,如(-0.01, 0.02) varying vec2 vTexCoord; void main() { // 深度越大,偏移量越大,实现视差效果 vec4 offset = vec4(uSensorOffset * aDepth, 0.0, 0.0); gl_Position = aPosition + offset; vTexCoord = aTexCoord; } - 通过
GLSurfaceView.queueEvent()将传感器数据传到Renderer,确保在GLThread中更新uniform变量:// MainActivity的传感器回调中 glView.queueEvent(() -> { yourRenderer.updateSensorOffset(xOffset, yOffset); glView.requestRender(); });
内容的提问来源于stack exchange,提问作者Mehmood Mir
相关产品推荐
相关产品推荐

