Screen flicker at the beginning of rendering

Started by kkl, September 30, 2013, 03:30:21 PM

Previous topic - Next topic

kkl

Hi I tried to draw a square with TextureInfo (2 textures), but it causes flickering for unknown reason. The second texture is in Mode_Blend. When the rendering started, it flickered once (the screen turns into frame buffer background color), then rendering got back to normal state. If I don't add the second texture, it doesn't cause the flickering. Method "preWarm" has been tried, but it looked the same too. Any idea what is going on there? (the square object is at -45z, the rest of objects are in 0z, and camera is at -50z)

EgonOlsen

No idea, i never saw anything like it. Make sure that you don't do any of these operations in anything but the rendering thread or in your setup methods.
If that's not the case, please provide me with a test case.

kkl

I spent the night trying all cases. The normal GLSurfaceView in Activity is fine. When the renderer is used in live wallpaper, in the case that the live wallpaper is set to homescreen and lock screen, it causes the flickering. It happens when device wakes up from sleep mode.

Here's the link for the sample live wallpaper test which causes flickering
https://dl.dropboxusercontent.com/u/9789471/LiveWallpaperTest.zip

Steps to reproduce the issue:
1. Set live wallpaper to homescreen and lockscreen.
2. Press power button to put device to sleep mode.
3. Press power button or home button to wakes up device again.
4. The flicker occurs when device wakes up.

Tested device: Samsung Galaxy S2 GT-I9100 Android 4.1.2

EgonOlsen

Oh boy...how much do a hate life wallpapers? (Hint: very much... ;)). I bet this is some threading/context issue again that happens caused by the twisted way in which lwps are implemented. I'll look into it and see if i can find something.

kkl

Same goes here. I never expect that it can be that complicated. Hopefully this isn't any major issue we're looking in. Btw, thanks alot. Look forward to your reply.

EgonOlsen

Your test case didn't even start on my Nexus 4 with Android 4.3, because it creates the instance twice and so it tries to add the same textures two times. This whole live wallpaper thing is a crude mix of contexts and random gl draw threads gone wild...anyway, i modified the test case in a way that works for me.

What i basically did:


  • Remove the code from onSurfaceDestroyed() because it caused data to be unloaded from the gpu if you assign the wallpaper.
  • Modified disposal and recreation of the FrameBuffer. This change doesn't really trigger on my device (it's always a new context), but it might help on others.
  • Added a condition to texture creation to make sure that it doesn't happen twice.

However, this still doesn't feel like the "clean" way to me. The whole issue with LWPs seems to be that multiple renderers can be created that might spawn multiple threads that somehow work on the same or another gl context, but all within one VM. I think the trick is to make sure that no other than the current (whatever that may be) rendering thread it fiddling around with the gl context.

Modified example:

package com.example.livewallpapertest;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import net.rbgrn.android.glwallpaperservice.GLWallpaperService.Renderer;
import android.content.Context;

import com.threed.jpct.Camera;
import com.threed.jpct.FrameBuffer;
import com.threed.jpct.Logger;
import com.threed.jpct.Matrix;
import com.threed.jpct.Object3D;
import com.threed.jpct.Primitives;
import com.threed.jpct.RGBColor;
import com.threed.jpct.SimpleVector;
import com.threed.jpct.Texture;
import com.threed.jpct.TextureInfo;
import com.threed.jpct.TextureManager;
import com.threed.jpct.World;
import com.threed.jpct.util.BitmapHelper;
import com.threed.jpct.util.MemoryHelper;

public class TestingRenderer2 implements Renderer {

protected World world;
protected FrameBuffer frame;
protected Context context;
private boolean isInit;
private GL10 oldContext = null;

public TestingRenderer2(Context context) {
this.context = context;
isInit = true;
}

@Override
public void onDrawFrame(GL10 arg0) {
frame.clear(RGBColor.GREEN);
world.renderScene(frame);
world.draw(frame);
frame.display();
}

@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
if (gl != oldContext) {
Logger.log("GL context has changed, creating a new buffer!");
if (frame != null) {
frame.dispose();
}
frame = new FrameBuffer(gl, width, height);
}

if (isInit) {
world = new World();
world.setAmbientLight(100, 100, 100);
Camera cam = world.getCamera();
cam.moveCamera(Camera.CAMERA_MOVEOUT, 50f);
cam.lookAt(new SimpleVector(0, 0, 0));

if (!TextureManager.getInstance().containsTexture("tree_shadow")) {
Texture texture1 = new Texture(BitmapHelper.convert(context.getResources().getDrawable(R.drawable.a)), true);
TextureManager.getInstance().addTexture("tree_shadow", texture1);
Texture texture2 = new Texture(BitmapHelper.convert(context.getResources().getDrawable(R.drawable.b)), true);
TextureManager.getInstance().addTexture("tree_shadow_blend", texture2);
}

TextureInfo texInfo = new TextureInfo(TextureManager.getInstance().getTextureID("tree_shadow"));
texInfo.add(TextureManager.getInstance().getTextureID("tree_shadow_blend"), TextureInfo.MODE_BLEND);
Object3D plane = Primitives.getPlane(1, 30);
plane.build();
plane.setTexture(texInfo);
plane.translate(0, 0, -30);
plane.setName("shadow");
plane.setTextureMatrix(new Matrix());
plane.setTransparency(10);
plane.setVisibility(true);
world.addObject(plane);

Object3D cube = Primitives.getPlane(1, 70);
cube.strip();
cube.build();

world.addObject(cube);

isInit = false;
}
MemoryHelper.compact();
}

@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// TODO Auto-generated method stub
}

@Override
public void onSurfaceDestroyed() {
System.gc();
}

}


BTW: Be sure to use the latest beta @ http://jpct.de/download/beta/jpct_ae.jar

kkl

Wow, by checking the glcontext to make new frame buffer, it works! I din't even use the JPCT beta version. BTW, what's new in that JPCT beta version and what exactly happened to the flickering previously?

EgonOlsen

The beta is context aware when it comes to unloading/disposing stuff, i.e. it doesn't try to unload data from the gpu after a context change.

I've no real idea what causes the flickering. I dimly remember that there are situations where this WP-service has multiple threads running at the same time (but only for a few frames) that interfere with each other, i.e. while one inits, the other one disposes or renders and other oddities of that kind. The root of the problem should be somewhere in that service, but i can't be bothered to search for it.

kkl

I see. I had the same problem when I first started off with the GLWallpaperService in which they run drawFrame and onSurfaceChanged at the same time. I fixed it by using a sync lock, so only one method can run at a time. But not sure if that ought to work correctly.

BTW, really appreciate your help on this.