Rajawali / Rajawali

Android OpenGL ES 2.0/3.0 Engine
https://rajawali.github.io/Rajawali/
Other
2.35k stars 700 forks source link

Livewallpaper preview bug #1103

Closed ravenfeld closed 10 years ago

ravenfeld commented 11 years ago

When set their livewallpaper then returns to the preview. Rajawali will not go in to taskReset TextureManager because there are two instances of Renderer. How to release the textures used in the instance of the preview? Currently if you go much on the preview, the application crash with OutOfMemory.

I do not know if it's related but if you look with DDMS threads you will see that whenever we create a preview there is a new GLThread.

thank you

ravenfeld commented 11 years ago

I found a solution, but I do not know if it's very safe Thread:

Modified the method onDestroy in Wallpaper.java

    @Override
    public void onDestroy() {
        setTouchEventsEnabled(false);
        mRenderer.onSurfaceDestroyed();
        mRenderer = null;
        mSurfaceView.onDestroy();
        super.onDestroy();
    }

and the method onSurfaceChanged in RajawaliRenderer.java

    mViewportWidth = width;
    mViewportHeight = height;
    mTextureManager = TextureManager.getInstance();
    mTextureManager.setContext(this.getContext());
    mTextureManager.registerRenderer(this);
    mMaterialManager = MaterialManager.getInstance();
    mMaterialManager.setContext(this.getContext());
    mMaterialManager.registerRenderer(this);
    if (!mSceneInitialized) {
        getCurrentScene().resetGLState();

        initScene();
    }
    ....

Now you must destroy in onSurfaceDestroyed your items in your Renderer

    mMaterial.removeTexture(mTexture);
    mTexture.reset();
    mTextureManager.taskRemove(mTexture);
    mMaterialManager.taskRemove(mMaterial);
Dreamonaut commented 10 years ago

Hi RavenFeld !

I have this issue and wasn't able to correct it since i'm new in programming. I'm really pleased to see that someone found a solution AND explain how to put it in place ! thank you very much !

BUT ! still had issue for the last step !

So i added in my renderer right after the InitScene{.......}

public void onSurfaceDestroyed() { mMaterial.removeTexture(mTexture); mTexture.reset(); mTextureManager.taskRemove(mTexture); mMaterialManager.taskRemove(mMaterial); } but looks like Eclipse can't find my mMaterial and mTexture... ??? Thank you in Advance

ravenfeld commented 10 years ago

it's your Texture and your Material

Show me initScene and I'll tell you how you have called ?

Dreamonaut commented 10 years ago

public void initScene() {

    ALight frontlight = new SpotLight();
    frontlight.setPosition(0, -1.3f, 4);
    frontlight.setPower(1.2f);
    frontlight.setLookAt(0,0,0);

    getCurrentScene().addLight(frontlight);

    OrthographicCamera camera = new OrthographicCamera();
    camera.setPosition(0, 0, 5);
    camera.setLookAt(0, 0, 0);
    camera.setRotation(0,0,0);
    replaceAndSwitchCamera(camera, 0);

    try {

        Plane background = new Plane(4,2.3f,2,2);
        background.setBlendingEnabled(true);
        background.setBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
        background.setDoubleSided(true);
        Material mbackground = new Material();

        mbackground.setDiffuseMethod(new DiffuseMethod.Lambert());
        Texture t = new Texture("mbackground", R.drawable.background);
        t.setRepeat(2, 1); // Tile Texture
        mbackground.addTexture(mTextureManager.addTexture(t));  

        mbackground.setColorInfluence(0);   
        background.setMaterial(mbackground);
        background.setPosition(0, 0, -10); 
        background.setRotation(0, 0, 0);
        addChild(background);  

    }

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    super.onSurfaceCreated(gl, config);
}

public void onDrawFrame(GL10 glUnused) {
    super.onDrawFrame(glUnused);

}

        public void onSurfaceDestroyed() {
    mMaterial.removeTexture(background);
    mTexture.reset();
    mTextureManager.taskRemove();
    mMaterialManager.taskRemove(mMaterial);

}

}

i believe i have to change mMaterial by mbackground and mTexture by t ? .... thank you for the fast reply :)

ravenfeld commented 10 years ago

Yes but they must be in class variable

