You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 17:00:55