Android中GLSL Wallpaper Service显示黑屏问题求助
Android GLSL 壁纸黑屏问题排查与解决
问题说明
开发Android项目时,尝试通过WallpaperService将GLSL着色器设置为动态壁纸,目标是显示简单的灰度分屏效果,但目前壁纸仅显示黑屏。已准备好最简复现的项目代码,同时希望后续能简化着色器的创建与定制流程。
相关代码实现
GLSL 片段着色器代码
void main() {// basic code for testing purpose if(gl_FragCoord.y > 250.0){ gl_FragColor = vec4(0.25); } else{ gl_FragColor = vec4(0.75); } }
GLSLWallpaperService 实现
import android.service.wallpaper.WallpaperService import android.view.SurfaceHolder import com.dhruv.hellohome.glsl.MyGLSurfaceView class GLSLWallpaperService : WallpaperService() { private var engine: GLWallpaperEngine? = null fun isRunning(): Boolean { return engine != null } override fun onCreateEngine(): Engine { return GLWallpaperEngine() } override fun onDestroy() { super.onDestroy() } inner class GLWallpaperEngine : Engine() { private var glSurfaceView: MyGLSurfaceView? = null override fun onCreate(surfaceHolder: SurfaceHolder) { super.onCreate(surfaceHolder) glSurfaceView = MyGLSurfaceView(this@GLSLWallpaperService) } override fun onSurfaceCreated(holder: SurfaceHolder) { super.onSurfaceCreated(holder) glSurfaceView?.surfaceCreated(holder) } override fun onVisibilityChanged(visible: Boolean) { super.onVisibilityChanged(visible) if (visible) { glSurfaceView?.onResume() } else { glSurfaceView?.onPause() } } override fun onDestroy() { super.onDestroy() glSurfaceView?.let { it.onPause() it.onDetachedFromWindow() } } override fun onSurfaceDestroyed(holder: SurfaceHolder) { super.onSurfaceDestroyed(holder) glSurfaceView?.surfaceDestroyed(holder) } } }
MyGLSurfaceView 实现
import android.content.Context import android.opengl.GLSurfaceView import android.util.Log import android.view.SurfaceHolder class MyGLSurfaceView(context: Context) : GLSurfaceView(context) { private val renderer: MyGLRenderer init { setEGLContextClientVersion(2) renderer = MyGLRenderer(ShaderData()) setRenderer(renderer) renderMode = RENDERMODE_CONTINUOUSLY } override fun surfaceCreated(holder: SurfaceHolder) { super.surfaceCreated(holder) Log.d("MyGLSurfaceView", "Surface created") } override fun surfaceDestroyed(holder: SurfaceHolder) { super.surfaceDestroyed(holder) Log.d("MyGLSurfaceView", "Surface destroyed") } public override fun onDetachedFromWindow() { super.onDetachedFromWindow() } }
注:MyGLRenderer为已验证可正常工作的GLSurfaceView.Renderer实现
Manifest 配置
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:installLocation="auto"> <supports-screens android:largeScreens="true" android:xlargeScreens="true"/> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="19"/> <!-- Required below API < 28 for exporting shaders --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="28"/> <uses-feature android:glEsVersion="0x00020000"/> <uses-feature android:name="android.hardware.camera.any" android:required="false"/> <uses-feature android:name="android.hardware.camera.autofocus" android:required="false"/> <uses-feature android:name="android.software.live_wallpaper"/> <queries> <intent> <action android:name="android.intent.action.VIEW"/> <data android:scheme="https"/> </intent> </queries> <application tools:ignore="UnusedAttribute" android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.HelloHome"> <service android:name=".services.GLSLWallpaperService" android:exported="true" android:description="@string/wallpaper_description" android:label="@string/app_name" android:permission="android.permission.BIND_WALLPAPER"> <intent-filter> <action android:name="android.service.wallpaper.WallpaperService" /> </intent-filter> <meta-data android:name="android.service.wallpaper" android:resource="@xml/wallpaper" /> </service> <activity android:name="com.example.openglwallpaper.SettingsActivity" /> <activity android:name=".MainActivity" android:exported="true" android:label="@string/app_name" android:theme="@style/Theme.HelloHome"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <activity android:name=".PreviewActivity" /> </application> </manifest>
可能的解决方向
1. 关联GLSurfaceView到壁纸的SurfaceHolder
默认GLSurfaceView会创建自己的SurfaceHolder,但壁纸场景下必须使用系统提供的SurfaceHolder。修改GLWallpaperEngine的onCreate方法:
override fun onCreate(surfaceHolder: SurfaceHolder) { super.onCreate(surfaceHolder) glSurfaceView = MyGLSurfaceView(this@GLSLWallpaperService) // 关键:将壁纸的SurfaceHolder绑定到GLSurfaceView glSurfaceView?.holder = surfaceHolder }
2. 验证Renderer生命周期调用
在MyGLRenderer的onSurfaceCreated、onDrawFrame方法中添加Log,确认这些方法是否被执行:
override fun onSurfaceCreated(gl: GL10?, config: EGLConfig?) { Log.d("MyGLRenderer", "Surface created in Renderer") // 初始化着色器等逻辑... } override fun onDrawFrame(gl: GL10?) { Log.d("MyGLRenderer", "Drawing frame") // 绘制逻辑... }
如果没有Log输出,说明GL上下文未正确初始化。
3. 修正GLSL坐标逻辑
gl_FragCoord.y是基于Surface实际尺寸的像素值,固定250.0在高分辨率屏幕上可能几乎不可见,改为相对坐标更合理:
// 先在Renderer中传递分辨率uniform uniform vec2 resolution; void main() { if(gl_FragCoord.y > resolution.y * 0.5){ gl_FragColor = vec4(0.25); } else{ gl_FragColor = vec4(0.75); } }
在onSurfaceChanged中传递分辨率:
override fun onSurfaceChanged(gl: GL10?, width: Int, height: Int) { GLES20.glViewport(0, 0, width, height) // 获取resolution的uniform位置并设置值 val resolutionLoc = GLES20.glGetUniformLocation(programId, "resolution") GLES20.glUniform2f(resolutionLoc, width.toFloat(), height.toFloat()) }
4. 指定EGL配置
部分设备可能需要显式指定EGL配置,在MyGLSurfaceView的init块中添加:
init { setEGLContextClientVersion(2) // 添加EGL配置选择器 setEGLConfigChooser(8, 8, 8, 8, 16, 0) renderer = MyGLRenderer(ShaderData()) setRenderer(renderer) renderMode = RENDERMODE_CONTINUOUSLY }
内容的提问来源于stack exchange,提问作者Dhruv Bansal
相关产品推荐
相关产品推荐