Dreamonaut commented 10 years ago

any precision ? i cant figure out... sorry for being annoying ....

ravenfeld commented 10 years ago
private Material mBackgroundTexture;
private Texture mBackgroundTexture;
public void initScene() {

    ALight frontlight = new SpotLight();
    frontlight.setPosition(0, -1.3f, 4);
    frontlight.setPower(1.2f);
    frontlight.setLookAt(0,0,0);

    getCurrentScene().addLight(frontlight);

    OrthographicCamera camera = new OrthographicCamera();
    camera.setPosition(0, 0, 5);
    camera.setLookAt(0, 0, 0);
    camera.setRotation(0,0,0);
    replaceAndSwitchCamera(camera, 0);

    try {

        Plane background = new Plane(4,2.3f,2,2);
        background.setBlendingEnabled(true);
        background.setBlendFunc(GLES20.GL_SRC_ALPHA, GLES20.GL_ONE_MINUS_SRC_ALPHA);
        background.setDoubleSided(true);
        mBackgroundMaterial = new Material();

        mBackgroundMaterial.setDiffuseMethod(new DiffuseMethod.Lambert());
        mBackgroundTexture = new Texture("mBackgroundMaterial", R.drawable.background);
        mBackgroundTexture.setRepeat(2, 1); // Tile Texture
        //don't use mTextureManager.addTexture
        mBackgroundMaterial.addTexture(mBackgroundTexture);  

        mBackgroundMaterial.setColorInfluence(0);   
        background.setMaterial(mBackgroundMaterial);
        background.setPosition(0, 0, -10); 
        background.setRotation(0, 0, 0);
        addChild(background);  

    }

public void onSurfaceCreated(GL10 gl, EGLConfig config) {
    super.onSurfaceCreated(gl, config);
}

public void onDrawFrame(GL10 glUnused) {
    super.onDrawFrame(glUnused);

}

        public void onSurfaceDestroyed() {
        mBackgroundMaterial.removeTexture(mBackgroundTexture);
        mBackgroundTexture.reset();
        mTextureManager.taskRemove(mBackgroundTexture);
        mMaterialManager.taskRemove(mBackgroundMaterial);

}
}

Test this code

Dreamonaut commented 10 years ago

Oh well i understand a little bit more how it works now thank you !

but the livewallpaper crashes lol ....

10-25 18:19:55.864: E/AndroidRuntime(4370): FATAL EXCEPTION: main 10-25 18:19:55.864: E/AndroidRuntime(4370): java.lang.NullPointerException 10-25 18:19:55.864: E/AndroidRuntime(4370): at livewallpaper.doodah.Renderer.onSurfaceDestroyed(Renderer.java:566) 10-25 18:19:55.864: E/AndroidRuntime(4370): at rajawali.wallpaper.Wallpaper$WallpaperEngine.onDestroy(Wallpaper.java:370) 10-25 18:19:55.864: E/AndroidRuntime(4370): at android.service.wallpaper.WallpaperService$Engine.detach(WallpaperService.java:917) 10-25 18:19:55.864: E/AndroidRuntime(4370): at android.service.wallpaper.WallpaperService$IWallpaperEngineWrapper.executeMessage(WallpaperService.java:1036) 10-25 18:19:55.864: E/AndroidRuntime(4370): at com.android.internal.os.HandlerCaller$MyHandler.handleMessage(HandlerCaller.java:40) 10-25 18:19:55.864: E/AndroidRuntime(4370): at android.os.Handler.dispatchMessage(Handler.java:99) 10-25 18:19:55.864: E/AndroidRuntime(4370): at android.os.Looper.loop(Looper.java:137) 10-25 18:19:55.864: E/AndroidRuntime(4370): at android.app.ActivityThread.main(ActivityThread.java:5103) 10-25 18:19:55.864: E/AndroidRuntime(4370): at java.lang.reflect.Method.invokeNative(Native Method) 10-25 18:19:55.864: E/AndroidRuntime(4370): at java.lang.reflect.Method.invoke(Method.java:525) 10-25 18:19:55.864: E/AndroidRuntime(4370): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737) 10-25 18:19:55.864: E/AndroidRuntime(4370): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 10-25 18:19:55.864: E/AndroidRuntime(4370): at dalvik.system.NativeStart.main(Native Method)

Well, i'll look about it later !! thanks for your help !!

ravenfeld commented 10 years ago

add super. onSurfaceDestroyed();

public void onSurfaceDestroyed() {
        mBackgroundMaterial.removeTexture(mBackgroundTexture);
        mBackgroundTexture.reset();
        mTextureManager.taskRemove(mBackgroundTexture);
        mMaterialManager.taskRemove(mBackgroundMaterial);
super. onSurfaceDestroyed();
}
Dreamonaut commented 10 years ago

i added super.onSurfaceDestroyed(); but the crash is still there ! i googled it and it seems to be a common bug with live wallpaper but i'm not able to find the right solution.

ravenfeld commented 10 years ago

Could you put your project on your github or send it to me by email?

Dreamonaut commented 10 years ago

So i declared my var as you told me and it looks like it works fine now ! Thanks !!

MarkEMarkEMark commented 10 years ago

Hi ravenfield! I think you might have answered my problem too. It's cost me about 60 potential buyers, I reckon, as sometimes it would happen straight away. My code is a bit more complex with multiple texture sheets for quality v performance reasons. I'm really hoping that you can help me too.

My wallpaper is based on the particle example, and as such it uses it's own material class which extends AParticleMaterial:

// textures/materials
private myParticleMaterial tex032sheet1Mat;
private myParticleMaterial tex064sheet1Mat;
private Texture tex032sheet1Tex;
private Texture tex064sheet1Tex;

Anyway... in InitScene:

    tex032sheet1Mat = new myParticleMaterial();
    tex064sheet1Mat = new myParticleMaterial();
    tex032sheet1Tex = new Texture(R.drawable.tex032sheet1);
    tex064sheet1Tex = new Texture(R.drawable.tex064sheet1);
    tex032sheet1Mat.addTexture(tex032sheet1Tex);
    tex064sheet1Mat.addTexture(tex064sheet1Tex);

Note that I can't do "tex032sheet1Tex = new Texture("tex032sheet1Mat", R.drawable.tex032sheet1);", as per your example.

My onSurfaceDestroyed is:

    tex032sheet1Mat.removeTexture(tex032sheet1Tex);
    tex064sheet1Mat.removeTexture(tex064sheet1Tex);

    //tex032sheet1Tex.reset();
    //tex064sheet1Tex.reset();

    mTextureManager.taskRemove(tex032sheet1Tex);
    mTextureManager.taskRemove(tex064sheet1Tex);

    mMaterialManager.taskRemove(tex032sheet1Mat);
    mMaterialManager.taskRemove(tex064sheet1Mat);

    super. onSurfaceDestroyed();

Note that my resets are commented out - this is because there is no reset() method!!

I'm not using 0.9 Rajawali so maybe that's the issue, but particles seem to have been removed from the master, so I can't point you in the direction of the version of Rajawali that I'm using.

Can you help with the reset?? Is the two parameter texture declaration required, or will my single parameter do?

Thanks for any help that you can provide.

MarkEMarkEMark commented 10 years ago

PS - My onSurfaceChanged in RajawaliRenderer is this, as it wasn't clear whether to leave the old lines there or not...

public void onSurfaceChanged(GL10 gl, int width, int height) {
    mViewportWidth = width;
    mViewportHeight = height;

    //https://github.com/MasDennis/Rajawali/issues/1103
    mTextureManager = TextureManager.getInstance();
    mTextureManager.setContext(this.getContext());
    mTextureManager.registerRenderer(this);
    mMaterialManager = MaterialManager.getInstance();
    mMaterialManager.setContext(this.getContext());
    mMaterialManager.registerRenderer(this);
    if (!mSceneInitialized) {
        getCurrentScene().resetGLState();

        initScene();
    }

    mCurrentScene.updateProjectionMatrix(width, height);
    GLES20.glViewport(0, 0, width, height);
}

Do I just use you lines and remove the other stuff?

ravenfeld commented 10 years ago

Can you retrieve your project somewhere? Did you try to put android: largeHeap = "true" in your manifest ?

MarkEMarkEMark commented 10 years ago

largeHeap="true" is a great help!

jwoolston commented 10 years ago

Closing this as a duplicate to #1138